#include "SaveStepOneResultEngine.h"


using namespace ai_matrix;

SaveStepOneResultEngine::SaveStepOneResultEngine() {}

SaveStepOneResultEngine::~SaveStepOneResultEngine() {}

APP_ERROR SaveStepOneResultEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
    strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path");
    iSplitSpan_ = MyYaml::GetIns()->GetIntValue("partition_frame_span");
    iSplitSpanPX_ = MyYaml::GetIns()->GetIntValue("gc_split_frame_span_px");

    dataSourceConfig_ = MyYaml::GetIns()->GetDataSourceConfigById(engineId_);

    std::map<int, ai_matrix::DataSourceConfig> mapUseDataSouceCfg = MyYaml::GetIns()->GetUseDataSourceConfig();
    std::string delimiter(",");
    for (auto iter = mapUseDataSouceCfg.begin(); iter != mapUseDataSouceCfg.end(); iter++)
    {
        int iCnt = 0;
        std::vector<std::string> vecSplit = MyUtils::getins()->split(iter->second.strTarget, delimiter);
        for (auto iter = vecSplit.begin(); iter != vecSplit.end(); iter++)
        {
            if (*iter == "NUM")
            {
                iCnt++;
            }
            else if (*iter == "CHKDATE")
            {
                iCnt++;
            }
            else if (*iter == "CONTAINER" || *iter == "CONTAINER_T")
            {
                iCnt++;
            }
        }
        mapInvokeModelCnt_[iter->first] = iCnt;
    }

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

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

