#include "SaveCsvEngine.h"

using namespace ai_matrix;

SaveCsvEngine::SaveCsvEngine() {}

SaveCsvEngine::~SaveCsvEngine() {}

APP_ERROR SaveCsvEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
    strPort2_ = engineName_ + "_" + std::to_string(engineId_) + "_2";
    strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path");
    strPoundNo_ = MyYaml::GetIns()->GetStringValue("atlas_poundno");

    LogInfo << "SaveCsvEngine Init ok";
    return APP_ERR_OK;
}

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

/**
* 保存合并后车厢的最优结果到CSV中 (该文件支持其web导入)
* inParam : std::shared_ptr<Train> pTrain   :列车信息
* outParam:
* return  : true/false
*/
bool SaveCsvEngine::SaveMergerCsv(std::shared_ptr<Train> pTrain)
{
    //1. 创建保存路径 (固定路径/YYYY-MM-DD/hh-mm-ss/)
    std::string strTrainPath = strResultPath_ + pTrain->strTrainDate + "/" + pTrain->strTrainName + "/";
    if (!MyUtils::getins()->CreateDirPath(strTrainPath))
    {
        LogError << "iCarXH:" << pTrain->iCarXH << " train savecsv err";
        return false;
    }

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

    bool bIsExsit = false;
    if (access(strCsvPath.c_str(), F_OK) != -1)
    {
        bIsExsit = true;
    }

    try
    {
        // 写文件
        std::ofstream outFile;
        outFile.open(strCsvPath, std::ios::app); // 打开模式可省略

        if (!bIsExsit)
        {
            outFile << "poundno" << ','
                    << "year" << ','
                    << "time" << ','
                    << "direction" << ','
                    << "speed" << ','
                    << "typeId" << ','
                    << "skipInterval" << ','
                    << "carxh" << ','
                    << "type" << ','
                    << "num" << ','
                    << "load" << ','
                    << "self" << ','
                    << "volume" << ','
                    << "volumesurface" << ','
                    << "change" << ','
                    << "numImgPath" << ','
                    << "proImgPath" << ','
                    << "videoStart" << ','
                    << "videoEnd" << ','
                    << "containerNo1" << ','
                    << "containerNo2" << ','
                    << "inspection" << ','
                    << "inspectionImg" << ','
                    << "containerImg_1" << ','
                    << "containerImg_2" << ','
                    << "startTime" << ','
                    << "endTime"
                    << std::endl;
        }

        std::string strTime = pTrain->strTrainName;
        strTime = MyUtils::getins()->replace_all_distinct(strTime, std::string("-"), std::string(":"));
        ai_matrix::DataSourceConfig dataSourceConfig = MyYaml::GetIns()->GetDataSourceConfigById(pTrain->trainNum.iDataSource); //获取摄像机参数

        char szCameraNo[4] = {0};
        sprintf(szCameraNo, "%03d", pTrain->trainNum.iDataSource + 1);

        char szNumImgPath[64] = {0};            //车号最优图片路径
        if (!pTrain->trainNum.strBestImg.empty())
        {
            sprintf(szNumImgPath, "%03d/%s", pTrain->trainNum.iDataSource + 1, pTrain->trainNum.strBestImg.c_str());
        }

        char szProImgPath[64] = {0};            //属性最优图片路径
        if (!pTrain->trainPro.strBestImg.empty())
        {
            sprintf(szProImgPath, "%03d/%s", pTrain->trainPro.iDataSource + 1, pTrain->trainPro.strBestImg.c_str());
        }

        char szChkDateImgPath[64] = {0};        //定检期最优图片路径
        if (!pTrain->chkDate.strBestImg.empty())
        {
            sprintf(szChkDateImgPath, "%03d/%s", pTrain->chkDate.iDataSource + 1, pTrain->chkDate.strBestImg.c_str());
        }

        char szContainer1ImgPath[64] = {0};     //集装箱1最优图片路径
        if (!pTrain->container1.strBestImg.empty())
        {
            sprintf(szContainer1ImgPath, "%03d/%s", pTrain->container1.iDataSource + 1, pTrain->container1.strBestImg.c_str());
        }

        char szContainer2ImgPath[64] = {0};     //集装箱2最优图片路径
        if (!pTrain->container2.strBestImg.empty())
        {
            sprintf(szContainer2ImgPath, "%03d/%s", pTrain->container2.iDataSource + 1, pTrain->container2.strBestImg.c_str());
        }

        outFile << strPoundNo_ << ','
                << pTrain->strTrainDate << ','
                << strTime << ','
                << pTrain->iDirection << ','
                << 0.0 << ','
                << pTrain->trainNum.iTrainTypeId << ','
                << dataSourceConfig.iSkipInterval << ','
                << pTrain->iCarXH << ','
                << pTrain->trainNum.strTrainType << ','
                << pTrain->trainNum.strTrainNum << ','
                << pTrain->trainPro.strLoad << ','
                << pTrain->trainPro.strSelf << ','
                << pTrain->trainPro.strVolume << ','
                << pTrain->trainPro.strVolumeSurface << ','     //容量记表
                << pTrain->trainPro.strChange << ','
                << szNumImgPath << ','
                << szProImgPath << ','
                << pTrain->iStartFrameId << ','
                << pTrain->iEndFrameId << ','
                << pTrain->container1.strContainerNo << ','
                << pTrain->container2.strContainerNo << ','
                << pTrain->chkDate.strChkDate1DeadLine << ','
                << szChkDateImgPath << ','
                << szContainer1ImgPath << ','
                << szContainer2ImgPath << ','
                << MyUtils::getins()->Stamp2Time(pTrain->i64StartTimeStamp, true) << ','
                << MyUtils::getins()->Stamp2Time(pTrain->i64EndTimeStamp, true)
                << std::endl;

        outFile.close();
    }
    catch (const std::exception &)
    {
        LogError << "strCsvPath:" << strCsvPath << " train savecsv fail!";
        return false;
    }
    return true;
}

