#include "TransTrainEngine.h"
#include "myutils.h"
#include <regex>
#include <deque>

using namespace ai_matrix;

namespace
{
    //按照x坐标排列
    bool CompareX(const SingleData &v1, const SingleData &v2)
    {
        return (v1.fLTX < v2.fLTX);
    }

    //自定义比较规则
    bool CmpVec(const pair<string, uint32_t> &P1, const pair<string, uint32_t> &P2)
    {
        return P1.second < P2.second;
    }
}

TransTrainEngine::TransTrainEngine() {}

TransTrainEngine::~TransTrainEngine() {}

APP_ERROR TransTrainEngine::Init()
{
    bUseEngine_ = MyUtils::getins()->ChkIsHaveTarget("NUM");
    if (!bUseEngine_)
    {
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    modelConfig_ = MyYaml::GetIns()->GetModelConfig("TrainStepTwoEngine");
    strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path");

    //读取模型参数信息文件
    Json::Value jvModelInfo;
    if (!MyUtils::getins()->ReadJsonInfo(jvModelInfo, modelConfig_.strModelInfoPath))
    {
        LogError << "ModelInfoPath:" << modelConfig_.strModelInfoPath << " doesn't exist or read failed!";
        return APP_ERR_COMM_NO_EXIST;
    }
    for (int i = 0; i < jvModelInfo["class"].size(); i++)
    {
        vecClassNames_.push_back(jvModelInfo["class"][i].asString());
    }

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

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

APP_ERROR TransTrainEngine::DeInit()
{
    if (!bUseEngine_)
    {
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }
    LogInfo << "TransTrainEngine DeInit ok";
    return APP_ERR_OK;
}

/**
* 初始化参数信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void TransTrainEngine::InitParam()
{
    for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
    {
        iter->second = false;
    }
    mapNumInfo_.clear();
    mapPreFrameId_.clear();
}

/**
 * 校验车型是否符合验证
 * inParam : int classId                    大框类别id
 *         : const std::string &trainNum    车型字符信息
 * outParam: N/A
 * return  : true:符合; false:不符合
 */
bool TransTrainEngine::AuthTransNum(int classId, const std::string &trainNum)
{
//    LogInfo << "classId:" << classId << " trainNum:" << trainNum;
    switch (classId)
    {
        case TRAIN_HEAD: // 车头上的编号
            break;
        case K_TRAIN_NUM: // 编号 矿车、煤炭漏斗车（兖矿自备、枣矿自备）
        {
            if (trainNum == "K13" || trainNum == "KM100AH")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 4:
                    reg = "^K[1FMZ]{1}[36789]{1}[018ABKNT]{1}";
                    break;
                case 5:
                    reg = "^K[1M]{1}[368]{1}[1ABDN]{1}[AGKNT]{1}";
                    break;
                case 6:
                    reg = "^K[MF]{1}[69]{1}[80]{1}A[KH]{1}";
                    break;
                default:
                    LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        case C_TRAIN_NUM:  // 敞车 特殊车型 C5D CF CFK
        {
            if (trainNum == "CF" || trainNum == "C62A(N)")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 3:
                    reg = "^C[15678F]{1}[0123456DK]{1}";
                    break;
                case 4:
                    reg = "^C[1678]{1}[012346]{1}[0ABCEFHKMTY]{1}";
                    break;
                case 5:
                    reg = "^C[1678]{1}[01246]{1}[0ABCEY]{1}[KAFHNT]{1}";
                    break;
                case 6:
                    reg = "^C[17]{1}0[0E]{1}[A-]{1}[AH]{1}";
                    break;
                default:
                    LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        case P_TRAIN_NUM:  // 编号 棚车
        {
            if (trainNum == "P70(H)" || trainNum == "P62(N)")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 3:
                    reg = "^P[1678]{1}[012345]{1}";
                    break;
                case 4:
                    reg = "^P[678]{1}[023456]{1}[ABHKNST]{1}";
                    break;
                case 5:
                    reg = "^P6[24]{1}[ANG]{1}[KT]{1}";
                    break;
                default:
                    LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        case G_TRAIN_NUM:  // 编号 罐车
        {
            if (trainNum == "GY100SK")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 2:
                    reg = "^G[HLS]{1}";
                    break;
                case 3:
                    reg = "^[GL]{1}[1567HL]{1}[01246789K]{1}";
                    break;
                case 4:
                    reg = "^[GU]{1}[167FJLNQSWY]{1}[170689]{1}[KSABDGTM075W]{1}";
                    break;
                case 5:
                    reg = "^[GU]{1}[17FHNQY6]{1}[1706A89]{1}[SBDAM057W]{1}[KEHTB0ZAS]{1}";
                    break;
                case 6:
                    reg = "^[UG]{1}[6YH]{1}[1489A]{1}[057W]{1}[Z0LSA]{1}[KSAT]{1}";
                    break;
                default:
                    LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        case NX_TRAIN_NUM:  // 编号 平车
        {
            if (trainNum == "N6")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 3:
                    reg = "^[NQX]{1}[1234678T]{1}[0124567HK]{1}";
                    break;
                case 4:
                    reg = "^[BNX]{1}[16X]{1}[17BC]{1}[07AGKT]{1}";
                    break;
                case 5:
                    reg = "^[NX]{1}[16NX]{1}[17C]{1}[07AGT]{1}[KTABH]{1}";
                    break;
                case 6:
                    reg = "^NX17[AB]{1}[KTH]{1}";
                    break;
                default:
                    LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        case J_TRAIN_NUM:  // 编号 牲畜车 特种车
        {
            if (trainNum == "TP64GK")
            {
                return true;
            }
            std::regex reg;
            switch (trainNum.size())
            {
                case 2:
                    reg = "^[DT]{1}[2678]{1}";
                    break;
                case 3:
                    reg = "^[DST]{1}[12346789LQ]{1}[012578ADFGP]{1}";
                    break;
                case 4:
                    reg = "^[DJNT]{1}[12356AFKQS]{1}[012345678DFQS]{1}[A12345679GHKQ]{1}";
                    break;
                case 5:
                    reg = "^[DJQT]{1}[2KNSH1P]{1}[613XQ2]{1}[A761234B]{1}[KA70G]{1}";
                    break;
                default:
                    LogWarn << "Unknow train， classId: " << classId << " trainNum:" << trainNum;
                    return false;
            }
            return std::regex_match(trainNum, reg);
        }
        default:
            LogWarn << "Unknow train，classId:" << classId << " trainNum:" << trainNum;
            return false;
    }
    return true;
}

/**
* 过滤第二步字段代号的误识别
* inParam : std::vector<SingleData> &vecObjs
*         : TargetMaxLen iMaxLen
* outParam: N/A
* return  : N/A
*/
void TransTrainEngine::FilterSingleData(std::vector<SingleData> &vecObjs, TargetMaxLen iMaxLen)
{
    /*误识别场景
    例： 车厢容积属性只有2位时，但因误识别导致自重的某个字符字段代号错误，划归到容积中，这样实际只有2位的容积变为3位。导致选优时错误。
    只处理1个字段代号的误识别，若有多个字段代号同时错误，无法区分哪些字符字段代号是正确的。(字段代号误识别较多时，则增强模型训练)

    排除一个最大和最小值后计算平局坐标值，每个框左上角和平局值左上角高度差大于平局值的高度则剔除.
    */
    if (vecObjs.size() != iMaxLen || vecObjs.size() <= 2)
    {
        return;
    }

    std::deque<SingleData> dqObjs(vecObjs.begin(), vecObjs.end());
    std::sort(dqObjs.begin(), dqObjs.end(), [](SingleData &a, SingleData &b)
    {
        return a.fLTY < b.fLTY;
    });
    dqObjs.pop_front();
    dqObjs.pop_back();

    SingleData singleDataAvg;
    for (auto iter = dqObjs.begin(); iter != dqObjs.end(); iter++)
    {
        singleDataAvg.fLTX += iter->fLTX;
        singleDataAvg.fLTY += iter->fLTY;
        singleDataAvg.fRBX += iter->fRBX;
        singleDataAvg.fRBY += iter->fRBY;
    }
    singleDataAvg.fLTX = singleDataAvg.fLTX / dqObjs.size();
    singleDataAvg.fLTY = singleDataAvg.fLTY / dqObjs.size();
    singleDataAvg.fRBX = singleDataAvg.fRBX / dqObjs.size();
    singleDataAvg.fRBY = singleDataAvg.fRBY / dqObjs.size();
    float fAvgHeight = singleDataAvg.fRBY - singleDataAvg.fLTY;

    //剔除位置错误的字符信息
    for (auto iter = vecObjs.begin(); iter != vecObjs.end(); iter++)
    {
        float fTemp = fabs(iter->fLTY - singleDataAvg.fLTY);
        if (fTemp > (fAvgHeight - 5))
        {
            std::string strOne = vecClassNames_.at(iter->iClassId);
            LogWarn << "engineId:" << engineId_ << " " << strOne << " Line wrong ";
            vecObjs.erase(iter);
            break;
        }
    }
}

/**
* 属性框内容转换
* inParam : std::map<int, std::vector<SingleData>> &mapLine
* outParam: TransSubData &transSubData
* return  : N/A
*/
void TransTrainEngine::TransPro(TransSubData &transSubData, std::map<int, std::vector<SingleData>> &mapLine)
{
    //载重
    if (mapLine.find(0) != mapLine.end())
    {
        TransInfo loadInfo;
        loadInfo.iLine = 0;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(0).size(); j++)
        {
            //过滤非数字
            std::string strOne = vecClassNames_.at(mapLine.at(0).at(j).iClassId);
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in load";
                continue;
            }
            strTemp += strOne;
            loadInfo.vecValue.emplace_back(strOne);
            loadInfo.vecScore.emplace_back(mapLine.at(0).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(0).at(j).fScore;
        }

        //匹配正则表达式
        //std::regex reg("^[0-9]{2}");
        std::regex reg("^([4,5,6,7,8,9]{1}[0-9]{1}|[1]{1}[0-3]{1}[0-9]{1})$"); //(第1位：棚车:4 5; K自备车:1 5 7 8 9; 平车:7; 罐车:6 7; 敞车:6 7 8)
        if (std::regex_match(strTemp, reg))
        {
            loadInfo.IsChkFlag = true;
        }
        transSubData.vecTransInfo.emplace_back(loadInfo);
    }

    //自重
    if (mapLine.find(1) != mapLine.end())
    {
        FilterSingleData(mapLine.at(1), SELF_MAXLEN);
        TransInfo selfInfo;
        selfInfo.iLine = 1;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(1).size(); j++)
        {
            //过滤非数字
            std::string strOne = vecClassNames_.at(mapLine.at(1).at(j).iClassId);
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in self";
                continue;
            }
            strTemp += strOne;
            selfInfo.vecValue.emplace_back(strOne);
            selfInfo.vecScore.emplace_back(mapLine.at(1).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(1).at(j).fScore;
        }

        //匹配正则表达式
        std::regex reg("^[1,2,3]{1}[0-9]{1,2}$");
        if (std::regex_match(strTemp, reg))
        {
            selfInfo.IsChkFlag = true;
        }
        transSubData.vecTransInfo.emplace_back(selfInfo);
    }

    //容积
    if (mapLine.find(2) != mapLine.end())
    {
        FilterSingleData(mapLine.at(2), VOLUME_MAXLEN);
        TransInfo volumeInfo;
        volumeInfo.iLine = 2;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(2).size(); j++)
        {
            //过滤非数字
            std::string strOne = vecClassNames_.at(mapLine.at(2).at(j).iClassId);
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in volume";
                continue;
            }
            strTemp += strOne;
            volumeInfo.vecValue.emplace_back(strOne);
            volumeInfo.vecScore.emplace_back(mapLine.at(2).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(2).at(j).fScore;
        }

        //匹配正则表达式
        //std::regex reg("^[0-9]{2,3}$");
        std::regex reg("^[1,6,7,8,9]{1}[0-9]{1,2}$");  //(第1位：棚车:1; K自备车:1或9; 罐车:6或7; 敞车:7或8)
        if (std::regex_match(strTemp, reg))
        {
            volumeInfo.IsChkFlag = true;
        }
        transSubData.vecTransInfo.emplace_back(volumeInfo);
    }

    //换长
    if (mapLine.find(3) != mapLine.end())
    {
        TransInfo changeInfo;
        changeInfo.iLine = 3;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(3).size(); j++)
        {
            //过滤非数字
            std::string strOne = vecClassNames_.at(mapLine.at(3).at(j).iClassId);
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in change";
                continue;
            }
            strTemp += strOne;
            changeInfo.vecValue.emplace_back(strOne);
            changeInfo.vecScore.emplace_back(mapLine.at(3).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(3).at(j).fScore;
        }

        //匹配正则表达式
        //std::regex reg("^[0-9]{2}$");
        std::regex reg("^[1]{1}[0-9]{1}$");
        if (std::regex_match(strTemp, reg))
        {
            changeInfo.IsChkFlag = true;
        }
        transSubData.vecTransInfo.emplace_back(changeInfo);
    }

    //罐车容量计表
    if (mapLine.find(4) != mapLine.end())
    {
        TransInfo volumeSurfaceInfo;
        volumeSurfaceInfo.iLine = 4;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(4).size(); j++)
        {
            strTemp += vecClassNames_.at(mapLine.at(4).at(j).iClassId);
            volumeSurfaceInfo.vecValue.emplace_back(vecClassNames_.at(mapLine.at(4).at(j).iClassId));
            volumeSurfaceInfo.vecScore.emplace_back(mapLine.at(4).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(4).at(j).fScore;
        }

        volumeSurfaceInfo.IsChkFlag = true; //暂不校验
        transSubData.vecTransInfo.emplace_back(volumeSurfaceInfo);
    }
}

/**
* 车号框内容转换
* inParam : std::map<int, std::vector<SingleData>> &mapLine
* outParam: TransSubData &transSubData
* return  : N/A
*/
void TransTrainEngine::TransNum(TransSubData &transSubData, std::map<int, std::vector<SingleData>> &mapLine)
{
    //车型
    if (mapLine.find(0) != mapLine.end())
    {
        TransInfo typeInfo;
        typeInfo.iLine = 0;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(0).size(); j++)
        {
            std::string strOne = vecClassNames_.at(mapLine.at(0).at(j).iClassId);

            /*20230117 该逻辑删除，有厂区发现有C70C DF4DD等车型。 针对重复印刷的场景需想其他方法处理。
            //注：车型多次印刷会导致之前印刷的个别字符会识别，导致最终的识别内容变多。针对车型没有重复字符的特点，因此剔除重复的字符
            auto iter = find(typeInfo.vecValue.begin(), typeInfo.vecValue.end(), strOne);
            if (iter != typeInfo.vecValue.end())
            {
                LogWarn << "Possible duplicate recognition strOne:" << strOne;
                continue;
            }
            */

            strTemp += strOne;
            typeInfo.vecValue.emplace_back(strOne);
            typeInfo.vecScore.emplace_back(mapLine.at(0).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(0).at(j).fScore;
        }

        //校验车型是否符合验证
        typeInfo.IsChkFlag = AuthTransNum(transSubData.iBigClassId, strTemp);
        // LogInfo << "--->>>  符合正则吗？" << typeInfo.IsChkFlag << "  --- " << strTemp;

        transSubData.vecTransInfo.emplace_back(typeInfo);
    }

    //编号
    if (mapLine.find(1) != mapLine.end())
    {
        TransInfo numInfo;
        numInfo.iLine = 1;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(1).size(); j++)
        {
            std::string strOne = vecClassNames_.at(mapLine.at(1).at(j).iClassId);
            //过滤非数字
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in num";
                continue;
            }
            strTemp += strOne;
            numInfo.vecValue.emplace_back(strOne);
            numInfo.vecScore.emplace_back(mapLine.at(1).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(1).at(j).fScore;
        }

        //匹配正则表达式
        std::regex reg("^[0-9]{7}$"); //车厢编号，固定7位
        if (std::regex_match(strTemp, reg))
        {
            numInfo.IsChkFlag = true;
        }

        transSubData.vecTransInfo.emplace_back(numInfo);
    }
}

/**
* 车头框内容转换
* inParam : std::map<int, std::vector<SingleData>> &mapLine
* outParam: TransSubData &transSubData
* return  : N/A
*/
void TransTrainEngine::TransHead(TransSubData &transSubData, std::map<int, std::vector<SingleData>> &mapLine)
{
    //车头型号
    if (mapLine.find(0) != mapLine.end())
    {
        TransInfo typeInfo;
        typeInfo.iLine = 0;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(0).size(); j++)
        {
            strTemp += vecClassNames_.at(mapLine.at(0).at(j).iClassId);
            typeInfo.vecValue.emplace_back(vecClassNames_.at(mapLine.at(0).at(j).iClassId));
            typeInfo.vecScore.emplace_back(mapLine.at(0).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(0).at(j).fScore;
        }

        //不做结果校验，IsChkFlag默认为true
        typeInfo.IsChkFlag = true;
        transSubData.vecTransInfo.emplace_back(typeInfo);
    }

    //车头编号
    if (mapLine.find(1) != mapLine.end())
    {
        TransInfo numInfo;
        numInfo.iLine = 1;
        std::string strTemp = "";
        for (auto j = 0; j < mapLine.at(1).size(); j++)
        {
            std::string strOne = vecClassNames_.at(mapLine.at(1).at(j).iClassId);
            //过滤非数字
            if (strOne[0] < '0' || strOne[0] > '9')
            {
                LogWarn << "engineId:" << engineId_ << " " << strOne << " not digit in headnum";
                continue;
            }
            strTemp += strOne;
            numInfo.vecValue.emplace_back(strOne);
            numInfo.vecScore.emplace_back(mapLine.at(1).at(j).fScore);
            transSubData.fScoreSum += mapLine.at(1).at(j).fScore;
        }

        //不做结果校验，IsChkFlag默认为true
        numInfo.IsChkFlag = true;
        transSubData.vecTransInfo.emplace_back(numInfo);
    }
}


/**
* 记录在画面中间位置识别的车号
* inParam : const TransSubData &transSubData                    车号信息
          : const std::shared_ptr<ProcessData> &pProcessData    帧数据
* outParam: N/A
* return  : N/A
*/
void TransTrainEngine::RecordNum(const TransSubData &transSubData, const std::shared_ptr<ProcessData> &pProcessData)
{
    int iCenterX = transSubData.step1Location.fLTX + (transSubData.step1Location.fRBX - transSubData.step1Location.fLTX) / 2;
    int iImgL = pProcessData->iWidth / 3;
    int iImgR = pProcessData->iWidth / 3 * 2;
    if (iCenterX <= iImgL || iCenterX >= iImgR)
    {
        return;
    }

    std::string strValue;
    for (size_t i = 0; i < transSubData.vecTransInfo.size(); i++)
    {
        TransInfo transInfo = transSubData.vecTransInfo[i];
        if (transInfo.iLine != 1)
        {
            continue;
        }
        for (size_t j = 0; j < transInfo.vecValue.size(); j++)
        {
            strValue += transInfo.vecValue[j];
        }
    }

    bool bIntervalFlag = ((int)(pProcessData->iFrameId - mapPreFrameId_[pProcessData->iDataSource]) > iSkipInterval_ * 2);
    if (mapNumInfo_[pProcessData->iDataSource].find(strValue) == mapNumInfo_[pProcessData->iDataSource].end())
    {
        LogDebug << " frameid:" << pProcessData->iFrameId << " NUM:" << strValue
                 << " bIntervalFlag:" << bIntervalFlag;
        if (bIntervalFlag)
        {
            mapNumInfo_[pProcessData->iDataSource][strValue] = pProcessData->iFrameId;
        }
    }
    // LogDebug << " preframeid:" << mapPreFrameId_[pProcessData->iDataSource]
    //          << " frameid:" << pProcessData->iFrameId << " mapsize:" << mapNumInfo_[pProcessData->iDataSource].size();
    mapPreFrameId_[pProcessData->iDataSource] = pProcessData->iFrameId;
}

/**
* 保存中间位置识别车号信息到csv中
* inParam : std::shared_ptr<Train> pTrain   :列车信息
* outParam:
* return  : true/false
*/
bool TransTrainEngine::SaveMiddleNumCsv(const std::vector<pair<string, uint32_t>> &vecNums, const std::shared_ptr<ProcessData> &pProcessData,
                                        int iSourceId)
{
    //1. 创建保存路径 (固定路径/YYYY-MM-DD/hh-mm-ss/)
    std::string strTrainPath = strResultPath_ + pProcessData->strTrainDate + "/" + pProcessData->strTrainName + "/";
    if (!MyUtils::getins()->CreateDirPath(strTrainPath))
    {
        LogError << "fail CreateDirPath:" << strTrainPath;
        return false;
    }

    //2. 保存csv
    std::string strCsvName = pProcessData->strTrainDate + pProcessData->strTrainName + "_" + std::to_string(iSourceId) + ".csv";
    strCsvName = MyUtils::getins()->replace_all_distinct(strCsvName, std::string("-"), std::string(""));
    strTrainPath += strCsvName;

    try
    {
        // 写文件
        std::ofstream outFile;
        outFile.open(strTrainPath, std::ios::app);

        outFile << "num" << ',' << "frameid" << std::endl;

        for (auto iterVec = vecNums.begin(); iterVec != vecNums.end(); iterVec++)
        {
            outFile << iterVec->first << "," << iterVec->second << std::endl;
        }
        outFile.close();
    }
    catch (const std::exception &)
    {
        LogError << "fail open dirPath:" << strTrainPath;
        return false;
    }
    return true;
}

/**
* push数据到队列，队列满时则休眠一段时间再push
* inParam : const std::string strPort                           push的端口
          : const std::shared_ptr<ProcessData> &pProcessData    push的数据
* outParam: N/A
* return  : N/A
*/
void TransTrainEngine::PushData(const std::string &strPort, const std::shared_ptr<ProcessData> &pProcessData)
{
    while (true)
    {
        int iRet = outputQueMap_[strPort]->push(std::static_pointer_cast<void>(pProcessData));
        if (iRet != 0)
        {
            LogDebug << "sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " push fail iRet:" << iRet;
            if (iRet == 2)
            {
                usleep(10000); // 10ms
                continue;
            }
        }
        break;
    }
}

APP_ERROR TransTrainEngine::Process()
{
    if (!bUseEngine_)
    {
        LogWarn << "engineId_:" << engineId_ << " not use engine";
        return APP_ERR_OK;
    }

    int iRet = APP_ERR_OK;
    while (!isStop_)
    {
        std::shared_ptr<void> pVoidData0 = nullptr;
        inputQueMap_[strPort0_]->pop(pVoidData0);
        if (nullptr == pVoidData0)
        {
            usleep(1000); //1ms
            continue;
        }

        std::shared_ptr<ProcessData> pProcessData = std::static_pointer_cast<ProcessData>(pVoidData0);
        //第2步后处理结果
        std::shared_ptr<PostData> pPostData = std::static_pointer_cast<PostData>(pProcessData->pVoidData);

        //最后一节的最后一帧为整列车的结束
        if (pProcessData->bIsTrainEnd && pProcessData->bIsEnd)
        {
            mapDataSourceIsEnd_[pProcessData->iDataSource] = true;
        }

        //组织输出数据
        std::shared_ptr<TransData> pTransData = std::make_shared<TransData>();
        for (size_t i = 0; i < pPostData->vecPostSubData.size(); i++)
        {
            PostSubData postSubData = pPostData->vecPostSubData[i];

            //按字段代号分类
            std::map<int, std::vector<SingleData>> mapLine;
            for (size_t j = 0; j < postSubData.vecSingleData.size(); j++)
            {
                mapLine[postSubData.vecSingleData.at(j).iLine].push_back(postSubData.vecSingleData.at(j));
            }

            //每一行按x坐标排序
            for (auto it = mapLine.begin(); it != mapLine.end(); it++)
            {
                std::sort(it->second.begin(), it->second.end(), CompareX);

                std::string strTemp = "";
                for (auto j = 0; j < it->second.size(); j++)
                {
                    strTemp += vecClassNames_.at(it->second.at(j).iClassId);
                }
//                LogDebug << "step2 char sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId
//                         << " bigclassId:" << postSubData.iBigClassId << " line:" << it->first << "," << strTemp;
            }

            TransSubData transSubData;
            transSubData.iBigClassId = postSubData.iBigClassId;
            transSubData.iCarXH = postSubData.iCarXH;
            transSubData.step1Location = postSubData.step1Location;
            //按大类处理
            if(postSubData.iBigClassId == 1)
            {
                TransPro(transSubData, mapLine);
            }
            else if (postSubData.iBigClassId >= 2 && postSubData.iBigClassId <= 6)
            {
                TransNum(transSubData, mapLine);
                RecordNum(transSubData, pProcessData);
            }
            else if(postSubData.iBigClassId == 0)
            {
                TransHead(transSubData, mapLine);
                RecordNum(transSubData, pProcessData);
            }
            else
            {
                continue;
            }

            pTransData->vecTransSubData.emplace_back(transSubData);
        }

        //是否全部结束
        bool bAllEnd = true;
        for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
        {
            bAllEnd = bAllEnd && iter->second;
        }

        pProcessData->pVoidData = std::static_pointer_cast<void>(pTransData);
        // push端口0，车号属性选优处理
        PushData(strPort0_, pProcessData);

        if (bAllEnd)
        {
            for(auto iter = mapNumInfo_.begin(); iter != mapNumInfo_.end(); iter++)
            {
                std::vector<pair<string, uint32_t>> vecTemp(iter->second.begin(), iter->second.end());
                sort(vecTemp.begin(), vecTemp.end(), CmpVec); //按帧号排序
                SaveMiddleNumCsv(vecTemp, pProcessData, iter->first);

                // for(auto iterVec = vecTemp.begin(); iterVec != vecTemp.end(); iterVec++)
                // {
                //     LogDebug << "sourceid:" << iter->first << " num:" << iterVec->first << " frameid:" << iterVec->second;
                // }
            }
            //转个json数组发送后面用于比较。(车厢个数和该json数据是否相等，相等则不处理。不相等则挨个比较下。)

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

    return APP_ERR_OK;
}
