/********************************************************************
* CONFIDENTIAL - All source code is the propriety and confidential  *
* information of David Sorber.                                      *
*                                                                   *
* Copyright 2024 David Sorber                                       *
* Unpublished -- all rights reserved under the copyright laws       *
* of the United States.                                             *
********************************************************************/

#include <chrono>
#include <cstdio>
#include <ctime>
#include <stdexcept>

#include "Logger.h"


DBS::Logger::Logger(CopyManagerOptions* configObj)
    : r_options(*configObj)
{
    m_outputStream.str("");

    if (r_options.getLogToStderr() == false)
    {
        // If configured to log to file attempt to open the specified log file
        m_logFile.open(r_options.getLogFilePath(), std::ios::out | std::ios::app);
        if (!m_logFile)
        {
            throw std::runtime_error("Unable to open log file: " +
                                     r_options.getLogFilePath());
        }
    }
}

DBS::Logger::~Logger()
{
    // Close log file if it was opened
    if (m_logFile.is_open())
    {
        m_logFile.close();
    }
}

void DBS::Logger::log_msg(
    enum LOG_LEVEL level,
    const std::string& msg)
{
    // Filter log messages as needed
    if ((! r_options.getEnableLog()) || level > r_options.getLogLevel())
    {
        return;
    }

    // Grab current time
    struct timeval tv{};
    gettimeofday(&tv, nullptr);
    struct tm* tm = std::localtime(&tv.tv_sec);

    char time_format[32], time_str[32];

    const bool LOG_WITH_MILLISECONDS = true;
    if (LOG_WITH_MILLISECONDS == true)
    {
        // Set format to include milliseconds
        std::strftime(time_format,
                      sizeof(time_format),
                      "%a %b %d %H:%M:%S.%%03u %Y",
                     tm);
        std::snprintf(time_str,
                      sizeof(time_str),
                      time_format,
                      (tv.tv_usec / 1000));
    }
    else
    {
        // Set format to not include milliseconds
        std::strftime(time_str,
                      sizeof(time_str),
                      "%a %b %d %H:%M:%S %Y",
                      tm);
    }

    switch (level)
    {
        case error:
            getStream() << time_str << "|ERROR|copytool|" << msg << std::endl;
            break;

        case warn:
            getStream() << time_str << "|WARNING|copytool|" << msg << std::endl;
            break;

        case info:
            getStream() << time_str << "|INFO|copytool|" << msg << std::endl;
            break;

        case debug:
            getStream() << time_str << "|DEBUG|copytool|" << msg << std::endl;
            break;

        case trace:
            getStream() << time_str << "|TRACE|copytool|" << msg << std::endl;
            break;

        default:
            break;
    }
}