/**
* 保存车厢的最优结果到CSV中
* inParam : std::shared_ptr<Train> pTrain   :列车信息
* outParam:
* return  : true/false
*/
bool SaveCsvEngine::SaveTrainCsv(std::shared_ptr<Train> pTrain)
{
    char szCameraNo[4] = {0};
    sprintf(szCameraNo, "%03d", pTrain->iDataSource + 1);
    std::string strTrainPath = strResultPath_ + pTrain->strTrainDate + "/" + pTrain->strTrainName + "/" +
                               szCameraNo + "/";

    //1. 创建保存路径 (固定路径/YYYY-MM-DD/hh-mm-ss/iDataSoure/)
    if (!MyUtils::getins()->CreateDirPath(strTrainPath))
    {
        LogError << "iCarXH:" << pTrain->iCarXH << " train savecsv err";
        return false;
    }

    //2. 保存csv
    std::string strCsvName = pTrain->strTrainDate + pTrain->strTrainName + "_" + szCameraNo + "_train.csv";
    strCsvName = MyUtils::getins()->replace_all_distinct(strCsvName, std::string("-"), std::string(""));
    std::string strCsvPath = strTrainPath + strCsvName;

    bool bIsExsit = false;
    if (access(strCsvPath.c_str(), F_OK) != -1)
    {
        bIsExsit = true;
    }

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

        if (!bIsExsit)
        {
            outFile << "car_xh" << ','
                    << "train_num_name" << ','
                    << "train_pro_name" << ','
                    << "t_type" << ','
                    << "t_num" << ','
                    << "load" << ','
                    << "self" << ','
                    << "volume" << ','
                    << "change" << ','
                    << "volumesurface" << ','
                    << "num_ltx" << ','
                    << "num_lty" << ','
                    << "num_rbx" << ','
                    << "num_rby" << ','
                    << "pro_ltx" << ','
                    << "pro_lty" << ','
                    << "pro_rbx" << ','
                    << "pro_rby" << ','
                    << "start_frameId" << ','
                    << "end_frameId" << ','
                    << "start_timestamp" << ','     //记录车厢开始，结束帧时间戳，用于比对集装箱合并
                    << "timestamp" << ','
                    << "end_timestamp" << ','
                    << "start_num" << ','
                    << "num_timestamp" << ','       //记录车号，属性时间戳，用于比对定检期合并
                    << "end_num" << ','
                    << "start_pro" << ','
                    << "pro_timestamp" << ','
                    << "end_pro" << std::endl;
        }
        outFile << pTrain->iCarXH << ','
                << pTrain->trainNum.strBestImg << ','
                << pTrain->trainPro.strBestImg << ','
                << pTrain->trainNum.strTrainType << ','
                << pTrain->trainNum.strTrainNum << ','
                << pTrain->trainPro.strLoad << ','
                << pTrain->trainPro.strSelf << ','
                << pTrain->trainPro.strVolume << ','
                << pTrain->trainPro.strChange << ','
                << pTrain->trainPro.strVolumeSurface << ','
                << pTrain->trainNum.step1Location.fLTX << ','
                << pTrain->trainNum.step1Location.fLTY << ','
                << pTrain->trainNum.step1Location.fRBX << ','
                << pTrain->trainNum.step1Location.fRBY << ','
                << pTrain->trainPro.step1Location.fLTX << ','
                << pTrain->trainPro.step1Location.fLTY << ','
                << pTrain->trainPro.step1Location.fRBX << ','
                << pTrain->trainPro.step1Location.fRBY << ','
                << pTrain->iStartFrameId << ','
                << pTrain->iEndFrameId << ','
                << pTrain->i64StartTimeStamp << ','
                << pTrain->i64TimeStamp << ','
                << pTrain->i64EndTimeStamp << ','
                << pTrain->trainNum.i64StartTimeStamp << ','
                << pTrain->trainNum.i64TimeStamp << ','
                << pTrain->trainNum.i64EndTimeStamp << ','
                << pTrain->trainPro.i64StartTimeStamp << ','
                << pTrain->trainPro.i64TimeStamp << ','
                << pTrain->trainPro.i64EndTimeStamp << std::endl;

        outFile.close();
    }
    catch (const std::exception &)
    {
        LogError << "strCsvPath:" << strCsvPath << " train savecsv fail!";
        return false;
    }
    return true;
}