/**
* 初始化参数信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SaveStepOneResultEngine::InitParam()
{
    iPushSpaceFrameId_ = 0;
    i64TimeStampFirst_ = 0;
    iDirection_ = DIRECTION_UNKNOWN;
    bPushIsEnd_ = false;
    vecParationInfo_.clear();
    std::vector<PartionInfo>().swap(vecParationInfo_);
    bDealCenterFlag_ = false;
    parationInfoLast_.i64EndTimeStamp = 0;
    parationInfoLast_.modelSpaceFrame = 0;
    parationInfoLast_.iRate = 0;
    parationInfoLast_.bmodelconfirmed = false;
    parationInfoLast_.fLTX = 0.0;
    parationInfoLast_.fRBX = 0.0;
    parationInfoLast_.strTrainDate = "";
    parationInfoLast_.strTrainName = "";
    parationInfoLast_.bIsEnd = false;
    parationInfoLast_.nStatus = 0;
    mapNumCenterInfo_.clear();
    mapProCenterInfo_.clear();
    bHaveHeadFlag_ = false;
    headInfo_.iFrameId = 0;
    headInfo_.fCenterX = 0;
}

/**
* 构造车厢间隔信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SaveStepOneResultEngine::MakeParationInfo(PartionInfo &parationInfo, std::shared_ptr<ProcessData> pProcessData, Json::Value &jvStep1Space)
{
    parationInfo.i64EndTimeStamp = pProcessData->i64TimeStamp;
    parationInfo.modelSpaceFrame = pProcessData->iFrameId;
    parationInfo.iRate = pProcessData->iRate;
    parationInfo.bmodelconfirmed = true;
    parationInfo.fLTX = jvStep1Space[0]["ltx"].asFloat();
    parationInfo.fRBX = jvStep1Space[0]["rbx"].asFloat();
    parationInfo.strTrainDate = pProcessData->strTrainDate;
    parationInfo.strTrainName = pProcessData->strTrainName;
    parationInfo.bIsEnd = pProcessData->bIsEnd;
    parationInfo.nStatus = ((pProcessData->iStatus == TRAINSTATUS_STOP) ? TRAIN_PAUSE : iDirection_);
    parationInfoLast_ = parationInfo;
}

/**
* 处理中心间隔信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SaveStepOneResultEngine::DealCenterSpace(std::vector<PartionInfo> &vecParationInfo,
                                              std::shared_ptr<ProcessData> pProcessData)
{
    int iVecSize = vecParationInfo.size();
    if (iVecSize < 0)
    {
        return;
    }
    LogDebug << "积累的车厢切分信息数:" << iVecSize << " 帧:" << pProcessData->iFrameId
             << " 第一个车厢切分信息帧:" << vecParationInfo.at(0).modelSpaceFrame
             << " 最后一个车厢切分信息帧:" << vecParationInfo.at(iVecSize - 1).modelSpaceFrame
             << " 最后一个车厢切分信息是否为结束:" << vecParationInfo.at(iVecSize - 1).bIsEnd;

    /*
    因停车后再行驶未能及时判断出为行驶状态，导致更新间隔信息，出现漏切分车厢(具体原因分析见正通2023-02-28的问题分析记录)
    漏切分时vecParationInfo中保存的是两辆车的间隔信息，因此针对vecParationInfo做特殊处理，从此处切分出遗漏的车厢。
    */
    std::vector<int> vecSpacePos;
    for (int i = 1; i < iVecSize; i++)
    {
        int iCenterXPre = vecParationInfo[i - 1].fLTX + (vecParationInfo[i - 1].fRBX - vecParationInfo[i - 1].fLTX) / 2;
        int iCenterX = vecParationInfo[i].fLTX + (vecParationInfo[i].fRBX - vecParationInfo[i].fLTX) / 2;
        bool bIntervalFlag = ((int)(vecParationInfo[i].modelSpaceFrame - vecParationInfo[i - 1].modelSpaceFrame)) > iSplitSpan_;
        LogDebug << "上一帧ID:" << vecParationInfo[i - 1].modelSpaceFrame << " 上一帧间隔X轴中线:" << iCenterXPre
                 << " 本帧ID:" << vecParationInfo[i].modelSpaceFrame << " 本帧间隔X轴中线:" << iCenterX
                 << " 满足帧间隔:" << bIntervalFlag << " i:" << i;
        if (iDirection_ == DIRECTION_LEFT && (iCenterXPre < iCenterX - iSplitSpanPX_) && bIntervalFlag)
        {
            vecSpacePos.push_back(i - 1);
        }
        if (iDirection_ == DIRECTION_RIGHT && (iCenterXPre - iSplitSpanPX_ > iCenterX) && bIntervalFlag)
        {
            vecSpacePos.push_back(i - 1);
        }
    }
    LogDebug << "vecSpacePos size:" << vecSpacePos.size();
    vecSpacePos.push_back(iVecSize - 1);

    /*
    如果集合中最后为列车结束帧，则表示停车在车厢间隔。这时用最后一个作为车厢划分帧。
    其他场景使用靠近中心的间隔帧作为车厢划分帧
    */
    for (int iSpacePos = 0; iSpacePos < vecSpacePos.size(); iSpacePos++)
    {
        LogDebug << "index:" << vecSpacePos.at(iSpacePos) << " frameid:" << vecParationInfo[vecSpacePos.at(iSpacePos)].modelSpaceFrame;
        std::shared_ptr<PartionInfo> pPartionInfo = std::make_shared<PartionInfo>();
        if (iSpacePos == vecSpacePos.size() - 1 && vecParationInfo[vecSpacePos.at(iSpacePos)].bIsEnd)
        {
            *pPartionInfo = vecParationInfo[vecSpacePos.at(iSpacePos)];
        }
        else
        {
            int iPos = 0;
            int iImageCenter = pProcessData->iWidth / 2;
            int iToCenterXMin = iImageCenter;
            int iBegin = (iSpacePos == 0 ? 0 : vecSpacePos.at(iSpacePos - 1) + 1);
            for (int i = iBegin; i <= vecSpacePos.at(iSpacePos); i++)
            {
                int iCenterX = vecParationInfo[i].fLTX + (vecParationInfo[i].fRBX - vecParationInfo[i].fLTX) / 2;
                if (iToCenterXMin > abs(iCenterX - iImageCenter))
                {
                    iToCenterXMin = abs(iCenterX - iImageCenter);
                    iPos = i;
                }
            }
            *pPartionInfo = vecParationInfo[iPos];
        }

        //此处切分时，依据车号，属性判断是否有漏的车厢，如果有则依靠车号属性切分。
        SplitTrainByNumPro(pPartionInfo, pProcessData);

        pPartionInfo->fLTX = pPartionInfo->fLTX / (pProcessData->iWidth / METHOD_BASE_WIDTH);
        pPartionInfo->fRBX = pPartionInfo->fRBX / (pProcessData->iWidth / METHOD_BASE_WIDTH);
        if (iPushSpaceFrameId_ == 0)
        {
            pPartionInfo->i64StartTimeStamp = i64TimeStampFirst_;
            pPartionInfo->startframe = dataSourceConfig_.iSkipInterval;
        }
        pPartionInfo->nStatus = ((pProcessData->iStatus == TRAINSTATUS_STOP) ? TRAIN_PAUSE : iDirection_);

        LogWarn << "--------- 向Paration 发送数据 --------";
        outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pPartionInfo));

        iPushSpaceFrameId_ = pPartionInfo->modelSpaceFrame;
        bPushIsEnd_ = pPartionInfo->bIsEnd;
        LogDebug << "pushSpaceFrameId:" << iPushSpaceFrameId_ << " timeStamp:" << pPartionInfo->i64EndTimeStamp
                 << " ltx:" << pPartionInfo->fLTX << " rbx:" << pPartionInfo->fRBX
                 << " bPushIsEnd:" << bPushIsEnd_;
    }
    vecParationInfo.clear();
}

