#include "Config.h"

namespace ai_matrix
{
    Config *Config::pInstance_ = nullptr;
    Config::GarbageCollector Config::gc_;
    std::mutex Config::mx_;

    Config *Config::getins()
    {
        //双层锁，确保线程安全
        if (pInstance_ == nullptr)
        {
            std::lock_guard<std::mutex> guard(mx_); //防止异常发生不能解锁
            if (pInstance_ == nullptr)
            {
                pInstance_ = new Config();
            }
        }
        return pInstance_;
    }

    int Config::readYaml(std::string &strPath)
    {
        try
        {
            strConfigYamlPath_ = strPath;
            config_ = YAML::LoadFile(strPath);

            //退出程序
            if (config_.IsNull())
            {
                printf("config.yaml no find");
                return -1;
            }

            // 控制参数
            this->baseConfig_.strTrackName = config_["base"]["track_name"].as<std::string>();
            this->baseConfig_.bTestModel = config_["base"]["test_model"].as<bool>();
            this->baseConfig_.iApiPort = config_["base"]["api_port"].as<int>();
            this->baseConfig_.strLogPath = config_["base"]["log_path"].as<std::string>();
            this->baseConfig_.strResultPath = config_["base"]["result_path"].as<std::string>();
            this->baseConfig_.strDebugResultPath = config_["base"]["debug_result_path"].as<std::string>();
            this->baseConfig_.iResultSaveDays = config_["base"]["result_save_days"].as<int>();

            // 日志参数
            this->logConfig_.strOutLevel = config_["log"]["out_level"].as<std::string>();
            this->logConfig_.strSaveLevel = config_["log"]["save_level"].as<std::string>();

            std::vector<YAML::Node> vecDataSourceNode = config_["data_source"].as<std::vector<YAML::Node>>();
            // 数据源参数
            for (const auto & it : vecDataSourceNode)
            {
                DataSourceConfig dataSourceConfig;
                dataSourceConfig.strUrl = it["url"].as<std::string>();
                dataSourceConfig.iSkipInterval = it["skip_interval"].as<int>();
                dataSourceConfig.vecIdentifyAreas = it["identify_areas"].as<std::vector<int>>();
                dataSourceConfig.strDivideModel = it["divide_mode"].as<std::string>();
                dataSourceConfig.strRunDirection = it["run_direction"].as<std::string>();
                this->vecDataSourceConfig_.emplace_back(dataSourceConfig);
            }

            // 识别参数
            this->identifyConfig_.iPartitionFrameSpan = config_["identify"]["partition_frame_span"].as<int>();
            this->identifyConfig_.iTop_Y_SplitSpanPx = config_["identify"]["top_y_split_span_px"].as<int>();
            this->identifyConfig_.iSide_X_SplitSpanPx = config_["identify"]["side_x_split_span_px"].as<int>();
            this->identifyConfig_.iChkstopPx = config_["identify"]["chkstop_px"].as<int>();
            this->identifyConfig_.iChkstopCount = config_["identify"]["chkstop_count"].as<int>();
            this->identifyConfig_.iTargetMinHeight = config_["identify"]["target_min_height"].as<int>();
            this->identifyConfig_.iTargetMinWidth = config_["identify"]["target_min_width"].as<int>();
            this->identifyConfig_.iTargetMinY = config_["identify"]["target_min_y"].as<int>();
            this->identifyConfig_.iMaxIdentifyFrame = config_["identify"]["max_identify_frame"].as<int>();
            this->identifyConfig_.iMaxContainerSpaceX = config_["identify"]["max_container_space_x"].as<int>();
            this->identifyConfig_.iMaxContainerSpaceY = config_["identify"]["max_container_space_y"].as<int>();

            // websocket server 服务端参数
            this->wSocketConfig_.bIsUse = config_["wsocket_server"]["is_use"].as<bool>();
            this->wSocketConfig_.iPort = config_["wsocket_server"]["port"].as<int>();
            this->wSocketConfig_.iMaxQueueLen = config_["wsocket_server"]["max_queue_len"].as<int>();

            // http服务器参数
            this->httpServerConfig_.bIsUse = config_["http_server"]["is_use"].as<bool>();
            this->httpServerConfig_.strIp = config_["http_server"]["http_ip"].as<std::string>();
            this->httpServerConfig_.iPort = config_["http_server"]["http_port"].as<int>();
            this->httpServerConfig_.strTokenUrl = config_["http_server"]["token_path"].as<std::string>();
            this->httpServerConfig_.strUpResultUrl = config_["http_server"]["up_result_path"].as<std::string>();
            this->httpServerConfig_.strUpDeviceStatusUrl = config_["http_server"]["device_status_url"].as<std::string>();
            this->httpServerConfig_.strUserName = config_["http_server"]["username"].as<std::string>();
            this->httpServerConfig_.strPassword = config_["http_server"]["password"].as<std::string>();

            // http服务器参数
            this->minioConfig_.bIsUse = config_["minio"]["is_use"].as<bool>();
            this->minioConfig_.strUrl = config_["minio"]["url"].as<std::string>();
            this->minioConfig_.strAccessKey = config_["minio"]["accesskey"].as<std::string>();
            this->minioConfig_.strSecretKey = config_["minio"]["secretkey"].as<std::string>();
            this->minioConfig_.strBucket = config_["minio"]["bucket"].as<std::string>();
        }
        catch (...) //捕获所有异常
        {
            return -1;
        }
        return 0;
    }