/**
* 保存定检期的最优结果到CSV中
* inParam : std::shared_ptr<ChkDate> pChkDate   :定检期信息
* outParam:
* return  : true/false
*/
bool SaveCsvEngine::SaveChkDateCsv(std::shared_ptr<ChkDate> pChkDate)
{
    if (pChkDate->strBestImg.empty())
    {
        LogDebug << "datetime:" << pChkDate->strTrainDate << " " << pChkDate->strTrainName
                 << " carxh:" << pChkDate->iCarXH << " chkdate empty";
        return true;
    }
    //1. 创建保存路径 (固定路径/YYYY-MM-DD/hh-mm-ss/iDataSoure/)
    char szCameraNo[4] = {0};
    sprintf(szCameraNo, "%03d", pChkDate->iDataSource + 1);
    std::string strChkDatePath = strResultPath_ + pChkDate->strTrainDate + "/" + pChkDate->strTrainName + "/" +
                                 szCameraNo + "/";

    if (!MyUtils::getins()->CreateDirPath(strChkDatePath))
    {
        LogError << "iCarXH:" << pChkDate->iCarXH << "chkdate savecsv err";
        return false;
    }

    //2. 保存csv
    std::string strCsvName = pChkDate->strTrainDate + pChkDate->strTrainName + "_" + szCameraNo + "_chkdate.csv";
    strCsvName = MyUtils::getins()->replace_all_distinct(strCsvName, std::string("-"), std::string(""));
    std::string strCsvPath = strChkDatePath + strCsvName;

    bool bIsExsit = false;
    if (access(strCsvPath.c_str(), F_OK) != -1)
    {
        bIsExsit = true;
    }

    try
    {
        // 写文件
        std::ofstream outFile;
        outFile.open(strCsvPath, std::ios::app); // 打开模式可省略

        if (!bIsExsit)
        {
            outFile << "car_xh" << ','
                    << "chkdate_name" << ','
                    << "chkdate1" << ','
                    << "chkdate2" << ','
                    << "chkdate_ltx" << ','
                    << "chkdate_lty" << ','
                    << "chkdate_rbx" << ','
                    << "chkdate_rby" << ','
                    << "start_frameId" << ','
                    << "end_frameId" << ','
                    << "start_timestamp" << ','
                    << "end_timestamp" << ','
                    << "timestamp" << ','
                    << "chkdate1deadline" << std::endl;
        }
        outFile << pChkDate->iCarXH << ','
                << pChkDate->strBestImg << ','
                << pChkDate->strChkDate1 << ','
                << pChkDate->strChkDate2 << ','
                << pChkDate->step1Location.fLTX << ','
                << pChkDate->step1Location.fLTY << ','
                << pChkDate->step1Location.fRBX << ','
                << pChkDate->step1Location.fRBY << ','
                << pChkDate->iStartFrameId << ','
                << pChkDate->iEndFrameId << ','
                << pChkDate->i64StartTimeStamp << ','
                << pChkDate->i64EndTimeStamp << ','
                << pChkDate->i64TimeStamp << ','
                << pChkDate->strChkDate1DeadLine << std::endl;

        outFile.close();
    }
    catch (const std::exception &)
    {
        LogError << "strCsvPath:" << strCsvPath << " chkdate savecsv fail!";
        return false;
    }
    return true;
}

