#ifndef PQ_PQLog_H
#define PQ_PQLog_H

#include <QObject>
#include <QTextStream>
#include <QFile>
#include <QCoreApplication>
#include <QSharedPointer>
#include <QReadWriteLock>
#include <QThread>

//#ifdef _MSC_VER
//#pragma execution_character_set("utf-8")
//#endif

#define LOG(log,Level) if (log->checkLevel(Level)) \
    PQ::LogMessage(log,__FILE__, __LINE__,Level).stream()

#define pqTest(log) LOG(log,PQ::TestMsg)
#define pqDebug(log) LOG(log,PQ::DebugMsg)
#define pqInfo(log) LOG(log,PQ::InfoMsg)
#define pqWarning(log) LOG(log,PQ::WarningMsg)
#define pqCritical(log) LOG(log,PQ::CriticalMsg)
#define pqFatal(log) LOG(log,PQ::FatalMsg)

#define LOGD(Level) if (PQ::PQLogManger::this_()->baseLog()->checkLevel(Level)) \
    PQ::LogMessage(PQ::PQLogManger::this_()->baseLog(),__FILE__, __LINE__,Level).stream()

#define pqDTest LOGD(PQ::TestMsg)
#define pqDDebug LOGD(PQ::DebugMsg)
#define pqDInfo LOGD(PQ::InfoMsg)
#define pqDWarning LOGD(PQ::WarningMsg)
#define pqDCritical LOGD(PQ::CriticalMsg)
#define pqDFatal LOGD(PQ::FatalMsg)

namespace PQ {
class PQLog;
class LogMessage;

// 等级递增，只记录 >= 设置的level
enum LogLevel{
    TestMsg = 0,
    DebugMsg = 1,
    InfoMsg = 2,
    WarningMsg = 3,
    CriticalMsg = 4,
    FatalMsg = 5,
};

enum OutState{
    STD_OUT = 0, // std::out
    STD_ERROR = 1, // std::erro
    File = 2 // 文件
};

enum FileCreateType
{
    OnlyOne, //一直保存在一个文件中
    OneStartOne, // 每次程序启动生成新的
    DayOne,  // 每日一个
    HourOne, // 每小时一个
    MonthOne // 每月一个
};

class LogEvent;

class PQLogManger : public QObject
{
    Q_OBJECT
public:
    ~PQLogManger();

    static PQLogManger * this_();
    // 获取默认日志
    inline PQLog * baseLog()const {
        return _baseLog.data();
    }

    //获取Qt日志，可能为空，为空为为未接管
    inline PQLog * qDebugLog()const {
        return _qtLog.data();
    }
    // 设置日志保存位置
    bool setSaveFilePath(const QString & path);
    // 开启接管 Qt 日志 qdebug（）
    PQLog * enbleQtMessage();
    // 获取自定义日志
    PQLog * getLog(const QString & name);
    // 获取当前日志目录
    inline QString getSaveFilePath() const {return path_;}
signals:
    void updateSavePath();
private:
    QString path_;
    PQLogManger();
    QReadWriteLock _locker;
    QHash<QString, QSharedPointer<PQLog>> _logs;
    QSharedPointer<PQLog> _baseLog;
    QSharedPointer<PQLog> _qtLog;
    QThread _thread;
};

class PQLog : public QObject
{
    Q_OBJECT
public:
    ~PQLog();
    inline  bool checkLevel(LogLevel level) {
        if (level < this->level) {
            return false;
        }
        return true;
    }

    bool writeTime; // 是否记录日志时间
    bool writeFileInfo; // 是否记录日志在代码中的文件位置
    bool writeLevel; // 是否记录等级
    bool writeEndLine; // 是否自动换行
    LogLevel level; // 记录等级
    FileCreateType fileCreateType; //文件的生成方式

    // 输出位置
    void setOutState(OutState outState);
    inline OutState getOutState() const {return state_;}
protected:
    void customEvent(QEvent * event);

protected slots:
    void restLog();

    void releaseLogFile();
private:
    OutState state_;
    QFile * file_;
    QTextStream ts_;
    QString _name;
    int  _fileCreateId;
private:
    explicit PQLog(const QString & name,OutState state = File);
    friend class PQLogManger;
    friend class LogMessage;
};
// private: 不要直接操作
class LogMessage
{
public:
    LogMessage(PQLog * log, const char * file, int line, LogLevel level);
    LogMessage(PQLog * log,LogLevel level);
    ~LogMessage();
    inline QTextStream & stream() {return ts;}
private:
    PQLog * log;
    QString str_;
    QTextStream ts;
    LogLevel level_;
};


} //namespace PQLog

#endif // PQLog_H
