#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_.bUpResult = config_["base"]["up_result"].as<bool>();
            this->baseConfig_.strLogPath = config_["base"]["log_path"].as<std::string>();
            this->baseConfig_.strResultPath = config_["base"]["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>();

            // 数据源参数
            this->dataSourceConfig_.strUrl = config_["data_source"]["url"].as<std::string>();
            this->dataSourceConfig_.iSkipInterval = config_["data_source"]["skip_interval"].as<int>();
            this->dataSourceConfig_.iDirection = config_["data_source"]["direction"].as<int>();
            this->dataSourceConfig_.iLeftFirst = config_["data_source"]["left_first"].as<int>();
            this->dataSourceConfig_.iRightFirst = config_["data_source"]["right_first"].as<int>();

            // 识别参数
            this->identifyConfig_.strRunModel = config_["identify"]["run_mode"].as<std::string>();
            this->identifyConfig_.bNeedMoveDetectFlag = config_["identify"]["need_move_detect_flag"].as<bool>();
            this->identifyConfig_.strIdentifyDirection = config_["identify"]["identify_direction"].as<std::string>();
            this->identifyConfig_.iPartitionFrameSpan = config_["identify"]["partition_frame_span"].as<int>();
            this->identifyConfig_.iSplitFrameSpanPx = config_["identify"]["split_frame_span_px"].as<int>();
            this->identifyConfig_.iChkstopPx = config_["identify"]["chkstop_px"].as<int>();
            this->identifyConfig_.iChkstopCount = config_["identify"]["chkstop_count"].as<int>();
            this->identifyConfig_.iNumFrameHeight = config_["identify"]["num_frame_height"].as<int>();
            this->identifyConfig_.iProFrameHeight = config_["identify"]["pro_frame_height"].as<int>();
            this->identifyConfig_.iSpaceFrameWidth = config_["identify"]["space_frame_width"].as<int>();
            this->identifyConfig_.bTrainHeardDetect = config_["identify"]["train_heard_detect"].as<bool>();

            // 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_.strUserName = config_["http_server"]["username"].as<std::string>();
            this->httpServerConfig_.strPassword = config_["http_server"]["password"].as<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;
    }

    DataSourceConfig Config::getDataSourceConfig() const
    {
        return this->dataSourceConfig_;
    }

    void Config::setDataSourceConfig(const ai_matrix::DataSourceConfig dataSourceConfig)
    {
        this->dataSourceConfig_ = 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;
    }
}