/**
* 保存集装箱的最优结果到CSV中
* inParam : std::shared_ptr<TrainContainer> pTrainContainer     :集装箱信息
* outParam:
* return  : true/false
*/
bool SaveCsvEngine::SaveContainerCsv(std::shared_ptr<TrainContainer> pTrainContainer)
{
    std::vector<Container> vecContainer;
    vecContainer.emplace_back(pTrainContainer->container1);
    vecContainer.emplace_back(pTrainContainer->container2);
    for (auto iter = vecContainer.begin(); iter != vecContainer.end(); iter++)
    {
        if (iter->strContainerNo.empty())
        {
            continue;
        }
        // 1. 创建保存路径 (固定路径/YYYY-MM-DD/hh-mm-ss/iDataSoure/)
        char szCameraNo[4] = {0};
        sprintf(szCameraNo, "%03d", iter->iDataSource + 1);
        std::string strContainerPath = strResultPath_ + iter->strTrainDate + "/" + iter->strTrainName + "/" +
                                       szCameraNo + "/";

        if (!MyUtils::getins()->CreateDirPath(strContainerPath))
        {
            LogError << "ContainerNo:" << iter->strContainerNo << " container savecsv err";
            continue;
        }
        // 2. 保存csv
        std::string strCsvName = iter->strTrainDate + iter->strTrainName + "_" + szCameraNo + "_container.csv";
        strCsvName = MyUtils::getins()->replace_all_distinct(strCsvName, std::string("-"), std::string(""));
        std::string strCsvPath = strContainerPath + strCsvName;

        bool bIsExsit = false;
        if (access(strCsvPath.c_str(), F_OK) != -1)
        {
            bIsExsit = true;
        }

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

            if (!bIsExsit)
            {
                outFile << "datasource" << ','
                        << "container_name" << ','
                        << "containerNo" << ','
                        << "container_ltx" << ','
                        << "container_lty" << ','
                        << "container_rbx" << ','
                        << "container_rby" << ','
                        << "start_frameId" << ','
                        << "end_frameId" << ','
                        << "timestamp" << std::endl;
            }
            outFile << iter->iDataSource << ','
                    << iter->strBestImg << ','
                    << iter->strContainerNo << ','
                    << iter->step1Location.fLTX << ','
                    << iter->step1Location.fLTY << ','
                    << iter->step1Location.fRBX << ','
                    << iter->step1Location.fRBY << ','
                    << iter->iStartFrameId << ','
                    << iter->iEndFrameId << ','
                    << iter->i64TimeStamp << std::endl;

            outFile.close();
        }
        catch (const std::exception &)
        {
            LogError << "strCsvPath:" << strCsvPath << " container savecsv fail!";
            continue;
        }
    }
    return true;
}

APP_ERROR SaveCsvEngine::Process()
{
    int iRet = APP_ERR_OK;
    while (!isStop_)
    {

        bool bPopFlag = false;
        //pop端口0 车厢信息
        std::shared_ptr<void> pVoidData0 = nullptr;
        iRet = inputQueMap_[strPort0_]->pop(pVoidData0);
        if (nullptr != pVoidData0)
        {
            std::shared_ptr<Train> pTrain = std::static_pointer_cast<Train>(pVoidData0);
            if (pTrain->bMergerFlag)
            {
                SaveMergerCsv(pTrain);
            }
            else
            {
                SaveTrainCsv(pTrain);
            }
            bPopFlag = true;
        }
        //pop端口1 定检期信息
        if (inputQueMap_.count(strPort1_) > 0)
        {
            std::shared_ptr<void> pVoidData1 = nullptr;
            inputQueMap_[strPort1_]->pop(pVoidData1);
            if (nullptr != pVoidData1)
            {
                std::shared_ptr<ChkDate> pChkDate = std::static_pointer_cast<ChkDate>(pVoidData1);
                SaveChkDateCsv(pChkDate);
                bPopFlag = true;
            }
        }
        //pop端口2 集装箱信息
        if (inputQueMap_.count(strPort2_) > 0)
        {
            std::shared_ptr<void> pVoidData2 = nullptr;
            inputQueMap_[strPort2_]->pop(pVoidData2);
            if (nullptr != pVoidData2)
            {
                std::shared_ptr<TrainContainer> pTrainContainer = std::static_pointer_cast<TrainContainer>(pVoidData2);
                SaveContainerCsv(pTrainContainer);
                bPopFlag = true;
            }
        }

        if (!bPopFlag)
        {
            usleep(1000);
            continue;
        }
    }
    return APP_ERR_OK;
}