/**
* 处理车厢间隔
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SaveStepOneResultEngine::DealTrainSpaceInfo(std::shared_ptr<ProcessData> pProcessData, Json::Value &jvStep1Space)
{
    /*
    无方向时，识别的内容都放入集合中。
    有向时，按方向判断是否push车厢间隔框
        向左行驶：帧间隔中心点小于画面1/3时，则处理车厢间隔集合。新车厢间隔必须大于上次车厢中心点再放入集合等待处理。
        向右行驶：帧间隔中心点大于画面2/3时，则处理车厢间隔集合。新车厢间隔必须小于上次车厢中心点再放入集合等待处理。
        注：最后一节不会再有帧间隔了，因此直接发送的结束帧，且坐标设置中心点。
    */
    if (jvStep1Space.size() <= 0 || pProcessData->iOrigFrameId < 50)
    {
        return;
    }

    /*
    停车状态后不再放入信息到集合中，防止长时间停在间隔上导致集合持续增大。
    停车状态且有间隔时需更新最后间隔框帧号。(防止在XXX帧停车且有间隔框，然后开始倒车再正向行驶，当再回到开始倒车的位置时，此时帧号为YYYY，
    会符合下面的partition_frame_span判断，导致bIntervalFlag为true而切分车厢)
    */
    if (pProcessData->iStatus == TRAINSTATUS_STOP && !pProcessData->bIsEnd)
    {
        // LogDebug << "status_stop parationInfoLast_:" << parationInfoLast_.modelSpaceFrame << " update by frameId:" << pProcessData->iFrameId;
        parationInfoLast_.i64EndTimeStamp = pProcessData->i64TimeStamp;
        parationInfoLast_.modelSpaceFrame = pProcessData->iFrameId;
        return;
    }

    if (iDirection_ == DIRECTION_UNKNOWN)
    {
        std::string strFilePath = strResultPath_ + pProcessData->strTrainDate + "/" + pProcessData->strTrainName + "/" + "direction.txt";
        Json::Value jvDirectionInfo;
        if (MyUtils::getins()->ReadJsonInfo(jvDirectionInfo, strFilePath))
        {
            iDirection_ = jvDirectionInfo["direction"].asInt();
        }
        else
        {
            LogWarn << "暂未检测出行车方向";
        }
    }

    bool bIntervalFlag = ((int)(pProcessData->iFrameId - parationInfoLast_.modelSpaceFrame)) > iSplitSpan_;
    int iCenterCur = jvStep1Space[0]["ltx"].asFloat() + (jvStep1Space[0]["rbx"].asFloat() - jvStep1Space[0]["ltx"].asFloat()) / 2;
    int iCenterLast = parationInfoLast_.fLTX + (parationInfoLast_.fRBX - parationInfoLast_.fLTX) / 2;
    LogDebug << "当前帧:" << pProcessData->iFrameId << " 间隔框中心线:" << iCenterCur
             << " 上一帧:" << parationInfoLast_.modelSpaceFrame << " 间隔框中心线:" << iCenterLast
             << " 行车方向:" << iDirection_ << " 是否满足切分帧数:" << bIntervalFlag << " bDealCenterFlag_:" << bDealCenterFlag_;

    if (iDirection_ == DIRECTION_UNKNOWN || iCenterLast == 0)
    {
        PartionInfo parationInfo;
        MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
        vecParationInfo_.push_back(parationInfo);
    }
    else if (iDirection_ == DIRECTION_LEFT)
    {
        if (iCenterCur < (pProcessData->iWidth / 3))
        {
            if (!bDealCenterFlag_)
            {
                PartionInfo parationInfo;
                MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
                vecParationInfo_.push_back(parationInfo);
                DealCenterSpace(vecParationInfo_, pProcessData);
                bDealCenterFlag_ = true;
            }
            //这需要替换parationInfoLast_, 确保parationInfoLast_是最靠左的一个间隔，但不需要加入集合
            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
        }
        else if ((iCenterLast < iCenterCur - iSplitSpanPX_) && bIntervalFlag)  //该条件只会在新车间隔出来进入一次
        {
            //防止上节车厢间隔框所有识别都大于画面的1/3，因此当前车厢间隔出来后也需处理下上节车厢间隔
            if (!bDealCenterFlag_ && vecParationInfo_.size() > 0)
            {
                LogDebug << "lastFrameid:" << vecParationInfo_[0].modelSpaceFrame << " frameid:" << pProcessData->iFrameId;
                DealCenterSpace(vecParationInfo_, pProcessData);
            }

            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
            vecParationInfo_.push_back(parationInfo);
            bDealCenterFlag_ = false;
        }
        else
        {
            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
            //该条件是防止第一个XXX帧满足小于画面1/3后切割，后一帧XXX+1的中心点大于画面1/3导致的加入vec中出现的多切分现象。(向右增加30px的浮动，因为大框可能不是同一种)
            if (!(bDealCenterFlag_ && !bIntervalFlag && (iCenterCur < (pProcessData->iWidth / 3 + 80))))
            {
                vecParationInfo_.push_back(parationInfo);
            }
        }
    }
    else if (iDirection_ == DIRECTION_RIGHT)
    {
        if (iCenterCur > (pProcessData->iWidth / 3 * 2))
        {
            if (!bDealCenterFlag_)
            {
                PartionInfo parationInfo;
                MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
                vecParationInfo_.push_back(parationInfo);
                DealCenterSpace(vecParationInfo_, pProcessData);
                bDealCenterFlag_ = true;
            }

            //这需要替换parationInfoLast_, 确保parationInfoLast_是最靠右的一个间隔，但不需要加入集合
            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
        }
        else if ((iCenterLast - iSplitSpanPX_ > iCenterCur) && bIntervalFlag) //该条件只会在新车间隔出来进入一次
        {
            //防止上节车厢间隔所有识别框都小于画面的2/3，因此当前车厢间隔出来后也需处理下上节车厢间隔
            if (!bDealCenterFlag_ && vecParationInfo_.size() > 0)
            {
                LogDebug << "lastFrameid:" << vecParationInfo_[0].modelSpaceFrame << " frameid:" << pProcessData->iFrameId;
                DealCenterSpace(vecParationInfo_, pProcessData);
            }

            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
            vecParationInfo_.push_back(parationInfo);
            bDealCenterFlag_ = false;
        }
        else
        {
            PartionInfo parationInfo;
            MakeParationInfo(parationInfo, pProcessData, jvStep1Space);
            //该条件是防止第一个XXX帧满足大于画面2/3后切割，后一帧XXX+1的中心点小于画面2/3导致的加入vec中出现的多切分现象。(向左增加80px的浮动因为大框可能不是同一种)
            if (!(bDealCenterFlag_ && !bIntervalFlag && (iCenterCur > (pProcessData->iWidth / 3 * 2 - 80))))
            {
                vecParationInfo_.push_back(parationInfo);
            }
        }
    }
}

