#include "SelectBestChkDateEngine.h"
#include "myutils.h"

using namespace ai_matrix;


SelectBestChkDateEngine::SelectBestChkDateEngine() {}

SelectBestChkDateEngine::~SelectBestChkDateEngine() {}

APP_ERROR SelectBestChkDateEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
    iSelectBestMode_ = MyYaml::GetIns()->GetIntValue("gc_select_best_mode");

    //获取几个摄像头识别定检期
    std::map<int, ai_matrix::DataSourceConfig> mapUseDataSouceCfg = MyYaml::GetIns()->GetUseDataSourceConfig();
    for (auto iter = mapUseDataSouceCfg.begin(); iter != mapUseDataSouceCfg.end(); iter++)
    {
        if (iter->second.strTarget.find("CHKDATE") != std::string::npos)
        {
            LogDebug << "DataSource:" << iter->first << " deal CHKDATE";
            mapDataSourceIsEnd_[iter->first] = false;
        }
    }

    InitParam();
    LogInfo << "SelectBestChkDateEngine Init ok";
    return APP_ERR_OK;
}

APP_ERROR SelectBestChkDateEngine::DeInit()
{
    LogInfo << "SelectBestChkDateEngine DeInit ok";
    return APP_ERR_OK;
}

/**
* 初始化定检期参数信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SelectBestChkDateEngine::InitChkDateParam()
{
    mapChkDateInfo_.clear();
    strBestChkDateImg_ = "";
    i64TimeStampChkDate_ = 0;
    fMaxScoreSumChkDate_ = 0;
    memset(&step1LocationBestChkDate_, 0, sizeof(step1LocationBestChkDate_));
    iDataSourceChkDate_ = 0;
}

/**
* 初始化参数信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SelectBestChkDateEngine::InitParam()
{
    iChkDateIndex_ = 1;
    InitChkDateParam();

    for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
    {
        iter->second = false;
    }
}

/**
* 获取最优长度
* inParam : std::vector<TransInfo> &vecAllTransInfo 待汇总取优的结果集
*         : TargetMaxLen iMaxLen                    目标最大长度  
* outParam: N/A
* return  : 最优长度
*/
int SelectBestChkDateEngine::GetBestLength(std::vector<TransInfo> &vecAllTransInfo, TargetMaxLen iMaxLen)
{
    //1.获取结果中每种长度出现的次数
    std::map<int, int> mapResultSize;
    for (size_t i = 0; i < vecAllTransInfo.size(); i++)
    {
        int iNowSize = vecAllTransInfo[i].vecValue.size();
        if (mapResultSize.find(iNowSize) != mapResultSize.end())
        {
            mapResultSize[iNowSize]++;
            continue;
        }
        mapResultSize[iNowSize] = 1;
    }

    int iBestLen = 0;
    //2.获取最优长度
    if (iSelectBestMode_ == FREQUENCY)
    {
        //2.1 按长度出现的频次最多，作为最优长度
        int iCnt = 0;
        for (auto it = mapResultSize.begin(); it != mapResultSize.end(); it++)
        {
            if (iCnt < it->second)
            {
                iCnt = it->second;
                iBestLen = it->first;
            }
        }
    }
    else if(iSelectBestMode_ == LENGTH)
    {
        //2.2 按最长长度且不能大于最大长度，作为最优长度
        for (auto rit = mapResultSize.rbegin(); rit != mapResultSize.rend(); rit++)
        {
            if (rit->first <= iMaxLen)
            {
                iBestLen = rit->first;
                break;
            }
        }
    }
    LogDebug << "iBestLen:" << iBestLen;
    return iBestLen;
}