    int Config::readModelYaml(std::string &strPath)
    {
        try
        {
            strConfigYamlPath_ = strPath;
            config_ = YAML::LoadFile(strPath);

            //退出程序
            if (config_.IsNull())
            {
                printf("config.yaml no find");
                return -1;
            }

            // 集装箱第一步模型
            this->modelConfig_containerStep1_.strModelPath = config_["container_step1_model"]["model_path"].as<std::string>();
            this->modelConfig_containerStep1_.fScoreThreshold = config_["container_step1_model"]["score_threshold"].as<float>();
            this->modelConfig_containerStep1_.vecClass = config_["container_step1_model"]["class"].as<std::vector<std::string>>();

            // 集装箱第二步模型
            this->modelConfig_containerStep2_.strModelPath = config_["container_step2_model"]["model_path"].as<std::string>();
            this->modelConfig_containerStep2_.fScoreThreshold = config_["container_step2_model"]["score_threshold"].as<float>();
            this->modelConfig_containerStep2_.vecClass = config_["container_step2_model"]["class"].as<std::vector<std::string>>();

            // 集装箱箱角模型
            this->modelConfig_corner_.strModelPath = config_["corner_model"]["model_path"].as<std::string>();
            this->modelConfig_corner_.fScoreThreshold = config_["corner_model"]["score_threshold"].as<float>();
            this->modelConfig_corner_.vecClass = config_["corner_model"]["class"].as<std::vector<std::string>>();

        }
        catch (...) //捕获所有异常
        {
            return -1;
        }
        return 0;
    }

    int Config::writeYaml()
    {
        try
        {
            std::ofstream of(strConfigYamlPath_);
            of << config_;
            of.close();
        }
        catch (...) //捕获所有异常
        {
            printf("yaml文件不存在\n");
            return -1;
        }
        return 0;
    }

    std::string Config::getStringValue(const char *pszKey, const YAML::Node *pConfig/*=nullptr*/) const
    {
        if(nullptr == pConfig)
        {
            pConfig = &config_;
        }
        if (!(*pConfig)[pszKey].IsDefined())
        {
            printf("key:[%s] not exist!\n", pszKey);
        }
        return (*pConfig)[pszKey].as<std::string>();
    }

    int Config::getIntValue(const char *pszKey, const YAML::Node *pConfig/*=nullptr*/) const
    {
        if (nullptr == pConfig)
        {
            pConfig = &config_;
        }
        if (!(*pConfig)[pszKey].IsDefined())
        {
            printf("key:[%s] not exist!\n", pszKey);
        }
        return (*pConfig)[pszKey].as<int>();
    }