void SaveStepOneResultEngine::SplitTrainByNumPro(std::shared_ptr<PartionInfo> &pPartionInfo, std::shared_ptr<ProcessData> &pProcessData)
{
    //向左行驶用车号位置，向右行驶用属性位置。
    std::map<uint32_t, float> *pMapCenterInfoTemp_ = nullptr;
    if (iDirection_ == DIRECTION_LEFT)
    {
        pMapCenterInfoTemp_ = &mapNumCenterInfo_;
        mapProCenterInfo_.clear();
    }
    else if (iDirection_ == DIRECTION_RIGHT)
    {
        pMapCenterInfoTemp_ = &mapProCenterInfo_;
        mapNumCenterInfo_.clear();
    }

    if (pMapCenterInfoTemp_ == nullptr || pMapCenterInfoTemp_->size() <= 0)
    {
        return;
    }

    LogDebug << "pPartionInfo->modelSpaceFrame:" << pPartionInfo->modelSpaceFrame << " mapsize:" << pMapCenterInfoTemp_->size();
    auto iter = pMapCenterInfoTemp_->begin();
    int iCenterXPre = iter->second;
    uint32_t iFrameIdPre = iter->first;
    bool bFlag = false;
    uint32_t iSplitFrameId = 0;
    while (++iter != pMapCenterInfoTemp_->end())
    {
        bool bIntervalFlag = (int)(iter->first - iFrameIdPre) > iSplitSpan_;
        LogDebug << "iFrameIdPre:" << iFrameIdPre << " iCenterXPre:" << iCenterXPre
                 << " iFrameid:" << iter->first << " iCenter:" << iter->second << " bIntervalFlag:" << bIntervalFlag;
        if (iDirection_ == DIRECTION_LEFT && (iCenterXPre < iter->second - iSplitSpanPX_) && bIntervalFlag)
        {
            iSplitFrameId = iter->first;
            bFlag = true;
        }
        if (iDirection_ == DIRECTION_RIGHT && (iCenterXPre - iSplitSpanPX_ > iter->second) && bIntervalFlag)
        {
            iSplitFrameId = iter->first;
            //iSplitFrameId = iFrameIdPre;    //向右行驶，从车号行驶到最右侧开始切分。
            bFlag = true;
        }

        //比较完后，可更新前一帧数据
        iCenterXPre = iter->second;
        iFrameIdPre = iter->first;

        if(bFlag)
        {
            if (iDirection_ == DIRECTION_LEFT && iter->second < (pProcessData->iWidth / 3))
            {
                bFlag = false;
            }
            else if (iDirection_ == DIRECTION_RIGHT && iter->second > (pProcessData->iWidth / 3 * 2))
            {
                bFlag = false;
            }
            if (!bFlag)
            {
                PartionInfo parationInfo;
                std::shared_ptr<PartionInfo> pPartionInfoNew = std::make_shared<PartionInfo>();
                // pPartionInfoNew->i64EndTimeStamp = pProcessData->i64TimeStamp;
                pPartionInfoNew->modelSpaceFrame = iSplitFrameId;
                // parationInfo.iRate = pProcessData->iRate;
                pPartionInfoNew->bmodelconfirmed = false;
                // pPartionInfoNew->fLTX = jvStep1Space[0]["ltx"].asFloat();
                // pPartionInfoNew->fRBX = jvStep1Space[0]["rbx"].asFloat();
                pPartionInfoNew->strTrainDate = pProcessData->strTrainDate;
                pPartionInfoNew->strTrainName = pProcessData->strTrainName;
                pPartionInfoNew->bIsEnd = false; //**通过该函数切分的肯定不是最后一节
                pPartionInfoNew->nStatus = ((pProcessData->iStatus == TRAINSTATUS_STOP) ? TRAIN_PAUSE : iDirection_);
                if (iPushSpaceFrameId_ == 0)
                {
                    pPartionInfoNew->i64StartTimeStamp = i64TimeStampFirst_;
                    pPartionInfoNew->startframe = dataSourceConfig_.iSkipInterval;
                }
//                pPartionInfoNew->nStatus = ((pProcessData->iStatus == TRAINSTATUS_STOP) ? TRAIN_PAUSE : iDirection_);

                //构造一个间隔信息写入到切分帧中
                char szCameraNo[5] = {0};
                sprintf(szCameraNo, "%03d/", pProcessData->iDataSource + 1);
                std::string strFilePath;
                strFilePath = strResultPath_ + pProcessData->strOrigTrainDate + "/" + pProcessData->strOrigTrainName + "/" +
                              szCameraNo + std::to_string(iSplitFrameId) + ".txt";
                Json::Value jvFrameInfo;
                MyUtils::getins()->ReadJsonInfo(jvFrameInfo, strFilePath);
                Json::Value jvOneSpace;
                jvOneSpace["classid"] = 18;
                jvOneSpace["ltx"] = pMapCenterInfoTemp_->at(iSplitFrameId) + (iDirection_ == DIRECTION_LEFT ? -50 : 50);
                jvOneSpace["lty"] = 0;
                jvOneSpace["rbx"] = pMapCenterInfoTemp_->at(iSplitFrameId) + (iDirection_ == DIRECTION_LEFT ? -50 : 50);
                jvOneSpace["rby"] = 0;
                jvFrameInfo["step1Space"].append(jvOneSpace);
                MyUtils::getins()->WriteJsonInfo(jvFrameInfo, strFilePath);

                LogWarn << "--------- 向Paration 发送数据 --------";
                outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pPartionInfoNew));

                iPushSpaceFrameId_ = pPartionInfoNew->modelSpaceFrame;
                bPushIsEnd_ = pPartionInfoNew->bIsEnd;
                LogDebug << "SplitTrainByNumPro pushSpaceFrameId:" << iPushSpaceFrameId_ << " timeStamp:" << pPartionInfoNew->i64EndTimeStamp
                         << " ltx:" << pPartionInfoNew->fLTX << " rbx:" << pPartionInfoNew->fRBX
                         << " bPushIsEnd:" << bPushIsEnd_;

                while (pMapCenterInfoTemp_->size() > 0)
                {
                    auto iterDel = pMapCenterInfoTemp_->begin();
                    if(iterDel->first > iPushSpaceFrameId_)
                    {
                        break;
                    }
                    LogDebug << "erase iFrameId:" << iterDel->first;
                    pMapCenterInfoTemp_->erase(iterDel);
                }
            }
        }

        if (iter->first >= pPartionInfo->modelSpaceFrame)
        {
            LogDebug << "frameid:"<< iter->first << " >= pPartionInfo->modelSpaceFrame:" << pPartionInfo->modelSpaceFrame << " break";
            break;
        }
    }

    while (pMapCenterInfoTemp_->size() > 0)
    {
        auto iterDel = pMapCenterInfoTemp_->begin();
        if (iterDel->first > pPartionInfo->modelSpaceFrame)
        {
            break;
        }
        LogDebug << "erase iFrameId:" << iterDel->first;
        pMapCenterInfoTemp_->erase(iterDel);
    }
}

