#include "VrLog.h"

#include <iostream>
#include <cstring>
#include <stdarg.h>

#include <log4cpp/Category.hh>
#include <log4cpp/Appender.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/Priority.hh>
#include <log4cpp/PatternLayout.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/PropertyConfigurator.hh>

#include "VrFileUtils.h"

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#pragma comment(lib,"Ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#ifdef _WIN32
// windows:
#define logfilename(x) strrchr(x,'\\')?strrchr(x,'\\')+1:x
#else
// linux:
#define logfilename(x) strrchr(x,'/')?strrchr(x,'/')+1:x
#endif // _WIN32

////定义Log宏
///******************************************************************************************************************/


#ifdef STM32_UCOSIII
#define LOG_TIME do{ \
	OS_ERR err;\
	OS_TICK time = OSTimeGet(&err);	\
	printf("[%10u]",time);	\
	}while(0)
#else
#define  LOG_TIME do { \
    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();   \
    std::time_t timestamp = std::chrono::system_clock::to_time_t(now);              \
    std::tm local_time;    \
    localtime_s(&local_time, &timestamp);   \
    long long milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count(); \
    printf("%d-%02d-%02d %02d:%02d:%02d.%03lld", local_time.tm_year + 1900 , local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_hour, local_time.tm_min, local_time.tm_sec, milliseconds % 1000);   \
    } while(0)
#endif

#ifdef __ANDROID__
#include <android/log.h>
//#define  MY_LOG_VERBOSE(fmt, ...)  	__android_log_print(ANDROID_LOG_VERBOSE,	"VrAPPV", "V[%10s : %4u] " fmt, logfilename(__FILE__), __LINE__ ,##__VA_ARGS__)
//#define  MY_LOG_DEBUG(fmt, ...) 	__android_log_print(ANDROID_LOG_DEBUG,		"VrAPPD", "V[%10s : %4u] " fmt, logfilename(__FILE__), __LINE__ ,##__VA_ARGS__)
//#define  MY_LOG_INFO(fmt, ...)  	__android_log_print(ANDROID_LOG_INFO,		"VrAPPI", "V[%10s : %4u] " fmt, logfilename(__FILE__), __LINE__ ,##__VA_ARGS__)
//#define  MY_LOG_WARNING(fmt, ...)  	__android_log_print(ANDROID_LOG_WARN,		"VrAPPW", "V[%10s : %4u] " fmt, logfilename(__FILE__), __LINE__ ,##__VA_ARGS__)
//#define  MY_LOG_ERRO(fmt, ...)  	__android_log_print(ANDROID_LOG_ERROR,		"VrAPPE", "V[%10s : %4u] " fmt, logfilename(__FILE__), __LINE__ ,##__VA_ARGS__)

#define  MY_LOG_VERBOSE(fmt, ...)  	__android_log_print(ANDROID_LOG_VERBOSE,	"VrAPPV",   ##__VA_ARGS__)
#define  MY_LOG_DEBUG(fmt, ...) 	__android_log_print(ANDROID_LOG_DEBUG,		"VrAPPD",   ##__VA_ARGS__)
#define  MY_LOG_INFO(fmt, ...)  	__android_log_print(ANDROID_LOG_INFO,		"VrAPPI",   ##__VA_ARGS__)
#define  MY_LOG_WARNING(fmt, ...)  	__android_log_print(ANDROID_LOG_WARN,		"VrAPPW",   ##__VA_ARGS__)
#define  MY_LOG_ERRO(fmt, ...)  	__android_log_print(ANDROID_LOG_ERROR,		"VrAPPE",   ##__VA_ARGS__)
#else

#define  MY_LOG_VERBOSE(fmt, ...)       do { LOG_TIME; printf(" V[%10s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } while(0)
#define  MY_LOG_DEBUG(fmt, ...) 		do { LOG_TIME; printf(" D[%10s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } while(0)

#define  MY_LOG_DEBUG_NOLINE(fmt, ...) 	printf(fmt, ##__VA_ARGS__)
#define  MY_LOG_INFO(fmt, ...)  		do { LOG_TIME; printf(" I[%10s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } while(0)
#define  MY_LOG_WARNING(fmt, ...)       do { LOG_TIME; printf(" W[%10s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } while(0)
#define  MY_LOG_ERRO(fmt, ...)  		do { LOG_TIME; printf(" E[%10s : %4u] " fmt"", logfilename(__FILE__), __LINE__ ,##__VA_ARGS__); } while(0)
#endif // __ANROID__
///******************************************************************************************************************/

