#include "ContainerCharacterConversionEngine.h"


using namespace ai_matrix;

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

ContainerCharacterConversionEngine::ContainerCharacterConversionEngine() {}

ContainerCharacterConversionEngine::~ContainerCharacterConversionEngine() {}

APP_ERROR ContainerCharacterConversionEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strPort3_ = engineName_ + "_" + std::to_string(engineId_) + "_3";
    this->modelConfig_ = Config::getins()->getModelByContainerStep2Config();
    this->baseConfig_ = Config::getins()->getBaseConfig();

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

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

/**
* 验证集装箱号是否满足规则(前10位依次与2^0 ~2^9相乘）/11 所得余数，即是校验位)
* inParam : std::string &strContainerNo   集装箱号信息
* outParam: N/A
* return  : true(校验通过)/false(校验失败)
*/
bool ContainerCharacterConversionEngine::verifyContainerNo(std::string &strContainerNo)
{
    bool bChkFlag = false;

    if(strContainerNo.length() != 11)
    {
        return bChkFlag;
    }

    int iSum = 0;
    for (int i = 0; i < strContainerNo.length()-1; ++i)
    {
        iSum += this->mapExchange_[strContainerNo.substr(i, 1)] * int(pow(2.0, i));
    }

    //当校验位等于10时要继续模运算,iSum % 11 % 10,保证最终结果为0~9之间的数
    int iChkValue = iSum % 11 % 10;
    if (iChkValue == atoi(strContainerNo.substr(strContainerNo.length()-1, 1).c_str()))
    {
        bChkFlag = true;
    }
    return bChkFlag;
}

void ContainerCharacterConversionEngine::transContainerType(Step2ResultData &step2ResultData, std::map<int, std::vector<SingleData>> &mapLine)
{
    TransInfo info;
    info.iLine = 1;
    //集装箱型号（4位 字母或数字）
    if (mapLine.find(3) != mapLine.end())
    {
        std::string strTemp;
        for (auto j = 0; j < mapLine.at(3).size(); j++)
        {
            strTemp += vecClassNames_.at(mapLine.at(3).at(j).iClassId);
        }
        int nTypesize = strTemp.length();
        nTypesize = nTypesize > 4 ? 4 : nTypesize;
        info.strTmpResult = strTemp.substr(0, nTypesize);
    }
    if (info.strTmpResult.length() != 4)
    {
        info.bIsChkFlag = false;
    }
//    step2ResultData.transInfo = info;
}

/**
* 集装箱框内容转换
* inParam : std::map<int, std::vector<SingleData>> &mapLine
* outParam: TransSubData &transSubData
* return  : N/A
*/
void ContainerCharacterConversionEngine::transContainerNum(Step2ResultData &step2ResultData, std::map<int, std::vector<SingleData>> &mapLine)
{
    TransInfo info;
    info.iLine = 0;
    // 箱主代码+设备识别码（4位英文字母）
    if (mapLine.find(0) != mapLine.end())
    {
        std::string strTemp;
        for (auto j = 0; j < mapLine.at(0).size(); j++)
        {
            std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(0).at(j).iClassId);
            // 过滤非字母
            if (strOne[0] < 'A' || strOne[0] > 'Z')
            {
//                LogDebug << strOne << " not A-Z in container";
                continue;
            }
            strTemp += strOne;
            info.vecValue.emplace_back(strOne);
            info.vecScore.emplace_back(mapLine.at(0).at(j).fScore);
            step2ResultData.fSubScoreSum += mapLine.at(0).at(j).fScore;
        }
        info.strTmpResult += strTemp;
    }

    // 箱号（6位数字）
    if (mapLine.find(1) != mapLine.end())
    {
        std::string strTemp;
        for (auto j = 0; j < mapLine.at(1).size(); j++)
        {
            std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(1).at(j).iClassId);
            // 过滤非数字
            if (strOne[0] < '0' || strOne[0] > '9')
            {
//                LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in num";
                continue;
            }
            strTemp += strOne;
            info.vecValue.emplace_back(strOne);
            info.vecScore.emplace_back(mapLine.at(1).at(j).fScore);
            step2ResultData.fSubScoreSum += mapLine.at(1).at(j).fScore;
        }
        info.strTmpResult += strTemp;
    }

    //校验码（1位数字）
    if (mapLine.find(2) != mapLine.end())
    {
        std::string strTemp;
        for (auto j = 0; j < mapLine.at(2).size(); j++)
        {
            //过滤非数字
            std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(2).at(j).iClassId);
            if (strOne[0] < '0' || strOne[0] > '9')
            {
//                LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in container_2";
                continue;
            }
            strTemp += strOne;
            info.vecValue.emplace_back(strOne);
            info.vecScore.emplace_back(mapLine.at(2).at(j).fScore);
            step2ResultData.fSubScoreSum += mapLine.at(2).at(j).fScore;
        }
        info.strTmpResult += strTemp;
    }

    if (this->verifyContainerNo(info.strTmpResult))
    {
        info.bIsChkFlag = true;
    }
    else
    {
        info.strTmpResult = "invalid-" + info.strTmpResult;
    }

    step2ResultData.transInfo = info;
}

