#include "CivHydrCompute.h"
#include "CivSimuResStruct.h"
#include "CivCommonUtils.h"
#include "CivDate.h"
#include "CivSysLog.h"

CivHydrCompute::CivHydrCompute()
{
    mInFile = CivCommonUtils::getExePath()+ "\\test.inp";
    mRptFile = CivCommonUtils::getExePath() + "\\test.rpt";
    mBinFile = CivCommonUtils::getExePath() + "\\test.bin";
}

bool CivHydrCompute::qualityCompute()
{
    // 运行水质运算需要先进行水力运算,没有直接采用ENSolveH 是为了考虑减压阀的压力曲线设置
    long  t(0), tstep(0);
    int   iTime(0);

    int  errcode = 0;

    char inpFile[128];
    strcpy_s(inpFile, mInFile.c_str());

    char rptFile[128];
    strcpy_s(rptFile, mRptFile.c_str());

    char binFile[128];
    strcpy_s(binFile, mBinFile.c_str());

    CivSysLog::getInstance()->info("打开inp文件", "CivHydrCompute", __FUNCTION__);
    errcode = ENopen(inpFile, rptFile, binFile);
    if (errcode > 0)
    {
        CivSysLog::getInstance()->error("ENopen 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }

    if (ENopenH() > 0)
    {
        CivSysLog::getInstance()->error("ENopenH 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }

    if (ENinitH(EN_SAVE) > 0)
    {
        CivSysLog::getInstance()->error("ENinitH 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }


    do
    {
        int nLinkCount;
        ENgetcount(EN_LINKCOUNT, &nLinkCount);
        /*for (int i = 1; i <= nLinkCount; i++)
        {
            int linkType;
            char id[128] = "";
            ENgetlinktype(i, &linkType);
            ENgetlinkid(i, id);
        }*/

        errcode = ENrunH(&t);	// errcode > 100 是错误
        if (errcode > 100)
        {
            ENcloseH();
            ENclose();
            return false;
        }

        ENnextH(&tstep);
        iTime++;

        // 获取当前节点和管段数据
        getNodeResult(iTime);
        getLinkResult(iTime);

    } while (tstep > 0);

    ENcloseH();

    // 进行水质分析
    ENopenQ();
    ENinitQ(1);

    t = 0;
    tstep = 0;
    iTime = 0;
    do
    {
        errcode = ENrunQ(&t);	// errcode > 100 是错误
        if (errcode > 100)
        {
            ENcloseQ();
            ENclose();
            return false;
        }
        iTime++;
        // 获取水质模拟结果
        getNodeQuality(iTime);
        getLinkQuality(iTime);

        ENstepQ(&tstep);


    } while (tstep > 0);


    ENcloseQ();
    ENclose();

    CivSysLog::getInstance()->info("ENclose", "CivHydrCompute", __FUNCTION__);
	return true;
}

bool CivHydrCompute::hdyrCompute()
{
    short hydCode = 1;
    long  t(0), tstep(0);
    int   iTime(0);

    int  errcode = 0;
    char inpFile[128];
    strcpy_s(inpFile, mInFile.c_str());

    char rptFile[128];
    strcpy_s(rptFile, mRptFile.c_str());

    char binFile[128];
    strcpy_s(binFile, mBinFile.c_str());

   
    errcode = ENopen(inpFile, rptFile, binFile);

    if (errcode > 0)
    {
        ENclose();
        return false;
    }
    
    if (ENopenH() > 0)
    {
        ENclose();
        return false;
    }

    if (ENinitH(0) > 0)
    {
        ENclose();
        return false;
    }
    float dHStep;
    ENGetVal(4, &dHStep);
    do
    {
        int nLinkCount;
        ENgetcount(EN_LINKCOUNT, &nLinkCount);
        /*for (int i = 1; i <= nLinkCount; i++)
        {
            int linkType;
            char id[128] = "";
            ENgetlinktype(i, &linkType);
            ENgetlinkid(i, id);
        }*/

        if (ENrunH(&t) > 100)	// errcode > 100 是错误
        {
            ENclose();
            return false;
        }

        ENnextH(&tstep);

        // 获取当前节点和管段数据
        getNodeResult(iTime);
        getLinkResult(iTime);

        iTime++;
    } while (tstep > 0);

    ENcloseH();
    ENclose();

    return true;
}

bool CivHydrCompute::chlorineCompute()
{
    // 运行水质运算需要先进行水力运算,没有直接采用ENSolveH 是为了考虑减压阀的压力曲线设置
    long  t(0), tstep(0);
    int   iTime(0);

    int  errcode = 0;

    char inpFile[128];
    strcpy_s(inpFile, mInFile.c_str());

    char rptFile[128];
    strcpy_s(rptFile, mRptFile.c_str());

    char binFile[128];
    strcpy_s(binFile, mBinFile.c_str());

    CivSysLog::getInstance()->info("打开inp文件", "CivHydrCompute", __FUNCTION__);
    errcode = ENopen(inpFile, rptFile, binFile);
    if (errcode > 0)
    {
        CivSysLog::getInstance()->error("ENopen 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }

    if (ENopenH() > 0)
    {
        CivSysLog::getInstance()->error("ENopenH 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }

    if (ENinitH(EN_SAVE) > 0)
    {
        CivSysLog::getInstance()->error("ENinitH 失败", "CivHydrCompute", __FUNCTION__);
        ENclose();
        return false;
    }


    do
    {
        int nLinkCount;
        ENgetcount(EN_LINKCOUNT, &nLinkCount);
        /*for (int i = 1; i <= nLinkCount; i++)
        {
            int linkType;
            char id[128] = "";
            ENgetlinktype(i, &linkType);
            ENgetlinkid(i, id);
        }*/

        errcode = ENrunH(&t);	// errcode > 100 是错误
        if (errcode > 100)
        {
            ENcloseH();
            ENclose();
            return false;
        }

        ENnextH(&tstep);
        iTime++;

    } while (tstep > 0);

    ENcloseH();

    // 进行水质分析
    ENopenQ();
    ENinitQ(1);

    t = 0;
    tstep = 0;
    iTime = 0;
    do
    {
        errcode = ENrunQ(&t);	// errcode > 100 是错误
        if (errcode > 100)
        {
            ENcloseQ();
            ENclose();
            return false;
        }
        iTime++;
        // 获取水质模拟结果
        getNodeChlorine(iTime);
        getLinkChlorine(iTime);

        ENstepQ(&tstep);


    } while (tstep > 0);


    ENcloseQ();
    ENclose();

    CivSysLog::getInstance()->info("ENclose", "CivHydrCompute", __FUNCTION__);
    return true;
}

void CivHydrCompute::dateAndTime(int time,std::string& nowDate,std::string& nowTime)
{
    CivDate civDate;
    nowDate = civDate.getDate();

    int baseTime = CivCommonUtils::currentHour();
    int a = baseTime + time;
    int modulus = a % 24;
    int yu = a / 24;

    if (yu > 0)
    {
        
        civDate.addDate();
        nowDate = civDate.getDate();
        a = modulus;
    }

    if (modulus < 10)
        nowTime = ("0" + std::to_string(a) + ":00:00");
    else
        nowTime = (std::to_string(a) + ":00:00");

    nowTime = nowDate + " " + nowTime;
}

void CivHydrCompute::getNodeResult(short time)
{
    // 计算节点
    int nNodeCount;
    ENgetcount(EN_NODECOUNT, &nNodeCount);
    int* typeCode = (int*)malloc(sizeof(int));

    std::string nowDate;
    std::string nowTime;
    dateAndTime(time, nowDate, nowTime);
    
    for (int i = 1; i <= nNodeCount; i++)
    {     
        ENgetnodetype(i, typeCode);
        if (*typeCode != EN_JUNCTION)
            continue;
   
        NodeResultItem nodeItem;

        ENgetnodeid(i, nodeItem.szNo);// 编号       
        ENgetnodevalue(i, EN_HEAD, &nodeItem.dHead);// 水头 
        ENgetnodevalue(i, EN_PRESSURE, &nodeItem.dPressure); // 压力 
        ENgetnodevalue(i, EN_ELEVATION, &nodeItem.dElevation);// 标高   
        ENgetnodevalue(i, EN_DEMAND, &nodeItem.dDemand);// 实际需水量

        nodeItem.dDate = nowDate;
        nodeItem.dTime = nowTime;
        nodeItem.dModifyTime = CurrentTime;
        mResultCache.addNodeItems(time, nodeItem);
        
    }
    free(typeCode);
}

void CivHydrCompute::getLinkResult(short time)
{
    int  nLinkCount;
    ENgetcount(EN_LINKCOUNT, &nLinkCount);
    int* typeCode = (int*)malloc(sizeof(int));

    std::string nowDate;
    std::string nowTime;
    dateAndTime(time, nowDate, nowTime);

    for (int i = 1; i <= nLinkCount; i++)
    {
        LinkResultItem linkItem;
        ENgetlinktype(i, typeCode);
        if (*typeCode != EN_PIPE)
            continue;
       
        ENgetlinkid(i, linkItem.szNo);  // 编号   
        ENgetlinkvalue(i, EN_FLOW, &linkItem.dFlow);// 流量     
        ENgetlinkvalue(i, EN_VELOCITY, &linkItem.dVelocity);// 流速   
        ENgetlinkvalue(i, EN_HEADLOSS, &linkItem.dHeadloss);// 水头损失
       
        // 状态
        float fState = 0;
        ENgetlinkvalue(i, EN_STATUS, &fState);
        if ((int)fState == 0)
            strcpy_s(linkItem.szStatus, "关闭");
        else
            strcpy_s(linkItem.szStatus, "开启");

        linkItem.dDate = nowDate;
        linkItem.dTime = nowTime;
        linkItem.dModifyTime = CurrentTime;

        // 放到缓存类中 
        mResultCache.addLinkItems(time,linkItem);
    }
    free(typeCode);
}

void CivHydrCompute::getNodeQuality(short time)
{
    int nNodeCount;
    ENgetcount(EN_NODECOUNT, &nNodeCount);

    int* typeCode = (int*)malloc(sizeof(int));
    for (int i = 1; i <= nNodeCount; i++)
    {
        ENgetnodetype(i, typeCode);
        if (*typeCode == EN_JUNCTION)        
        {
            char No[35];
            ENgetnodeid(i, No);// 编号
            float quality;
            ENgetnodevalue(i, EN_QUALITY, &quality); // 水质

            mResultCache.addNodeQuality(quality, time, No);
        }
       
    }
    free(typeCode);
}

void CivHydrCompute::getLinkQuality(short time)
{
    int  nLinkCount;
    ENgetcount(EN_LINKCOUNT, &nLinkCount);
    int* typeCode = (int*)malloc(sizeof(int));
    for (int i = 1; i <= nLinkCount; i++)
    {
        ENgetlinktype(i, typeCode);
        if (*typeCode != EN_PIPE)
            continue;

        char lnkNo[35];  
        ENgetlinkid(i, lnkNo);// 编号
        float quality;     
        ENgetlinkvalue(i, EN_LINKQUAL, &quality);// 水质

        mResultCache.addLinkQuality(quality, time, lnkNo);
    }
    free(typeCode);
}

void CivHydrCompute::getNodeChlorine(short time)
{
    int nNodeCount;
    ENgetcount(EN_NODECOUNT, &nNodeCount);
    int* typeCode = (int*)malloc(sizeof(int));
    for (int i = 1; i <= nNodeCount; i++)
    {

        ENgetnodetype(i, typeCode);
        if (*typeCode != EN_JUNCTION)
            continue;

        char No[35];
        ENgetnodeid(i, No);// 编号
        float quality;
        ENgetnodevalue(i, EN_QUALITY, &quality); // 水质

        mResultCache.addNodeChlorine(quality, time, No);
    }

    free(typeCode);
  
}

void CivHydrCompute::getLinkChlorine(short time)
{
    int  nLinkCount;
    ENgetcount(EN_LINKCOUNT, &nLinkCount);
    int* typeCode = (int*)malloc(sizeof(int));
    for (int i = 1; i <= nLinkCount; i++)
    {
        ENgetlinktype(i, typeCode);
        if (*typeCode != EN_PIPE)
            continue;

        char lnkNo[35];
        ENgetlinkid(i, lnkNo);// 编号
        float quality;
        ENgetlinkvalue(i, EN_LINKQUAL, &quality);// 水质

        mResultCache.addLinkChlorine(quality, time, lnkNo);
    }
    free(typeCode);
}

void CivHydrCompute::saveResult(const std::string& uri)
{
    mResultCache.save(uri);
}

void CivHydrCompute::cacheCodeSn(const std::string& uri)
{
    mResultCache.getCodeToSnMap(uri);
}

void CivHydrCompute::getTrackingResult(const std::string& uri,std::string& jsonResult)
{
    PipeCoords pipeCoords;
    mResultCache.getAllPipeCoords(uri, pipeCoords);

    // 查找
    std::vector<std::vector<std::string>> pipeSns;
    mResultCache.getPipesSnsByQuality(pipeSns);

    jsonResult.append("[");
    int hours = pipeSns.size();
    for (int i = 0; i < hours; i++)
    {
        std::vector<std::string> pipeS = pipeSns[i];
        size_t total = pipeS.size();
        if (total <= 0)
            continue;

        jsonResult.append("[");
        for (int j = 0; j < total; j++)
        {
            std::string sn = pipeS[j];
            PipeCoord pipe = pipeCoords.find(sn)->second;

            jsonResult.append("[[");
            jsonResult.append(pipe.startX);
            jsonResult.append(",");
            jsonResult.append(pipe.startY);
            jsonResult.append("],[");
            jsonResult.append(pipe.endX);
            jsonResult.append(",");
            jsonResult.append(pipe.endY);
            jsonResult.append("]],");
        }
     
        jsonResult = jsonResult.substr(0, jsonResult.length() - 1);
        jsonResult.append("],");
    }
    jsonResult = jsonResult.substr(0, jsonResult.length() - 1);
    jsonResult.append("]");
}

void CivHydrCompute::getNodeItemByInterval(int time, NodeResultItems& nodeItem)
{
    mResultCache.getNodeItemByInterval(time, nodeItem);
}

void CivHydrCompute::getPipeItemByInterval(int time, LinkResultItems& linkItem)
{
    mResultCache.getPipeItemByInterval(time, linkItem);
}