#include "TrainParationMgr.h"

using namespace ai_matrix;

TrainParationMgr::TrainParationMgr() {}

TrainParationMgr::~TrainParationMgr() {}

APP_ERROR TrainParationMgr::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path");
    //获取主摄像头信息
    mainCfg_ = MyYaml::GetIns()->GetDataSourceConfigById(0);

    nFrameRate = 25;
    InitParam();
    nTailPixOffset = getTailPixOffset();
    LogInfo << "TrainParationMgr Init ok";
    return APP_ERR_OK;
}

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

int TrainParationMgr::getTailPixOffset()
{
    LogInfo << "TrainParationMgr getTailPixOffset start";
    // 单位计算
    // 帧宽像素/米
    float fframewidth_meter = ((METHOD_BASE_WIDTH * 1.0) / (TRAIN_IN_CAMERA_WIDTH));
    // 车尾车钩像素位置
    float fOffsetPosistion = TRAIN_WIDTH * fframewidth_meter;
    int nretOffset = (int)fOffsetPosistion;
    return nretOffset;
}

/**
* 参数初始化(列车结束时需调用)
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void TrainParationMgr::InitParam()
{

}

/**
* 计算车钩移动的像素值
* inParam : 行车速度(单位:米/秒)
* inParam : 宽度
* inParam : 相机帧率(单位:帧/秒)
* outParam: N/A
* return  : 间隔帧
*/
int TrainParationMgr::getCouplerOffsetPosition(float fspeed, int nframeindex)
{
    LogInfo << "TrainAnaEngine getCouplerOffsetPosition start";
    //单位换算
    // 米/秒 -> 米/帧
    // 米/帧 = 米/秒 * 秒/帧(即:1/帧率)
    float fmeter_frame = fspeed / nFrameRate;
    // 米/帧 -> 像素/帧
    // 像素/帧 = 米/帧 * 像素/米
    float fpix_frame = fmeter_frame * (METHOD_BASE_WIDTH / TRAIN_IN_CAMERA_WIDTH);

    int nretPixOffet = (int)fpix_frame;
    nretPixOffet = nretPixOffet * nframeindex;
    LogInfo << "TrainAnaEngine getCouplerOffsetPosition nretPixOffet:" << nretPixOffet;
    LogInfo << "TrainAnaEngine getCouplerOffsetPosition end";
    return nretPixOffet;
}

/**
* 计算车钩移动的像素值
* inParam : 行车速度(单位:米/秒)
* inParam : 宽度
* inParam : 相机帧率(单位:帧/秒)
* outParam: N/A
* return  : 间隔帧
*/
int TrainParationMgr::getCouplerOffsetPix(float fspeed, int noffsetPix)
{
    LogInfo << "TrainAnaEngine getCouplerOffsetPix start";
    LogInfo << "TrainAnaEngine getCouplerOffsetPix fspeed:" << fspeed;
//    LogInfo << "TrainAnaEngine getCouplerOffsetPix start:" << nframeindex;
    //单位换算
    // 米/秒 -> 米/帧
    // 米/帧 = 米/秒 * 秒/帧(即:1/帧率)
    float fmeter_frame = fspeed / nFrameRate;
    LogInfo << "TrainAnaEngine getCouplerOffsetPix fmeter_frame:" << fmeter_frame;
    // 米/帧 -> 像素/帧
    // 像素/帧 = 米/帧 * 像素/米
    float fpix_frame = fmeter_frame * (METHOD_BASE_WIDTH / TRAIN_IN_CAMERA_WIDTH);
    LogInfo << "TrainAnaEngine getCouplerOffsetPix fpix_frame:" << fpix_frame;

    int nretPixOffet = (int)fpix_frame;
    nretPixOffet = (noffsetPix - (METHOD_BASE_WIDTH / 2)) / nretPixOffet;
    LogInfo << "TrainAnaEngine getCouplerOffsetPix nretPixOffet:" << nretPixOffet;
    LogInfo << "TrainAnaEngine getCouplerOffsetPix end";
    return nretPixOffet;
}