/**
* 获取最优结果
* inParam : std::vector<TransInfo> &vecAllTransInfo 待汇总取优的结果集
*         : TargetMaxLen iMaxLen                    目标最大长度 
* outParam: N/A
* return  : 最优结果
*/
std::string SelectBestChkDateEngine::GetBest(std::vector<TransInfo> &vecAllTransInfo, TargetMaxLen iMaxLen)
{
    std::string strValue = "";
    if (vecAllTransInfo.size() <= 0)
    {
        return strValue;
    }

    //优先使用校验通过的数据选优。
    std::vector<TransInfo> vecTransInfoTemp;
    for (size_t i = 0; i < vecAllTransInfo.size(); i++)
    {
        TransInfo transInfo = vecAllTransInfo[i];
        if (transInfo.IsChkFlag)
        {
            vecTransInfoTemp.emplace_back(transInfo);
        }
    }
    if (vecTransInfoTemp.size() > 0)
    {
        vecAllTransInfo = vecTransInfoTemp;
    }

    //获取最优长度
    int iBestLen = GetBestLength(vecAllTransInfo, iMaxLen);

    //初始化最优结果
    TransInfo transInfoBest;
    transInfoBest.vecScore.reserve(iBestLen);
    transInfoBest.vecValue.reserve(iBestLen);
    for (int i = 0; i < iBestLen; i++)
    {
        transInfoBest.vecScore.emplace_back(0);
        transInfoBest.vecValue.emplace_back("");
    }

    std::map<std::string, int> mapResult; //符合最优长度的结果集 [key:结果; value:结果出现次数]
    for (size_t iIndex = 0; iIndex < vecAllTransInfo.size(); iIndex++)
    {
        if (vecAllTransInfo[iIndex].vecValue.size() != iBestLen)
        {
            continue;
        }

        std::string strValueTemp;
        for (int j = 0; j < iBestLen; j++)
        {
            strValueTemp += vecAllTransInfo[iIndex].vecValue[j];
            if (transInfoBest.vecScore[j] < vecAllTransInfo[iIndex].vecScore[j])
            {
                transInfoBest.vecScore[j] = vecAllTransInfo[iIndex].vecScore[j];
                transInfoBest.vecValue[j] = vecAllTransInfo[iIndex].vecValue[j];
            }
        }

        if (mapResult.find(strValueTemp) != mapResult.end())
        {
            mapResult[strValueTemp]++;
        }
        else
        {
            mapResult[strValueTemp] = 1;
        }
    }

    //按字符最高得分汇总结果
    for (size_t i = 0; i < transInfoBest.vecValue.size(); ++i)
    {
        strValue += transInfoBest.vecValue[i];
    }

    //按出现次数汇总结果
    int iMaxCnt = 0;
    std::string strValue2;
    for (auto iter = mapResult.begin(); iter != mapResult.end(); iter++)
    {
        if (iter->second > iMaxCnt)
        {
            iMaxCnt = iter->second;
            strValue2 = iter->first;
        }
    }

    //最高得分汇总和最高次数汇总不相等，且识别同一结果次数大于等于3次，则使用按次数汇总结果。
    if (strValue != strValue2)
    {
        LogWarn << "engineId:" << engineId_ << " value1:" << strValue << " value2:" << strValue2
                << " not equal value2cnt:" << iMaxCnt;
        if (iMaxCnt >= 3)
        {
            strValue = strValue2;
        }
    }

    return strValue;
}

/**
* 校验日期的合理性
* inParam : std::string &strDate    日期
* outParam: N/A
* return  : true/false
*/
bool SelectBestChkDateEngine::ChkValidDate(std::string &strDate)
{
    bool bChkFlag = false;
    //2010年~2040年
    if (strDate.length() >= 3)
    {
        if (atoi(strDate.substr(0, 2).c_str()) >= 10 && atoi(strDate.substr(0, 2).c_str()) <= 40)
        {
            // 1月~12月
            if (atoi(strDate.substr(2).c_str()) >= 1 && atoi(strDate.substr(2).c_str()) <= 12)
            {
                bChkFlag = true;
            }
        }
    }
    return bChkFlag;
}

/**
* 获取定检期截至日期
* inParam : std::string &strChkDate 定检期内容
* outParam: N/A
* return  : 定检期截至日期
*/
std::string SelectBestChkDateEngine::GetChkDateDeadLine(std::string &strChkDate)
{
    bool bFlag = false;
    std::string strDeadLine;
    if (strChkDate.length() >= 8)
    {
        //正常的yymmyymm
        bFlag = true;
        strDeadLine = strChkDate.substr(0, 4);
    }
    else if (strChkDate.length() == 7 || strChkDate.length() <= 5)
    {
        //yymyymm;  yymmyym;  8位少识别1位
        std::string strTemp1 = strChkDate.substr(0, 4);
        std::string strTemp2 = strChkDate.substr(0, 3);
        if (ChkValidDate(strTemp1))
        {
            strDeadLine = strTemp1;
            bFlag = true;
        }
        else if (ChkValidDate(strTemp2))
        {
            strDeadLine = strTemp2;
            bFlag = true;
        }
        else
        {
            strDeadLine = strTemp1;
        }
    }
    else if (strChkDate.length() == 6)
    {
        //yymyym;  8位少识别2位;  7位少识别1位
        std::string strTemp1 = strChkDate.substr(0, 3);
        std::string strTemp2 = strChkDate.substr(0, 4);
        if (ChkValidDate(strTemp1))
        {
            strDeadLine = strTemp1;
            bFlag = true;
        }
        else if (ChkValidDate(strTemp2))
        {
            strDeadLine = strTemp2;
            bFlag = true;
        }
        else
        {
            strDeadLine = strTemp1;
        }
    }
    else if (strChkDate.length() == 5)
    {
        //5位及5位以下按4位，3位截取； 同7位处理
    }

    if (strDeadLine.length() >= 3 && bFlag)
    {
        char szDeadLine[16] = {0};
        sprintf(szDeadLine, "%d-%02d", atoi(strDeadLine.substr(0, 2).c_str()), atoi(strDeadLine.substr(2).c_str()));
        return std::string(szDeadLine);
    }
    return strDeadLine;
}

