#include "logger.h"
#include "src/po/translation.h"
#include "src/frame/configuration.h"

#include <fcntl.h>
#include <unistd.h>

#include <QDateTime>
#include <QDir>

#define LOG_PATH "/tmp/kylin-burner/log/"

Logger *Logger::m_oInstance = nullptr;
QMutex  Logger::m_oMutex;

static QStringList level;


Logger::Logger(QObject *parent) :
    QObject(parent),
    m_iLevel(-1),
    m_iHandle(-1),
    m_iCurrentLevel(Info)
{
    m_oRegister.clear();
    level << _("info") << _("warn") << _("error") << _("debug");
}

Logger *Logger::instance()
{
    if (nullptr == m_oInstance)
    {
        QMutexLocker locker(&m_oMutex);
        if (nullptr == m_oInstance)
        {
            m_oInstance = new Logger();
        }
    }
    return m_oInstance;
}

void Logger::init()
{
    QString defaultPath;
    QDir logDir;

    defaultPath = LOG_PATH;
    logDir.setPath(LOG_PATH);
    if (!logDir.mkpath(LOG_PATH)) return;
    defaultPath = CFG->get("logger", "path", defaultPath).toString();
    if (!defaultPath.endsWith("/")) defaultPath.append("/");
    if (!logDir.mkpath(defaultPath))
    {
        defaultPath = LOG_PATH;
        CFG->set("logger", "path", defaultPath);
    }
    defaultPath.append(QString("%1.log").arg(date()));
    m_iHandle = ::open(defaultPath.toUtf8().constData(), O_RDWR | O_CREAT | O_APPEND, 0664);
    if (-1 == m_iHandle) return;
    m_iLevel = CFG->get("logger", "level", Info).toInt();
    if (m_iLevel > Debug) m_iLevel = Debug;
    info(_("logger path : %1").arg(defaultPath));
    info(_("Will record under %1 level log.").arg(level[m_iLevel]));
}

QString Logger::registerName(QObject *obj, QString name)
{
    if (m_oRegister.value(obj).isEmpty())
    {
        m_oRegister.insert(obj, name);
    }
    return m_oRegister.value(obj);
}

void Logger::info(const char *fmt, ...)
{
    char    content[2048];
    va_list list;
    m_iCurrentLevel = Info;
    va_start(list, fmt);
    vsprintf(content, fmt, list);
    va_end(list);
    log(QString::fromUtf8(content, strlen(content)));
}

void Logger::warn(const char *fmt, ...)
{
    char    content[2048];
    va_list list;
    m_iCurrentLevel = Warning;
    va_start(list, fmt);
    vsprintf(content, fmt, list);
    va_end(list);
    log(QString::fromUtf8(content, strlen(content)));
}

void Logger::error(const char *fmt, ...)
{
    char    content[2048];
    va_list list;
    m_iCurrentLevel = Error;
    va_start(list, fmt);
    vsprintf(content, fmt, list);
    va_end(list);
    log(QString::fromUtf8(content, strlen(content)));
}

void Logger::debug(const char *fmt, ...)
{
    char    content[2048];
    va_list list;
    m_iCurrentLevel = Debug;
    va_start(list, fmt);
    vsprintf(content, fmt, list);
    va_end(list);
    log(QString::fromUtf8(content, strlen(content)));
}

void Logger::info(QString content)
{
    m_iCurrentLevel = Info;
    log(content, model(sender()));
}

void Logger::warn(QString content)
{
    m_iCurrentLevel = Warning;
    log(content, model(sender()));
}

void Logger::error(QString content)
{
    m_iCurrentLevel = Error;
    log(content, model(sender()));
}

void Logger::debug(QString content)
{
    m_iCurrentLevel = Debug;
    log(content, model(sender()));
}

QString Logger::model(QObject *obj)
{
    if (m_oRegister.value(obj).isEmpty() || nullptr == obj)
        return QString(_("common"));
    return m_oRegister.value(obj);
}

QString Logger::date()
{
    return QDateTime::currentDateTime().toString("yyyyMMdd");
}

QString Logger::dateTime()
{
    return QDateTime::currentDateTime().toString("yyyy-MMMM-dd dddd HH:mm:ss.z");
}

void Logger::log(QString content, QString model)
{
    QString w;
    QString m;

    if ((m_iLevel < m_iCurrentLevel) && m_iCurrentLevel != Error) return;

    m = model;
    if (m.isEmpty()) m = this->model();

    w.clear();
    // date time pid appname model level - content
    w.append(dateTime());
    w.append(" ");
    w.append(QString("%1").arg(::getpid()));
    w.append(" ");
    w.append(_("KylinBurner"));
    w.append(" ");
    w.append(m);
    w.append(" ");
    w.append(level[m_iCurrentLevel]);
    w.append(" - ");
    w.append(content);
    w.append("\n");
    if (-1 != m_iHandle)
    {
        lseek(m_iHandle, SEEK_END, 0);
        ::write(m_iHandle, w.toUtf8().constData(), w.toUtf8().length());
    }
    if (m_iCurrentLevel > Info)
    {
        printf("%s", w.toUtf8().constData());
        fflush(0);
    }
}

Logger::~Logger()
{
    if (-1 != m_iHandle) ::close(m_iHandle);
}
