/*
 * @Author: your name
 * @Date: 2022-02-08 15:59:33
 * @LastEditors: your name
 * @LastEditTime: 2022-02-16 10:39:05
 * @Description: file content
 * @FilePath: \lirs\code\MyYaml\MyYaml.h
 * 
 * Copyright © 2022 <Shandong Matrix Software Engineering Co., Ltd>
 */
#ifndef CONFIG_H_
#define CONFIG_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;
        // 日志文件目录
        std::string strLogPath;
        // 识别结果目录
        std::string strResultPath;
        // 调试结果目录
        std::string strDebugResultPath;
        // 日志存储天数
        int iResultSaveDays;
    };

    // 日志参数
    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;
        // 识别区域
        std::vector<int> vecIdentifyAreas;
        // 切箱方式
        std::string strDivideModel;
        // 汽车行进方向
        std::string strRunDirection;
    };

    // 识别参数
    struct IdentifyConfig {
        // 大框帧跨度（比一个大框从出现到消失的跨度稍大一点, 跟跳帧有关系）
        int iPartitionFrameSpan;
        // 顶部Y轴大框帧跨度的位置像素差异
        int iTop_Y_SplitSpanPx;
        // 侧边X轴大框帧跨度的位置像素差异
        int iSide_X_SplitSpanPx;
        // 每帧大框位置差异最小值 (持续小于此值，则可能停车)
        int iChkstopPx;
        // 持续X次续位置差异小于gc_chkstop_px，则判断为停车。
        int iChkstopCount;
        // 过滤最小大框高度（不需要的话就写个很小的值）
        int iTargetMinHeight;
        // 过滤最小大框宽度（不需要的话就写个很小的值）
        int iTargetMinWidth;
        // 过滤低于指定Y轴的大框
        int iTargetMinY;
        // 单次识别最大帧数
        int iMaxIdentifyFrame;
        // 两个箱子的箱角最大差值X
        int iMaxContainerSpaceX;
        // 两个箱子的箱角最大差值Y
        int iMaxContainerSpaceY;
    };

    // 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 strUpDeviceStatusUrl;
        // 接口用户名
        std::string strUserName;
        // 接口密码
        std::string strPassword;
    };

    struct MinioConfig
    {
        // 使用状态
        bool bIsUse;
        // 服务地址
        std::string strUrl;
        // 通讯授权
        std::string strAccessKey;
        // 密钥授权
        std::string strSecretKey;
        // 容器名
        std::string strBucket;
    };

    struct ModelConfig
    {
        std::string strModelPath;
        float fScoreThreshold;
        std::vector<std::string> vecClass;
    };


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

        // 读yaml文件
        int readYaml(std::string &strPath);
        int readModelYaml(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);
        // 获取数据源参数
        std::vector<DataSourceConfig> getAllDataSourceConfig() const;
        void setDataSourceConfig(int index, const ai_matrix::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);
        // 获取minio服务器参数
        MinioConfig getMinioConfig() const;
        void setMinioConfig(const MinioConfig minioCConfig);
        // 获取集装箱关键区域检测模型参数
        ModelConfig getModelByContainerStep1Config() const;
        void setModelByContainerStep1Config(const ModelConfig modelConfig);
        // 获取集装箱文字检测模型参数
        ModelConfig getModelByContainerStep2Config() const;
        void setModelByContainerStep2Config(const ModelConfig modelConfig);
        // 获取集装箱文字检测模型参数
        ModelConfig getModelByCornerConfig() const;
        void setModelByCornerConfig(const ModelConfig modelConfig);


        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_;

        // 数据源列表
        std::vector<DataSourceConfig> vecDataSourceConfig_;

        // 识别参数
        IdentifyConfig identifyConfig_;

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

        // web服务器参数
        HttpServerConfig httpServerConfig_;

        // MinIO服务器参数
        MinioConfig minioConfig_;

        // 集装箱第一步识别
        ModelConfig modelConfig_containerStep1_;
        // 集装箱第二步识别
        ModelConfig modelConfig_containerStep2_;
        // 集装箱箱角识别
        ModelConfig modelConfig_corner_;

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

#endif