#include "SelectBestEngine.h"

using namespace ai_matrix;

SelectBestEngine::SelectBestEngine() {}

SelectBestEngine::~SelectBestEngine() {}

APP_ERROR SelectBestEngine::Init()
{
    strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
    strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
    strPort2_ = engineName_ + "_" + std::to_string(engineId_) + "_2";

    this->baseConfig_ = Config::getins()->getBaseConfig();
    this->minioConfig_ = Config::getins()->getMinioConfig();
    this->vecDataSourceConfig_ = Config::getins()->getAllDataSourceConfig();

    this->initParam();

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

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

/**
* 初始化参数信息
* inParam : N/A
* outParam: N/A
* return  : N/A
*/
void SelectBestEngine::initParam()
{
    this->strImagePath_ = "";
    this->strDetectDate_ = "";
    this->strDetectTime_ = "";
    this->mapIndex_Containers_.clear();
    this->iEndCount_ = 0;
}

void SelectBestEngine::sendWSServer(DetectResultData &detectResultData)
{
    std::string strImage, strImageDir;
    std::string data;
    Json::Value jsonData;

    for (int i = 0; i < detectResultData.vecImage.size(); ++i)
    {
        strImage += detectResultData.vecImage[i];
        if (i < detectResultData.vecImage.size() - 1)
        {
            strImage += ",";
        }
    }
    if (!detectResultData.vecImage.empty())
    {
        LogInfo << " 图片数: " << detectResultData.vecImage.size();
        strImageDir = detectResultData.strDetectDate + "/" + ai_matrix::StringUtil::getins()->replace_all_distinct(detectResultData.strDetectTime, ":", "-") + "/";
    }

    std::string strContainerNo;
    for (int i = 0; i < detectResultData.vecContainerNO.size(); ++i)
    {
        strContainerNo += detectResultData.vecContainerNO[i];
        if (i < detectResultData.vecContainerNO.size() - 1)
        {
            strContainerNo += ",";
        }
    }
    jsonData["detectDate"] = detectResultData.strDetectDate;
    jsonData["detectTime"] = detectResultData.strDetectTime;
    jsonData["containerNo"] = strContainerNo;
    jsonData["images"] = strImage;
    jsonData["imagesDir"] = strImageDir;
    jsonData["status"] = "normal";
    jsonData["id"] = "";
    Json::StreamWriterBuilder jswBuilder;
    std::string strSendData = Json::writeString(jswBuilder, jsonData);
    outputQueMap_[strPort0_]->push(std::static_pointer_cast<std::string>(std::make_shared<std::string>(strSendData)));
}

void SelectBestEngine::sendMinioServer(DetectResultData &detectResultData)
{
    std::shared_ptr<DetectResultData> pDetectResultData = std::make_shared<DetectResultData>();
    *pDetectResultData = detectResultData;
    outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pDetectResultData));
}

void SelectBestEngine::sendSaveCSV(DetectResultData &detectResultData)
{
    std::shared_ptr<DetectResultData> pDetectResultData = std::make_shared<DetectResultData>();
    *pDetectResultData = detectResultData;
    outputQueMap_[strPort2_]->push(std::static_pointer_cast<void>(pDetectResultData));
}

/**
 * 获取最优识别结果
 */