APP_ERROR SaveStepOneResultEngine::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<PostData> pPostData = std::static_pointer_cast<PostData>(pProcessData->pVoidData);

        if (pProcessData->iFrameId == dataSourceConfig_.iSkipInterval)
        {
            i64TimeStampFirst_ = pProcessData->i64TimeStamp;
        }

        char szCameraNo[5] = {0};
        sprintf(szCameraNo, "%03d/", pProcessData->iDataSource + 1);
        std::string strFilePath;
        strFilePath = strResultPath_ + pProcessData->strOrigTrainDate + "/" + pProcessData->strOrigTrainName + "/" +
                      szCameraNo + std::to_string(pProcessData->iOrigFrameId) + ".txt";


        Json::Value jvStep1Num;
        Json::Value jvStep1Pro;
        Json::Value jvStep1ChkDate;
        Json::Value jvStep1Container;
        Json::Value jvStep1Space;
        Json::Value jvStep1TrainSpace;
        Json::Value jvStep1TopSpace;
        for (int i = 0; i < pPostData->vecPostSubData.size(); i++)
        {
            PostSubData postSubData = pPostData->vecPostSubData[i];
            if (postSubData.vecSingleData.size() < 0)
            {
                continue;
            }

            SingleData sdInfo = postSubData.vecSingleData.at(0);
            Json::Value jvInfo;
            jvInfo["classid"] = sdInfo.iClassId;
            jvInfo["score"] = sdInfo.fScore;
            jvInfo["clear"] = sdInfo.fClear;
            jvInfo["ltx"] = sdInfo.fLTX;
            jvInfo["lty"] = sdInfo.fLTY;
            jvInfo["rbx"] = sdInfo.fRBX;
            jvInfo["rby"] = sdInfo.fRBY;
            float fCenter = sdInfo.fLTX + (sdInfo.fRBX - sdInfo.fLTX) / 2;
            if (postSubData.iTargetType == NUM || postSubData.iTargetType == HEAD)
            {
                jvStep1Num.append(jvInfo);
                if (pProcessData->iDataSource == 0 && pProcessData->iStatus != TRAINSTATUS_STOP)
                {
                    if (postSubData.iTargetType != HEAD)
                    {
                        mapNumCenterInfo_.insert(std::make_pair(pProcessData->iFrameId, fCenter));
                    }
                    else
                    {
                        //车头没有属性，因此车头号也加入到属性中。保证向右行驶属性在前时最后2节的切分。
                        //车头只加入一次，防止一个车头2个车头号的场景。但有两个车头且没识别车头间隔则无法处理。
                        if (!bHaveHeadFlag_)
                        {
                            bool bIntervalFlag = ((int)(pProcessData->iFrameId - headInfo_.iFrameId) > iSplitSpan_ && headInfo_.iFrameId != 0);

                            LogDebug << "frameid:" << pProcessData->iFrameId << " center:" << fCenter
                                     << " preframeid:" << headInfo_.iFrameId << " precenter:" << headInfo_.fCenterX << " bIntervalFlag:" << bIntervalFlag;
                            if ((bIntervalFlag && abs((int)(headInfo_.fCenterX - fCenter)) > iSplitSpanPX_))
                            {
                                bHaveHeadFlag_ = true;
                            }
                            else
                            {
                                headInfo_.fCenterX = fCenter;
                                headInfo_.iFrameId = pProcessData->iFrameId;
                                mapNumCenterInfo_.insert(std::make_pair(pProcessData->iFrameId, fCenter));
                                mapProCenterInfo_.insert(std::make_pair(pProcessData->iFrameId, fCenter));
                            }
                        }
                    }
                }
            }
            else if (postSubData.iTargetType == PRO)
            {
                jvStep1Pro.append(jvInfo);
                if (pProcessData->iDataSource == 0 && pProcessData->iStatus != TRAINSTATUS_STOP)
                {
                    mapProCenterInfo_.insert(std::make_pair(pProcessData->iFrameId, fCenter));
                }
            }
            else if (postSubData.iTargetType == CHKDATE)
            {
                jvStep1ChkDate.append(jvInfo);
            }
            else if (postSubData.iTargetType == CONTAINER)
            {
                jvStep1Container.append(jvInfo);
            }
            else if (postSubData.iTargetType == SPACE)
            {
                jvStep1Space.append(jvInfo);
            }
            else if (postSubData.iTargetType == TRAINSPACE)
            {
                jvStep1TrainSpace.append(jvInfo);
            }
            else if (postSubData.iTargetType == TOPSPACE)
            {
                jvStep1TopSpace.append(jvInfo);
            }
        }

        //先读取文本内容，追加新的信息后再写入
        Json::Value jvFrameInfo;
        if (!MyUtils::getins()->ReadJsonInfo(jvFrameInfo, strFilePath))
        {
            LogError << "read fail:" << strFilePath;
        }

        if (jvStep1Num.size() > 0)
        {
            jvFrameInfo["step1Num"] = jvStep1Num;
        }
        if (jvStep1Pro.size() > 0)
        {
            jvFrameInfo["step1Pro"] = jvStep1Pro;
        }
        if (jvStep1ChkDate.size() > 0)
        {
            jvFrameInfo["step1ChkDate"] = jvStep1ChkDate;
        }
        if (jvStep1Container.size() > 0)
        {
            jvFrameInfo["step1Container"] = jvStep1Container;
        }
        if (jvStep1Space.size() > 0)
        {
            jvFrameInfo["step1Space"] = jvStep1Space;
        }
        if (jvStep1TrainSpace.size() > 0)
        {
            jvFrameInfo["step1TrainSpace"] = jvStep1TrainSpace;
            if (jvStep1Space.size() <= 0)
            {
                jvFrameInfo["step1Space"] = jvStep1TrainSpace;
                jvStep1Space = jvStep1TrainSpace;
            }
        }
        if (jvStep1TopSpace.size() > 0)
        {
            jvFrameInfo["step1TopSpace"] = jvStep1TopSpace;
        }

        int iInvokeModelCnt = jvFrameInfo["invokeModelCnt"].asInt();
        iInvokeModelCnt++;
        jvFrameInfo["invokeModelCnt"] = iInvokeModelCnt;
        if (mapInvokeModelCnt_[pProcessData->iDataSource] == iInvokeModelCnt)
        {
            jvFrameInfo["step1Finish"] = true;
        }
        jvFrameInfo["isEnd"] = (pProcessData->bIsEnd || jvFrameInfo["isEnd"].asBool());
        if (pProcessData->iStatus == TRAINSTATUS_STOP && pProcessData->iStatus != jvFrameInfo["status"].asInt())
        {
            jvFrameInfo["status"] = pProcessData->iStatus;
        }
        MyUtils::getins()->WriteJsonInfo(jvFrameInfo, strFilePath);
        //第一步处理结束后, push端口1，做复制图片文本数据和图片上传处理。
        if (jvFrameInfo["step1Finish"].asBool())
        {
            iRet = outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pProcessData));
        }

        if (pProcessData->iDataSource == 0 && pPostData->iModelType == MODELTYPE_NUM)
        {
            DealTrainSpaceInfo(pProcessData, jvStep1Space);

            if (pProcessData->bIsEnd)
            {
                //最后一节处理下前一节信息
                if (!bDealCenterFlag_ && vecParationInfo_.size() > 0)
                {
                    LogDebug << "lastFrameid:" << vecParationInfo_[0].modelSpaceFrame << " frameid:" << pProcessData->iFrameId;
                    DealCenterSpace(vecParationInfo_, pProcessData);
                }
                if (!bPushIsEnd_)
                {
                    std::shared_ptr<PartionInfo> pPartionInfo = std::make_shared<PartionInfo>();
                    pPartionInfo->iRate = pProcessData->iRate;
                    pPartionInfo->i64EndTimeStamp = pProcessData->i64TimeStamp;
                    pPartionInfo->modelSpaceFrame = pProcessData->iFrameId;
                    pPartionInfo->bmodelconfirmed = true;
                    pPartionInfo->strTrainDate = pProcessData->strTrainDate;
                    pPartionInfo->strTrainName = pProcessData->strTrainName;
                    pPartionInfo->bIsEnd = pProcessData->bIsEnd;
                    pPartionInfo->nStatus = ((pProcessData->iStatus == TRAINSTATUS_STOP) ? TRAIN_PAUSE : iDirection_);

                    //最后一节和倒数第二节之间的间隔未能识别时，此时也需要通过车号属性切分下。
                    SplitTrainByNumPro(pPartionInfo, pProcessData);

                    LogWarn << "--------- 向Paration 发送数据 --------";
                    outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pPartionInfo));

                    iPushSpaceFrameId_ = pPartionInfo->modelSpaceFrame;
                    bPushIsEnd_ = pPartionInfo->bIsEnd;
                    LogDebug << "pushSpaceFrameId:" << iPushSpaceFrameId_ << " timeStamp:" << pPartionInfo->i64EndTimeStamp
                             << " ltx:" << pPartionInfo->fLTX << " rbx:" << pPartionInfo->fRBX
                             << " bPushIsEnd:" << bPushIsEnd_;
                }
                InitParam();
            }
        }
    }
    return APP_ERR_OK;
}
