#ifndef MYYAML_H_
#define MYYAML_H_


#include <mutex>
#include <fstream>
#include "yaml-cpp/yaml.h"
#include "Log.h"

namespace ai_matrix
{

    struct RunConfig
    {
        // 识别状态
        bool bRun;

    };

    // 基础控制参数
    struct BaseConfig
    {
        // 股道名称
        std::string strTrackName;
        // 测试模式
        bool bTestModel;
        // Api 监听端口
        int iApiPort;
        // 是否上传识别结果
        bool bUpResult;
        // 日志文件目录
        std::string strLogPath;
        // 识别结果目录
        std::string strResultPath;
        // 调试结果目录
        std::string strDebugResultPath;
        // 日志存储天数
        int iResultSaveDays;
        // 过期文件夹天数
        int iDayForResultExpire;
    };

    // 日志参数
    struct LogConfig {
        // 输出日志级别[DEBUG, INFO, WARN, ERROR, FATAL]
        std::string strOutLevel;
        // 保存日志级别[DEBUG, INFO, WARN, ERROR, FATAL]
        std::string strSaveLevel;
    };

    // 数据源参数
    struct DataSourceConfig {
        // 数据源地址
        std::string strUrl;
        // 跳帧数
        int iSkipInterval;
        // 行驶方向  0-自动识别 1-向左 2-向右 （与“首位信息”成对存在，形成例如向左就编号在前，向右就属性在前的对应）
        int iDirection;
        // 0-向左编号在前 1-向左属性在前 (向右行驶的情况：2-向右编号在前 3-向右属性在前)
        int iLeftFirst;
        // (向左行驶的情况：0-向左编号在前 1-向左属性在前) 2-向右编号在前 3-向右属性在前
        int iRightFirst;
    };

    // 识别参数
    struct IdentifyConfig {
        // 运行方式
        std::string strRunModel;
        // 是否开启动态检测
        bool bNeedMoveDetectFlag;
        // 识别方向  [LEFT,RIGHT,ALL]
        std::string strIdentifyDirection;
        // 大框帧跨度（比一个大框从出现到消失的跨度稍大一点, 跟跳帧有关系）
        int iPartitionFrameSpan;
        // 大框帧跨度的位置像素差异
        int iSplitFrameSpanPx;
        // 每帧大框位置差异最小值 (持续小于此值，则可能停车)
        int iChkstopPx;
        // 持续X次续位置差异小于gc_chkstop_px，则判断为停车。
        int iChkstopCount;
        // 过滤最小大框高度（不需要的话就写个很小的值）
        int iNumFrameHeight;
        int iProFrameHeight;
        // 过滤最大框宽度（不需要的话就写个很大的值）
        int iSpaceFrameWidth;
        // 是否识别车头
        bool bTrainHeardDetect;
    };

    // websocket_server 的服务端参数
    struct WSocketConfig {
        // 是否启用
        bool bIsUse;
        // 端口
        int iPort;
        // 最大链接队列
        int iMaxQueueLen;
    };

    // web服务器参数
    struct HttpServerConfig
    {
        // 使用状态
        bool bIsUse;
        // 获取接口授权地址
        std::string strIp;
        // 通讯端口
        int iPort;
        // 获取接口授权地址
        std::string strTokenUrl;
        // 识别结果上传地址
        std::string strUpResultUrl;
        // 接口用户名
        std::string strUserName;
        // 接口密码
        std::string strPassword;
    };

    class Config final
    {
    public:
        static Config *GetIns();

        // 读yaml文件
        int readYaml(std::string &strPath);
        // 写yaml文件
        int writeYaml();
        std::string getStringValue(const char *pszKey, const YAML::Node *pConfig = nullptr) const;
        int getIntValue(const char *pszKey, const YAML::Node *pConfig = nullptr) const;
        bool getBoolValue(const char *pszKey, const YAML::Node *pConfig = nullptr) const;
        float getFloatValue(const char *pszKey, const YAML::Node *pConfig = nullptr) const;
        std::string getPathValue(const char *pszKey, const YAML::Node *pConfig =nullptr) const;


        RunConfig getRunConfig() const;
        void setRunConfig(const RunConfig runConfig);

        // 获取控制参数
        BaseConfig getBaseConfig() const;
        void setBaseConfig(const BaseConfig baseConfig);
        // 获取日志参数
        LogConfig getLogConfig() const;
        void setLogConfig(const LogConfig logConfig);
        // 获取数据源参数
        DataSourceConfig getDataSourceConfig() const;
        void setDataSourceConfig(const DataSourceConfig dataSourceConfig);
        // 获取识别参数
        IdentifyConfig getIdentifyConfig() const;
        void setIdentifyConfig(const IdentifyConfig identifyConfig);
        // 获取websocket server 参数
        WSocketConfig getWSocketConfig() const;
        void setWSocketConfig(const WSocketConfig wSocketConfig);
        // 获取web服务器参数
        HttpServerConfig getHttpServerConfig() const;
        void setHttpServerConfig(const HttpServerConfig httpServerConfig);

        YAML::Node config_;

    private:
        Config() = default;
        Config(const Config &) = delete;
        Config(Config &&) = delete;
        Config &operator=(const Config &) = delete;
        Config &operator=(Config &&) = delete;
        ~Config() = default;

        static Config *pInstance_;
        static std::mutex mx_; //锁，保证线程安全
        std::string strConfigYamlPath_;

        // （全局）运行实时变量
        RunConfig runConfig_;

        // 控制参数
        BaseConfig baseConfig_;

        // 日志参数
        LogConfig logConfig_;

        // 数据源参数
        DataSourceConfig dataSourceConfig_;

        // 识别参数
        IdentifyConfig identifyConfig_;

        // websocket server 服务端参数
        WSocketConfig wSocketConfig_;

        // web服务器参数
        HttpServerConfig httpServerConfig_;

        //定义一个嵌套类，负责释放内存，操作系统自动完成，不用担心内存泄露
        class GarbageCollector
        {
        public:
            ~GarbageCollector()
            {
                if (Config::pInstance_)
                {
                    delete Config::pInstance_;
                    Config::pInstance_ = nullptr;
                }
            }
        };
        static GarbageCollector gc_;
    };
}

#endif