#include "stdafx.h"
#include "LoggerFactory.h"
#include "IInStream.h"
#include "Logger/Logger.h"
#include "lock.h"
#include "IOutStream.h"
#include "android/CreateStream.h"

#include "androidlog.h"
#define LOG_TAG "LoggerFactory"

extern const char* __progname;


namespace NS_Logging
{
#ifdef PLATFORM_WINDOWS
    static const char* S_configFileName = "%ALLUSERSPROFILE%/Funambol/DMClient/Logs/LogRequired.txt";
#elif defined PLATFORM_ANDROID
    static const char* S_configFileName = "/data/data/com.funambol.omadmclient.android.service/Logs/LogRequired.txt";
    static const char* S_configDataPath = "/data/data/";
    static const char* S_configLogPath = "/files/Logs/";
    static const char* S_configDefineFile = "LogRequired.txt";

#else // PLATFORM_POSIX
    static const char* S_configFileName = "/etc/Funambol/DMClient/Logs/LogRequired.txt";
#endif

    static const String S_allLoggers = "*";

    void LoggerFactory::destroy()
    {
        delete ms_instance;
        ms_instance = 0;
    }
    //-------------------------------------------------------------------------------------------

    LoggerFactory* LoggerFactory::ms_instance = 0;
    NS_DM_Client::NS_Common::CritSection LoggerFactory::ms_critSection;
    int LoggerFactory::ms_defaultLevel = 0;

    LoggerFactory::LoggerFactory(): m_ostream(0)
    {
        m_ostream = CreateOutStream();
        readConfiguration();
    }
    //-------------------------------------------------------------------------------------------

    LoggerFactory& LoggerFactory::GetInstance()
    {
        if (!ms_instance)
        {
            NS_DM_Client::NS_Common::Lock lock(ms_critSection);
            if (!ms_instance)
            {
                ms_instance = new(std::nothrow) LoggerFactory();
                if(ms_instance == NULL) LOGW("new LoggerFactory");
                if (::atexit(destroy))
                {
                    destroy();
                }
            }
        }
        return *ms_instance;
    }
    //-------------------------------------------------------------------------------------------

    LoggerFactory::~LoggerFactory()
    {
        Release();
    }
    //-------------------------------------------------------------------------------------------

    void LoggerFactory::Release()
    {
        Loggers::iterator end(m_loggers.end());
        for (Loggers::iterator iter = m_loggers.begin(); iter != end; ++iter)
        {
            Logger* logger = iter->second;
            delete logger;
        }
        m_loggers.clear();
        m_ostream->Close();
        delete m_ostream;
    }
    //-------------------------------------------------------------------------------------------

    void LoggerFactory::readConfiguration()
    {
LOGI("LoggerFactory::readConfiguration");
        // if file doesn't exist - logging process is disabled
        NS_DM_Client::NS_Common::IInStream* configFile = CreateInStream();
////        bool isOpen = configFile->Open(S_configFileName);

        std::string configFilePath = std::string(S_configDataPath) + std::string(__progname) + std::string(S_configLogPath) + std::string(S_configDefineFile);

         LOGI("configFilePath:%s",configFilePath.c_str());
         struct stat st_buf;
         memset(&st_buf, 0, sizeof(st_buf));
         int ret = stat(configFilePath.c_str(), &st_buf);
         if(ret < 0)
        {
            LOGI("error:%d",errno);
        }
         else
        {
            if(S_ISREG(st_buf.st_mode))
            {
                LOGI("reguler file");
            }
            if(S_IRUSR & st_buf.st_mode)
            {
                LOGI("readable for user");
            }
        }
        bool isOpen = configFile->Open(configFilePath.c_str());
        if (isOpen)
         {
            LOGI("isOpen is true");
         }
        else
         {
            LOGI("isOpen is false");
            delete configFile;
            return;
         }

        String loggerInfo;
        bool isDefaultLevel = false;
        while (configFile->GetLine(loggerInfo))
        {
            LOGI("loggerInfo:%s",loggerInfo.c_str());
            if (loggerInfo.length() && '\n' == loggerInfo[loggerInfo.length()-1])
            {
//              loggerInfo.set(loggerInfo.length()-1, '\0');
                loggerInfo[loggerInfo.length()-1] = '\0';
            }

            LoggerName loggerName;
            size_t level;
            expandLoggerInfo(loggerInfo, loggerName, level);
            LoggerName tmpLoggerName(loggerName.c_str()); // it is required to have string with correct length (without \n or \r)
            if (S_allLoggers != tmpLoggerName)
            {
                Loggers::iterator found = m_loggers.find(tmpLoggerName);
                if (m_loggers.end() == found)
                {
                    Logger* logger = new(std::nothrow) Logger(tmpLoggerName.c_str());
                    if(logger == NULL)
                    {
                    LOGW("logger is NULL");
                    }
                    logger->enable(m_ostream, m_loggerCritSection);
                    logger->SetMinimalCategory((NS_Logging::Category)level);
                    m_loggers[tmpLoggerName] = logger;
                }
            }
            else
            {
                isDefaultLevel = true;
                ms_defaultLevel = level;
            }
            loggerInfo.clear();
        }
        if (isDefaultLevel)
        {
            setDefaultCategoryForAllLogers();
        }
        configFile->Close();
        delete configFile;
    }
    //-------------------------------------------------------------------------------------------

    void LoggerFactory::setDefaultCategoryForAllLogers()
    {
        Loggers::iterator end = m_loggers.end();
        for (Loggers::iterator iter = m_loggers.begin(); iter != end; ++iter)
        {
            iter->second->SetMinimalCategory((NS_Logging::Category)ms_defaultLevel);
        }

    }
    //-------------------------------------------------------------------------------------------

    void LoggerFactory::expandLoggerInfo(const String& loggerInfo, LoggerName& loggerName, size_t& level)
    { // loggerName level
        const char *seperator = " ";
        String::size_type endName = loggerInfo.find_first_of(seperator);
        if (endName == String::npos)
        {
            loggerName = loggerInfo;
            level = ms_defaultLevel;
        }
        else
        {
            loggerName = loggerInfo.substr(0, endName);
            size_t beginLevel = endName + strlen(seperator);
            String::size_type endLevel = loggerInfo.find_first_of(seperator, beginLevel);
            String strLevel;
            if (endName == String::npos)
            {
                strLevel = loggerInfo.substr(beginLevel, endLevel);
            }
            else
            {
                strLevel = loggerInfo.substr(beginLevel, endLevel - beginLevel);
            }
            level = atoi(strLevel.c_str());
        }
    }
    //-------------------------------------------------------------------------------------------

    Logger& LoggerFactory::GetLogger(const char* name)
    {
        Loggers::iterator found = m_loggers.find(name);
        Logger* logger = NULL;
        if (m_loggers.end() == found)
        {
            logger = new(std::nothrow) Logger(name);
            if(logger == NULL)
            {
                LOGW("logger is NULL");
            }
            m_loggers[name] = logger;

            return *logger;
        }
        return *found->second;
    }
    //-------------------------------------------------------------------------------------------

    Logger& GetLogger(const char* name)
    {
        return NS_Logging::LoggerFactory::GetInstance().GetLogger(name);
    }
    //-------------------------------------------------------------------------------------------

    void ReleaseLoggers()
    {
        NS_Logging::LoggerFactory::GetInstance().Release();
    }
}