void SelectBestEngine::selectBest()
{
    auto contains = [] (const std::vector<std::string>& vec, std::string value) -> bool {
        return std::find(vec.begin(), vec.end(), value) != vec.end();
    };
    auto vCompare = [](std::string a, std::string b) {
        if (a.size() != b.size()) return 999;

        int count = 0;
        for (int i = 0; i < a.size(); ++i)
        {
            if (a[i] != b[i])
            {
                ++count;
            }
        }
        return count;
    };
    DetectResultData detectResultData;
    detectResultData.strDetectDate = this->strDetectDate_;
    detectResultData.strDetectTime = this->strDetectTime_;

    std::string strAlternativeResult;
    bool bHaveTwoContainer = false;
    for (auto & it_container : this->mapIndex_Containers_) {
        bool bHaveVerify = false;
        std::map<std::string, int> mapContainer_count;
        for (auto &container: it_container.second) {
            if (container.bIsChkFlag) {
                bHaveVerify = true;
                mapContainer_count[container.strNumResult]++;
            }
            if (container.bHaveTwoContainer) bHaveTwoContainer = true;

            std::string strUploadName =
                    std::to_string(container.iFrameId) + "_" + std::to_string(container.iDataSource) + ".jpg";
            detectResultData.vecImage.emplace_back(strUploadName);
        }

        if (bHaveVerify) {
            std::string strBestContainer;
            int count = 0;
            // 取出现次数最高的 且与第一个箱子不一样的
            for (auto &it_max: mapContainer_count) {
                if (it_max.first.empty()) continue;
                if (it_max.second >= count) {
                    count = it_max.second;
                    if (!contains(detectResultData.vecContainerNO, it_max.first)) {
                        strBestContainer = it_max.first;
                        break;
                    }
                }
            }
            if (mapContainer_count.size() > 1)
            {
                for (auto &it_max : mapContainer_count)
                {
                    if (it_max.first != strBestContainer && vCompare(it_max.first, strBestContainer) > 2)
                    {
                        strAlternativeResult = it_max.first;
                    }
                }
            }
            detectResultData.vecContainerNO.emplace_back(strBestContainer);
        } else {
            if (detectResultData.vecContainerNO.size() == 1 && !strAlternativeResult.empty())
            {
                detectResultData.vecContainerNO.emplace_back(strAlternativeResult);
            }
            else
            {
                // 取识别字数最长的
                std::string strBestContainer;
                int iMaxSize = 0;
                for (auto &it_max: mapContainer_count) {
                    if (it_max.first.size() > iMaxSize) {
                        iMaxSize = it_max.first.size();
                        strBestContainer = it_max.first;
                    }
                }
                detectResultData.vecContainerNO.emplace_back(strBestContainer);
            }
        }
    }
    if (bHaveTwoContainer && detectResultData.vecContainerNO.size() < 2)
    {
        detectResultData.vecContainerNO.emplace_back("?");
    }

    // 向其他引擎发送信息
    this->sendWSServer(detectResultData);
    this->sendMinioServer(detectResultData);
    this->sendSaveCSV(detectResultData);
}

APP_ERROR SelectBestEngine::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<VSelectBestData> pVSelectBestData = std::static_pointer_cast<VSelectBestData>(pVoidData0);

        if (pVSelectBestData->bIsEnd)
        {
            if (this->strDetectDate_.empty())
            {
                this->strDetectDate_ = pVSelectBestData->strDetectDate;
                this->strDetectTime_ = pVSelectBestData->strDetectTime;
            }

            LogInfo << " --- >>> " << this->iEndCount_ << "  数据源: " << pVSelectBestData->iDataSource;
            this->iEndCount_++;
            if (!(this->iEndCount_ % this->vecDataSourceConfig_.size()))
            {
                this->selectBest();
                this->initParam();
            }
            continue;
        }
        LogInfo << " --- >>> 有数据  数据源: " << pVSelectBestData->iDataSource;
        if (g_car_type) this->iEndCount_ = 0;

        if (this->strImagePath_.empty())
        {
            this->strDetectDate_ = pVSelectBestData->strDetectDate;
            this->strDetectTime_ = pVSelectBestData->strDetectTime;
            this->strImagePath_ = pVSelectBestData->strDetectDate + "/"
                                  + StringUtil::getins()->replace_all_distinct(pVSelectBestData->strDetectTime, ":", "-")
                                  + "/" + std::to_string(pVSelectBestData->iDataSource) + "/";
        }

        VSelectBestData selectBestData = *pVSelectBestData;

        this->mapIndex_Containers_[selectBestData.iContainerIndex].emplace_back(selectBestData);

    }
    return APP_ERR_OK;
}
