#include "Logger.h"
#ifdef __linux__
#include <unistd.h>
#define ACCESS access 
#elif _WIN32
#include <windows.h>
#include <io.h>
#define ACCESS _access 
#endif
#include "../Version.h"



static inline int NowDateToInt()
{
	time_t now;
	time(&now);
 
	// choose thread save version in each platform
    tm p = {0};
#ifdef _WIN32
	localtime_s(&p, &now);
#else
	localtime_r(&now, &p);
#endif // _WIN32
	int now_date = (1900 + p.tm_year) * 10000 + (p.tm_mon + 1) * 100 + p.tm_mday;
	return now_date;
}

static inline int NowTimeToInt()
{
	time_t now;
	time(&now);
	// choose thread save version in each platform
    tm p = { 0 };
#ifdef _WIN32
	localtime_s(&p, &now);
#else
	localtime_r(&now, &p);
#endif // _WIN32
 
	int now_int = p.tm_hour * 10000 + p.tm_min * 100 + p.tm_sec;
	return now_int;
}

#ifdef _WIN32  // Windows平台

#include <Windows.h>

static std::string GetDynamicLibraryPath()
{
    HMODULE hModule = GetModuleHandle(NULL);
    char path[MAX_PATH];
    GetModuleFileName(hModule, path, MAX_PATH);
    std::string fullPath(path);
    size_t pos = fullPath.find_last_of("\\/");
    return fullPath.substr(0, pos);
}

#elif __linux__  // Linux平台


#include <dlfcn.h>
#include <unistd.h>

static std::string GetDynamicLibraryPath()
{
    Dl_info dlInfo;
    dladdr((void*)GetDynamicLibraryPath, &dlInfo);
    char* path = realpath(dlInfo.dli_fname, NULL);
    std::string fullPath(path);
    free(path);
    size_t pos = fullPath.find_last_of("/");
    return fullPath.substr(0, pos);
}

#else

#error Unsupported platform

#endif



XLogger * XLogger::getInstance()
{
	static XLogger xlogger;
	return &xlogger;
}

std::shared_ptr<spdlog::logger> XLogger::getLogger(LogType type)
{
    switch(type) 
    {
        case LogType::_TIMER: return m_logger_Timer;
        case LogType::_INPUT: return m_logger_in;
        case LogType::_OUTPUT: return m_logger_out;
        default: return m_logger;
    }

    return m_logger;
}

void XLogger::setLevel(LogType type, int lev)
{
    auto level = static_cast<spdlog::level::level_enum>(lev);
    auto logger = getLogger(type);
    logger->set_level(level);
    logger->flush_on(level);
}

void XLogger::setLevel(int lev)
{
    auto level = static_cast<spdlog::level::level_enum>(lev);

    m_logger->set_level(level);
    m_logger->flush_on(level);
    
    m_logger_in->set_level(level);
    m_logger_in->flush_on(level);

    m_logger_out->set_level(level);
    m_logger_out->flush_on(level);

    m_logger_Timer->set_level(level);
    m_logger_Timer->flush_on(level);

    printf("set logger level:%d\n",lev);

}

int XLogger::getLevel(LogType type)
{
    auto logger = getLogger(type);
    return logger->level();
}

void XLogger::setLevelByFileState()
{
    char resPath[256] = { 0 };
    std::string path = GetDynamicLibraryPath();
    fileState = true;
    if (ACCESS(path.append("/LogT").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::trace);
        return;
    }
    if (ACCESS(path.append("/LogD").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::debug);
        return;
    }    
    if (ACCESS(path.append("/LogI").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::info);
        return;
    }   
    if (ACCESS(path.append("/LogW").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::warn);
        return;
    }
    if (ACCESS(path.append("/LogE").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::err);
        return;
    }
    if (ACCESS(path.append("/LogC").c_str(), 0) == 0)
    {
        setLevel(spdlog::level::critical);
        return;
    }

    // 不使用文件控制日志
    fileState = false;

}

void XLogger::createAllLogger()
{
    const std::string logger_name_prefix = "Neo";

    // logger name with timestamp
    int date = NowDateToInt();
    int time = NowTimeToInt();

    const std::string logger_name = logger_name_prefix + std::to_string(date) /*+ "_" + std::to_string(time)*/;

    const std::string logger_name_Input = "Arith_Input";
    const std::string logger_name_Output = "Arith_Output";
    const std::string logger_name_Timer = "Arith_Timer";


    m_logger = spdlog::create_async<spdlog::sinks::rotating_file_sink_mt>(logger_name, log_dir + "/" + logger_name + ".log", 
        10 * 1024 * 1024, 3); // multi part log files, with every part 500M, max 1000 files

    m_logger_in = spdlog::create_async<spdlog::sinks::rotating_file_sink_mt>(logger_name_Input, log_dir + "/" + logger_name_Input + ".log", 
        50 * 1024 * 1024, 3);//100M循环写入

    m_logger_out = spdlog::create_async<spdlog::sinks::rotating_file_sink_mt>(logger_name_Output, log_dir + "/" + logger_name_Output + ".log", 
        50* 1024 * 1024, 3);//100M循环写入

    m_logger_Timer = spdlog::create_async<spdlog::sinks::rotating_file_sink_mt>(logger_name_Timer, log_dir + "/" + logger_name_Timer + ".log", 
        0.1 * 1024 * 1024, 1); // multi part
    

    // 设置输出格式
    m_logger->set_pattern(LOG_OUTPUT_FORMAT_NONE_10KG);
    m_logger_in->set_pattern(LOG_OUTPUT_FORMAT_NONE_10KG);
    m_logger_out->set_pattern(LOG_OUTPUT_FORMAT_NONE_10KG);
    m_logger_Timer->set_pattern(LOG_OUTPUT_FORMAT_SIMPLE);

    
    // 输入日志默认debug，其他全关
    setLevel(spdlog::level::off);

    // 读取文件控制级别，如果有，则覆盖默认配置。
    setLevelByFileState();
}

XLogger::XLogger()
{

#ifdef NEON
    log_dir = "/app/sd/NeoLog";
#else
    log_dir = "NeoLog";
#endif

    fileState = false;     // 默认非文件设置状态

    try
    {
        createAllLogger();
    }
    catch (const spdlog::spdlog_ex& ex)
    {
        std::cout << "Log initialization failed: " << ex.what() << std::endl;
    }

}

XLogger::~XLogger()
{
    spdlog::drop_all(); // must do this
}