    bool Config::getBoolValue(const char *pszKey, const YAML::Node *pConfig/*=nullptr*/) const
    {
        if (nullptr == pConfig)
        {
            pConfig = &config_;
        }
        if (!(*pConfig)[pszKey].IsDefined())
        {
            printf("key:[%s] not exist!\n", pszKey);
        }
        return (*pConfig)[pszKey].as<bool>();
    }

    float Config::getFloatValue(const char *pszKey, const YAML::Node *pConfig/*=nullptr*/) const
    {
        if (nullptr == pConfig)
        {
            pConfig = &config_;
        }
        if (!(*pConfig)[pszKey].IsDefined())
        {
            printf("key:[%s] not exist!\n", pszKey);
        }
        return (*pConfig)[pszKey].as<float>();
    }

    std::string Config::getPathValue(const char *pszKey, const YAML::Node *pConfig /*=nullptr*/) const
    {
        if (nullptr == pConfig)
        {
            pConfig = &config_;
        }
        if (!(*pConfig)[pszKey].IsDefined())
        {
            printf("key:[%s] not exist!\n", pszKey);
        }
        std::string strTmp = (*pConfig)[pszKey].as<std::string>();
        if (strTmp.back() != '/')
        {
            strTmp += "/";
        }
        return strTmp;
    }

    RunConfig Config::getRunConfig() const
    {
        return this->runConfig_;
    }

    void Config::setRunConfig(const ai_matrix::RunConfig runConfig)
    {
        this->runConfig_ = runConfig;
    }

    BaseConfig Config::getBaseConfig() const
    {
        return this->baseConfig_;
    }

    void Config::setBaseConfig(const BaseConfig baseConfig)
    {
        this->baseConfig_ = baseConfig;
    }

    LogConfig Config::getLogConfig() const
    {
        return this->logConfig_;
    }

    void Config::setLogConfig(const LogConfig logConfig)
    {
        this->logConfig_ = logConfig;
    }

    std::vector<DataSourceConfig> Config::getAllDataSourceConfig() const
    {
        return this->vecDataSourceConfig_;
    }

    void Config::setDataSourceConfig(int index, const ai_matrix::DataSourceConfig dataSourceConfig)
    {
        if (this->vecDataSourceConfig_.size() <= index) return;
        this->vecDataSourceConfig_[index] = dataSourceConfig;
    }

    IdentifyConfig Config::getIdentifyConfig() const
    {
        return this->identifyConfig_;
    }

    void Config::setIdentifyConfig(const ai_matrix::IdentifyConfig identifyConfig)
    {
        this->identifyConfig_ = identifyConfig;
    }

    WSocketConfig Config::getWSocketConfig() const
    {
        return this->wSocketConfig_;
    }

    void Config::setWSocketConfig(const ai_matrix::WSocketConfig wSocketConfig)
    {
        this->wSocketConfig_ = wSocketConfig;
    }

    HttpServerConfig Config::getHttpServerConfig() const
    {
        return this->httpServerConfig_;
    }

    void Config::setHttpServerConfig(const HttpServerConfig httpServerConfig)
    {
        this->httpServerConfig_ = httpServerConfig;
    }

    MinioConfig Config::getMinioConfig() const
    {
        return this->minioConfig_;
    }

    void Config::setMinioConfig(const ai_matrix::MinioConfig minioCConfig)
    {
        this->minioConfig_ = minioCConfig;
    }

    ModelConfig Config::getModelByContainerStep1Config() const
    {
        return this->modelConfig_containerStep1_;
    }

    void Config::setModelByContainerStep1Config(const ai_matrix::ModelConfig modelConfig)
    {
        this->modelConfig_containerStep1_ = modelConfig;
    }

    ModelConfig Config::getModelByContainerStep2Config() const
    {
        return this->modelConfig_containerStep2_;
    }

    void Config::setModelByContainerStep2Config(const ai_matrix::ModelConfig modelConfig)
    {
        this->modelConfig_containerStep2_ = modelConfig;
    }

    ModelConfig Config::getModelByCornerConfig() const
    {
        return this->modelConfig_corner_;
    }

    void Config::setModelByCornerConfig(const ai_matrix::ModelConfig modelConfig)
    {
        this->modelConfig_corner_ = modelConfig;
    }
}