/**
* 计算车钩从中间到边缘的间隔帧
* inParam : 行车速度(单位:米/秒)
* inParam : 宽度
* inParam : 相机帧率(单位:帧/秒)
* outParam: N/A
* return  : 间隔帧
*/
int TrainParationMgr::getOffsetFrame(float fspeed, int width, int nFrameRate)
{
    LogInfo << "TrainAnaEngine getOffsetFrame start";
    LogInfo << "TrainAnaEngine getOffsetFrame fspeed:" << fspeed;
    LogInfo << "TrainAnaEngine getOffsetFrame width:" << width;
    LogInfo << "TrainAnaEngine getOffsetFrame nFrameRate:" << nFrameRate;
    //LogInfo << "TrainAnaEngine getOffsetFrame nLatestFrame:" << nLatestFrame;
    //偏移值 = (中间到边缘的宽度(米) / 速度(米/秒)->时间(秒))* 帧率(帧/秒)
    float ftmp = width * (float) nFrameRate;
    LogInfo << "TrainAnaEngine getOffsetFrame start end:" << ftmp;
    ftmp = ftmp / fspeed;
    LogInfo << "TrainAnaEngine getOffsetFrame start end:" << ftmp;
    int nRet = (int) ftmp;
    LogInfo << "TrainAnaEngine getOffsetFrame start end:" << nRet;
    return nRet;
}



