#include "fmp_logger_p.h"
#include <fmp_settings_i.h>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QCoreApplication>
#include <ctkPluginContext.h>
#include <ctkServiceReference.h>

FMPLoggerPrivate::FMPLoggerPrivate(FMPLogger *q, ctkPluginContext *ctx)
    : q_ptr(q),
      _ctx(ctx),
      _inited(false)
{
    _lvlmap[FMPLogger::LOG_DEBUG] = "dbg";
    _lvlmap[FMPLogger::LOG_INFO] = "info";
    _lvlmap[FMPLogger::LOG_WARNING] = "warn";
    _lvlmap[FMPLogger::LOG_ERROR] = "err";
}

int FMPLoggerPrivate::Init()
{
    if (_inited) return FMP_SUCCESS;

    Q_Q(FMPLogger);

    QString filename = _NewFileName();
    q->_file = new QFile(filename);
    q->_file->open(QFile::WriteOnly);

    _inited = true;
    return FMP_SUCCESS;
}

int FMPLoggerPrivate::Uninit()
{
    if (!_inited) return FMP_SUCCESS;

    Q_Q(FMPLogger);
    //! Clean up
    q->_file->close();
    _inited = false;
    delete q->_file;
    q->_file = 0;
    return FMP_SUCCESS;
}

short FMPLoggerPrivate::GetLogLevel()
{
    return _GetValue(FMP_INIKEY_LOGLEVEL, FMPLogger::LOG_INFO).toInt();
}

void FMPLoggerPrivate::SetLogLevel(short level)
{
    if (_SetValue(FMP_INIKEY_LOGLEVEL, level)) {
        Q_Q(FMPLogger);
        q->_level = level;
    }
}

uint FMPLoggerPrivate::GetMaxLogSize()
{
    return _GetValue(FMP_INIKEY_LOGSIZE, 2).toUInt();
}

void FMPLoggerPrivate::SetMaxLogSize(uint sz)
{
    if (_SetValue(FMP_INIKEY_LOGSIZE, sz)) {
        Q_Q(FMPLogger);
        q->_max_size = sz;
    }
}

QString FMPLoggerPrivate::GetLogPath()
{
    QString path = _GetValue(FMP_INIKEY_LOGPATH).toString();
    if (path.isEmpty()) path = qApp->applicationDirPath() + "/log";
    path.replace("\\", "/");
    QDir log_dir;
    if (!log_dir.isAbsolutePath(path)) {
        path = qApp->applicationDirPath() + "/" + path;
    }
    return path;
}

void FMPLoggerPrivate::SetLogPath(const QString &path)
{
    if (_SetValue(FMP_INIKEY_LOGPATH, path)) {
        q_func()->_path = path;
    }
}

void FMPLoggerPrivate::Log(short level, const QString &msg, const char* file, const char* func, int line)
{
    Q_Q(FMPLogger);

    if (level > q->_level) {
        if (q->_file->size() >= (q->_max_size * 1024 * 1024)) {
            q->_file->close();
            q->_file->setFileName(_NewFileName());
            q->_file->open(QFile::WriteOnly);
        }
        FMPLogStream(level, file, func, line, q->_file) << msg;
    }
    else {
        FMPNullLogStream(level, file, func, line) << msg;
    }
}

QString FMPLoggerPrivate::_NewFileName()
{
    QString file_time = QDateTime::currentDateTime().toString("yyMMddhhmmss");
    Q_Q(FMPLogger);
    QString log_path = GetLogPath();
    QDir log_dir(log_path);
    if (!log_dir.exists()) {
        if (log_dir.mkdir(log_path)) {
            _FMP_INFO << "Create log dir:" << log_path;
        }
        else {
            _FMP_INFO << "Create log dir" << log_path << "failed!";
        }
    }
    return q->_path + "/" + _lvlmap[q->_level] + "_" + file_time + ".log";
}

bool FMPLoggerPrivate::_SetValue(const QString &key, QVariant v)
{
    Q_Q(FMPLogger);
    FMPSettingsInterface *sets = q->GetService<FMPSettingsInterface>(_ctx);
    if (sets) {
        sets->SetValue(key, v);
        return true;
    }
    else {
        FMP_WARN(q) << "Settings service not available";
    }

    return false;
}

QVariant FMPLoggerPrivate::_GetValue(const QString &key, QVariant default_val)
{
    Q_Q(FMPLogger);
    FMPSettingsInterface *sets = q->GetService<FMPSettingsInterface>(_ctx);
    if (sets) {
        return sets->GetValue(key);
    }
    else {
        FMP_WARN(q) << "Settings service not available";
    }

    return default_val;
}

void FMPLoggerPrivate::_KeepFileSize()
{
    Q_Q(FMPLogger);
    qint64 file_sz = q->_file->size();
    if ( file_sz >= (q->_max_size * 1024 * 1024)) {
        QString new_file_name = _NewFileName();
        FMP_INFO(q) << "Current log file size:" << file_sz << "reaches max value";
        FMP_INFO(q) << "New log file:" << new_file_name;
        q->_file->close();
        q->_file->setFileName(new_file_name);
        q->_file->open(QFile::WriteOnly);
    }
}