/**
* 汇总单节车厢-定检期最佳值
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SelectBestChkDateEngine::GetChkDateBest(std::shared_ptr<ChkDate> pChkDate, std::shared_ptr<ProcessData> pProcessData)
{
    pChkDate->iDataSource = iDataSourceChkDate_;
    pChkDate->bIsEnd = pProcessData->bIsEnd;
    pChkDate->strTrainDate = pProcessData->strTrainDate;
    pChkDate->strTrainName = pProcessData->strTrainName;
    pChkDate->iCarXH = pProcessData->iTrainIndex;

    //定检期1(段修)
    if(mapChkDateInfo_.find(0) != mapChkDateInfo_.end())
    {
        pChkDate->strChkDate1 = GetBest(mapChkDateInfo_.at(0), CHKDATE_MAXLEN);
    }

    //定检期2(厂修)
    if (mapChkDateInfo_.find(1) != mapChkDateInfo_.end())
    {
        pChkDate->strChkDate2 = GetBest(mapChkDateInfo_.at(1), CHKDATE_MAXLEN);
    }
    
    pChkDate->strBestImg = strBestChkDateImg_;
    pChkDate->fScoreSum = fMaxScoreSumChkDate_;
    pChkDate->iCarXH = iChkDateIndex_++;
    pChkDate->step1Location = step1LocationBestChkDate_;
    pChkDate->i64TimeStamp = i64TimeStampChkDate_;
    pChkDate->strChkDate1DeadLine = GetChkDateDeadLine(pChkDate->strChkDate1);

    //初始化车号信息
    InitChkDateParam();
}

/**
* 定检期数据加入到待选优集合中
* inParam : std::shared_ptr<ProcessData> pProcessData           :处理帧数据
          : TransSubData &transSubData                          :转换后子数据
* outParam: N/A
* return  : N/A
*/
void SelectBestChkDateEngine::ChkDateAddSelectBestMap(std::shared_ptr<ProcessData> pProcessData, TransSubData &transSubData)
{
    for (size_t i = 0; i < transSubData.vecTransInfo.size(); i++)
    {
        TransInfo transInfo = transSubData.vecTransInfo[i];
        mapChkDateInfo_[transInfo.iLine].emplace_back(transInfo);
    }
    
    //最高分和最优帧号
    if (fMaxScoreSumChkDate_ < transSubData.fScoreSum)
    {
        fMaxScoreSumChkDate_ = transSubData.fScoreSum;
        strBestChkDateImg_ = std::to_string(pProcessData->iFrameId) + ".jpg";
        i64TimeStampChkDate_ = pProcessData->i64TimeStamp;
        step1LocationBestChkDate_ = transSubData.step1Location;
        iDataSourceChkDate_ = pProcessData->iDataSource;
    }
}

APP_ERROR SelectBestChkDateEngine::Process()
{
    int iRet = APP_ERR_OK;
    while (!isStop_)
    {
        //pop端口0
        std::shared_ptr<void> pVoidData0 = nullptr;
        iRet = inputQueMap_[strPort0_]->pop(pVoidData0);
        if (nullptr == pVoidData0)
        {
            usleep(1000);
            continue;
        }
        std::shared_ptr<ProcessData> pProcessData = std::static_pointer_cast<ProcessData>(pVoidData0);
        std::shared_ptr<TransData> pTransData = std::static_pointer_cast<TransData>(pProcessData->pVoidData);

        if (pProcessData->bIsEnd)
        {
            mapDataSourceIsEnd_[pProcessData->iDataSource] = pProcessData->bIsEnd;
        }

        for (size_t i = 0; i < pTransData->vecTransSubData.size(); i++)
        {
            TransSubData transSubData = pTransData->vecTransSubData[i];
			
            //定检期
            if (transSubData.iBigClassId == 7)
            {
                //定检期加入待汇总集合中
                ChkDateAddSelectBestMap(pProcessData, transSubData);
            }
        }

        // 3. 结束帧，需汇总
        bool bAllEnd = true;
        for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
        {
            bAllEnd = bAllEnd && iter->second;
        }
        //3. 结束帧，需汇总
        if (bAllEnd)
        {
            std::shared_ptr<ChkDate> pChkDate = std::make_shared<ChkDate>();
            GetChkDateBest(pChkDate, pProcessData);

            //push端口0
            outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pChkDate));
            outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pChkDate));

            //初始化参数变量
            InitParam();
        }
    }
    return APP_ERR_OK;
}