APP_ERROR ContainerCharacterConversionEngine::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<VStep2OutputData> pVStep2OutputData = std::static_pointer_cast<VStep2OutputData>(pVoidData0);

        std::shared_ptr<SaveDebugImgData> pSaveDebugImgData = std::make_shared<SaveDebugImgData>();
        pSaveDebugImgData->iFrameId = pVStep2OutputData->iFrameId;
        pSaveDebugImgData->iDataSource = pVStep2OutputData->iDataSource;
        pSaveDebugImgData->strDetectDate = pVStep2OutputData->strDetectDate;
        pSaveDebugImgData->strDetectTime = pVStep2OutputData->strDetectTime;
        pSaveDebugImgData->cvImage = pVStep2OutputData->cvImage.clone();
        pSaveDebugImgData->step2ResultData = pVStep2OutputData->step2ResultData;
        pSaveDebugImgData->vecCornerResultData = pVStep2OutputData->vecCornerResultData;

        if (pVStep2OutputData->bIsEnd)
        {
//            LogInfo << " --->>> 结束信号 : " << pVStep2OutputData->iDataSource;
            outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast<void>(pVStep2OutputData), true);
//            outputQueMap_[strPort3_]->push(std::static_pointer_cast<void>(pSaveDebugImgData), true);
            continue;
        }

        std::vector<SingleData> vecSingleData = pVStep2OutputData->step2ResultData.vecSingleData;

        if (pVStep2OutputData->step2ResultData.fScore == 0.0f)
        {
            outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast<void>(pVStep2OutputData), true);
//            outputQueMap_[strPort3_]->push(std::static_pointer_cast<void>(pSaveDebugImgData), true);
            continue;
        }

        std::map<int, std::vector<SingleData>> mapLine;
        for (auto & it_singleData : vecSingleData)
        {
            mapLine[it_singleData.iLine].push_back(it_singleData);
        }

        bool bSortByX =
                (pVStep2OutputData->step2ResultData.fRBY - pVStep2OutputData->step2ResultData.fLTY) <
                ((pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX) *
                 1.5);

        //每一行按x坐标排序
        for (auto & it : mapLine)
        {
            if (it.second.size() > 2)
            {
                std::set<float> setX;
                std::set<float> setY;
                for (auto & it_singleData : it.second)
                {
                    setX.insert(it_singleData.fLTX);
                    setY.insert(it_singleData.fLTY);
                }
                float X = *setX.rbegin() - *setX.begin();
                float Y = *setY.rbegin() - *setY.begin();
                bSortByX = (X > Y);
            }

            if (bSortByX)
            {
                std::sort(it.second.begin(), it.second.end(), CompareX);
            }
            else
            {
                std::sort(it.second.begin(), it.second.end(), CompareY);
            }

//            std::string strTemp;
//            for (auto & it_singleData : it.second)
//            {
//                strTemp += this->modelConfig_.vecClass.at(it_singleData.iClassId);
//            }
        }

        switch (pVStep2OutputData->step2ResultData.iClassId)
        {
            case 0:
                this->transContainerNum(pVStep2OutputData->step2ResultData, mapLine);
                break;
            default:
                break;
        }

        // 模型识别不稳定时才用。
//        if (bSortByX && pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag)
//        {
//            if (mapLine.find(0) != mapLine.end() && mapLine.find(1) != mapLine.end())
//            {
//                if (mapLine.at(1).at(0).fLTX < mapLine.at(0).at(0).fLTX)
//                {
//                    pVStep2OutputData->step2ResultData.transInfo.strTmpResult = "invalid-" + pVStep2OutputData->step2ResultData.transInfo.strTmpResult;
//                    pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag = false;
//                }
//            }
//        }

        pSaveDebugImgData->step2ResultData = pVStep2OutputData->step2ResultData;
        outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast<void>(pVStep2OutputData), true);
//        outputQueMap_[strPort3_]->push(std::static_pointer_cast<void>(pSaveDebugImgData), true);
    }

    return APP_ERR_OK;
}