APP_ERROR TrainParationMgr::Process()
{
    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<PartionInfo> pPartionInfo = std::static_pointer_cast<PartionInfo>(pVoidData0);

        int nSize = lstPartInfo.size();
        int nPartionIndex = nSize - 1;

        //当然车厢通过的数量
        if (nSize == 0) {
            PartionInfo stTempInfo;
            stTempInfo.endframe = pPartionInfo->modelSpaceFrame;
            stTempInfo.i64EndTimeStamp = pPartionInfo->i64EndTimeStamp;
            stTempInfo.nindex = 1;
            //第一节车厢开始帧为跳帧数，开始帧时间设置为来车时间
            stTempInfo.startframe = mainCfg_.iSkipInterval;
            std::string strTemp = pPartionInfo->strTrainDate + " " + pPartionInfo->strTrainName;
            stTempInfo.i64StartTimeStamp = MyUtils::getins()->GetParamTimeMilliSeconds(strTemp);

            // LogWarn << "日期:" << strTemp << " -- 时间戳:" << stTempInfo.i64StartTimeStamp;
            stTempInfo.fspeed = TRAIN_DEFAULT_SPEED;
            stTempInfo.fLTX = (abs(pPartionInfo->fLTX - pPartionInfo->fRBX) / 2) + pPartionInfo->fLTX;
            lstPartInfo.push_back(stTempInfo);
            //lstPartInfo.push_back(stTempInfo);
            nPartionIndex++;
        }
        lstPartInfo[nPartionIndex].i64EndTimeStamp = pPartionInfo->i64EndTimeStamp;
        lstPartInfo[nPartionIndex].endframe = pPartionInfo->modelSpaceFrame;
        // 根据开始帧时间戳和结束帧时间错 计算当节车厢的行车速度
        // 根据时间戳计算时间差


        float nTimePassed = (abs(lstPartInfo[nPartionIndex].i64EndTimeStamp - lstPartInfo[nPartionIndex].i64StartTimeStamp)) * 1.0;
        //防止停车导致速度过小
        if(pPartionInfo->nStatus != TRAIN_PAUSE && nTimePassed <= 50000) {
            lstPartInfo[nPartionIndex].fspeed = (TRAIN_WIDTH * 1000.0) /nTimePassed;
        } else {
            if (nPartionIndex >= 1){
                lstPartInfo[nPartionIndex].fspeed = lstPartInfo[nPartionIndex - 1].fspeed / 3;
            } else {
                lstPartInfo[nPartionIndex].fspeed = TRAIN_DEFAULT_SPEED / 10;
            }
        }

        //
        //nSamePartionIgnoreCount = (nTimePassed / (3 * 5000)) * nFrameRate;
        // 结束帧为当前帧再往后 (除以2的原因：中间为车钩，车钩后的车体宽度为整个镜头的宽度除以2)
        lstPartInfo[nPartionIndex].bmodelconfirmed = true;

        /// write json info to file

        //先读取文本内容，追加新的信息后再写入
        //划分信息 JSON格式
        Json::Value jvPartionInfo;
        //JSON保存路径
        std::string strFilePath;

        //检测到车厢划分信息
        strFilePath = strResultPath_ + pPartionInfo->strTrainDate + "/" + pPartionInfo->strTrainName + "/"
                      + std::to_string(nPartionIndex + 1) + ".txt";

        LogInfo << "TrainAnaEngine Process lstPartInfo[nPartionIndex].startframe：" << lstPartInfo[nPartionIndex].startframe ;
        LogInfo << "TrainAnaEngine Process lstPartInfo[nPartionIndex].endframe：" << lstPartInfo[nPartionIndex].endframe;

        PartionInfo stTempInfo;
        // 开始记录新的一节车厢信息(从索引变成序号+1 ，新增一节车厢信息+1)
        stTempInfo.nindex = nPartionIndex + 2;
        // 上一节车厢的结束帧  - (偏移帧 = (镜头内的车体宽度/ (速度) -> 通过时间) * 帧/秒 ) 作为下一节车厢的开始帧
        int ntempOffsetFrame = lstPartInfo[nPartionIndex].endframe;
        stTempInfo.startframe = ntempOffsetFrame;
        stTempInfo.i64StartTimeStamp = pPartionInfo->i64EndTimeStamp;
        // 初始化下一节的结束帧
        //stTempInfo.endframe = 0;

        lstPartInfo.push_back(stTempInfo);

        // 记录过车日期
        jvPartionInfo["trainDate"] = pPartionInfo->strTrainDate;
        // 记录过车时间
        jvPartionInfo["trainName"] = pPartionInfo->strTrainName;
        // 记录车厢节数 (索引从0开始 所以这里+1)
        jvPartionInfo["trainNo"] = nPartionIndex + 1;
        // 记录行车开始帧
        jvPartionInfo["startFrameId"] = lstPartInfo[nPartionIndex].startframe;
        jvPartionInfo["startTimeStamp"] = lstPartInfo[nPartionIndex].i64StartTimeStamp;
        // 记录行车结束帧
        jvPartionInfo["endFrameId"] = lstPartInfo[nPartionIndex].endframe;
        jvPartionInfo["endTimeStamp"] = lstPartInfo[nPartionIndex].i64EndTimeStamp;
        // 记录车厢是否完全通过
        jvPartionInfo["isEnd"] = pPartionInfo->bIsEnd;

        //是否是间隔模型切分的车厢
        jvPartionInfo["modelconfirmed"] = pPartionInfo->bmodelconfirmed;

        // 记录当前车厢的信息到JSON文件
        MyUtils::getins()->WriteJsonInfo(jvPartionInfo, strFilePath);
        std::shared_ptr<TrainRange> pTrainRange = std::make_shared<TrainRange>();
        pTrainRange->strTrainDate = jvPartionInfo["trainDate"].asString();
        pTrainRange->strTrainName = jvPartionInfo["trainName"].asString();
        pTrainRange->iTrainIndex = jvPartionInfo["trainNo"].asInt();
        pTrainRange->iStartFrameId = jvPartionInfo["startFrameId"].asInt();
        pTrainRange->i64StartTimeStamp = jvPartionInfo["startTimeStamp"].asInt64();
        pTrainRange->iEndFrameId = jvPartionInfo["endFrameId"].asInt();
        pTrainRange->i64EndTimeStamp = jvPartionInfo["endTimeStamp"].asInt64();
        pTrainRange->bIsEnd = jvPartionInfo["isEnd"].asBool();
        pTrainRange->bmodelconfirmed = jvPartionInfo["modelconfirmed"].asBool();
        iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pTrainRange));

        if (pPartionInfo->bIsEnd) {
            lstPartInfo.clear();
        }
    }
    return APP_ERR_OK;
}