#ifdef __ANDROID__
#define LOG_PATH  "/sdcard/VrPrintlog"
#define PATH_SEP  "/"
#else
#define LOG_PATH  ".\\VrPrintlog"
#define PATH_SEP  "\\"
#endif

#define LOG_CONFIG_FILE  "config.ini"
#define LOG_PRINT_FILE   "VrLog.log"

static log4cpp::PatternLayout*         m_pLayout = nullptr;
static log4cpp::RollingFileAppender*   m_prollfileAppender = nullptr;

/// 初始化log
void VrLogUtils::InitLog()
{
    // if file exist then load file config
    std::string logConfig = std::string(LOG_PATH).append(PATH_SEP).append(LOG_CONFIG_FILE);
    if (CVrFileUtils::IsFileExist(logConfig.c_str()))
    {
        // load profile
        try
        {
            log4cpp::PropertyConfigurator::configure(logConfig);
        }
        catch (log4cpp::ConfigureFailure& f)
        {
            std::cout << "Load Log Profile Error" << f.what() << std::endl;
        }
    }
    else
    {
        if (!CVrFileUtils::IsDirExist(LOG_PATH))
        {
            CVrFileUtils::CreatNewDir(LOG_PATH);
        }

        // create file appender
        if (nullptr == m_pLayout)
        {
            m_pLayout = new log4cpp::PatternLayout;
            m_pLayout->setConversionPattern(std::string("[%d] [%p] %c %x: %m%n"));
        }
        if (nullptr == m_prollfileAppender)
        {
            m_prollfileAppender = new log4cpp::RollingFileAppender(LOG_PATH, std::string(LOG_PATH).append(PATH_SEP).append(LOG_PRINT_FILE), 10 * 1024, 1);

            m_prollfileAppender->setLayout(m_pLayout);

            // add appender to category
            log4cpp::Category& root = log4cpp::Category::getRoot();
            root.addAppender(m_prollfileAppender);

            // set priority
            root.setPriority(log4cpp::Priority::DEBUG);
        }
    }
}

/// 关闭log
void VrLogUtils::UninitLog()
{
    if (m_pLayout) 
    {
        delete m_pLayout;
    }

    if (m_prollfileAppender)
    {
        delete m_prollfileAppender;
    }
    log4cpp::Category::shutdown();//关闭Category;
}

/// 输出log
void VrLogUtils::EchoLog(VrLogLevel eLogLevel, const char* sLogGroup, const char* sFormat, ...)
{
    // load log info
    va_list args;
    va_start(args, sFormat);
    char szLogInfo[1024] = { 0 };
#ifdef _WIN32
    vsprintf_s(szLogInfo, sFormat, args);
#else
    vsprintf(szLogInfo, sFormat, args);
#endif
    va_end(args);
    log4cpp::Category& root = log4cpp::Category::getRoot();

    switch (eLogLevel)
    {
    case KELOGLEVEL_None:
        break;
    case KELOGLEVEL_Verbose:
        MY_LOG_VERBOSE("%s", szLogInfo);
        if (nullptr != m_pLayout && nullptr != m_prollfileAppender)
        {
            LOG4CPP_DEBUG(root, szLogInfo);
        }
        break;
    case KELOGLEVEL_Debug:
        MY_LOG_DEBUG("%s", szLogInfo);
        if (nullptr != m_pLayout && nullptr != m_prollfileAppender)
        {
            LOG4CPP_DEBUG(root, szLogInfo);
        }
        break;
    case KELOGLEVEL_Info:
        MY_LOG_INFO("%s", szLogInfo);
        if (nullptr != m_pLayout && nullptr != m_prollfileAppender)
        {
            LOG4CPP_INFO(root, szLogInfo);
        }
        break;
    case KELOGLEVEL_Warning:
        MY_LOG_WARNING("%s", szLogInfo);
        if (nullptr != m_pLayout && nullptr != m_prollfileAppender)
        {
            LOG4CPP_WARN(root, szLogInfo);
        }
        break;
    case KELOGLEVEL_Error:
        MY_LOG_ERRO("%s", szLogInfo);
        if (nullptr != m_pLayout && nullptr != m_prollfileAppender)
        {
            LOG4CPP_ERROR(root, szLogInfo);
        }
        break;
    default:
        break;
    }
}

/// 修改log level default info
void VrLogUtils::AlterLogLevel(VrLogLevel eLogLevel)
{

}

/// 修改log输出形式  默认都输出
void VrLogUtils::AlterLogType(VrLogType eLogType)
{

}
