#include "CivProjSimulation.h"
#include "CivCommonUtils.h"
#include "epanet2.h"
#include "CivInpConvertor.h"
#include "CivHydrTableHelper.h"

CivProjSimulation::CivProjSimulation(const std::string& uri):mUri(uri)
{
    mRptFile = CivCommonUtils::getExePath() + "\\test.rpt";
    mBinFile = CivCommonUtils::getExePath() + "\\test.bin";
}

CivProjSimulation::~CivProjSimulation()
{

}

bool CivProjSimulation::simulationProj(const std::string& projCode, const std::string& time)
{
    mSimulTime = time;
    mProjCode = projCode;

    // 转inp之前先拓扑维护
    CivHydrTableHelper helper(mUri);
    if (!helper.mainTain())
        return false;

    // 缓存编码和code的映射
    mProjCache.getCodeToSnMap(mUri);

    // 转普通inp文件
    CivInpConvertor conventor(mUri);
    std::string baseInp = conventor.convertNotPorjInp(time);

    // 转方案inp文件
   std::string projInp =  conventor.convertPorjInp(projCode, time);
    
   char baseInpFile[256];
   strcpy(baseInpFile, baseInp.c_str());

   char projInpFile[256];
   strcpy(projInpFile, projInp.c_str());

   if (!projBeforeHydrCompute(baseInpFile))
       return false;

   if (!projHydrCompute(projInpFile))
       return false;

   if (!saveToDb())
       return false;

	return true;
}

bool CivProjSimulation::saveToDb()
{
	return mProjCache.saveToUri(mUri,mSimulTime,mProjCode);
}

bool CivProjSimulation::projBeforeHydrCompute(char* inp)
{
    short hydCode = 1;
    long  t(0), tstep(0);
    int   iTime(0);

    int  errcode = 0;

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

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

    errcode = ENopen(inp, 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;
        }
        // 获取计算结果
        getNodeResult();
        getLinkResult();

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

    ENcloseH();
    ENclose();

    return true;
}

bool CivProjSimulation::projHydrCompute(char* inp)
{
    short hydCode = 1;
    long  t(0), tstep(0);
    int   iTime(0);

    int  errcode = 0;

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

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

    errcode = ENopen(inp, 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;
        }

        // 存储方案模拟结果数据
        getProjNodeResult();
        getProjLinkResult();

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

    ENcloseH();
    ENclose();

    return true;
}

void CivProjSimulation::getProjNodeResult()
{
    // 计算节点
    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;

        NodeResultItem nodeItem;

        ENgetnodeid(i, nodeItem.szNo);// 编号       
        ENgetnodevalue(i, EN_HEAD, &nodeItem.dHead);// 水头 
        mProjCache.addProjNodeHead(nodeItem.szNo, nodeItem.dHead);

        ENgetnodevalue(i, EN_PRESSURE, &nodeItem.dPressure); // 压力 
        mProjCache.addProjNodePressure(nodeItem.szNo, nodeItem.dPressure);
    }
    free(typeCode);
}

void CivProjSimulation::getProjLinkResult()
{
    int  nLinkCount;
    ENgetcount(EN_LINKCOUNT, &nLinkCount);
    int* typeCode = (int*)malloc(sizeof(int));
  
    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);// 流量     

        mProjCache.addProjPipeFlow(linkItem.szNo, linkItem.dFlow);

        ENgetlinkvalue(i, EN_VELOCITY, &linkItem.dVelocity);// 流速   
        mProjCache.addProjPipeVelcoity(linkItem.szNo, linkItem.dVelocity);

        ENgetlinkvalue(i, EN_HEADLOSS, &linkItem.dHeadloss);// 水头损失
        mProjCache.addPipeHeadLoss(linkItem.szNo, linkItem.dHeadloss);

    }
    free(typeCode);
}

void CivProjSimulation::getNodeResult()
{
    // 计算节点
    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;

        ProjNodeResultItem nodeItem;

        ENgetnodeid(i, nodeItem.szNo);// 编号       
        ENgetnodevalue(i, EN_HEAD, &nodeItem.dHead);// 水头  
        ENgetnodevalue(i, EN_PRESSURE, &nodeItem.dPressure); // 压力 

        nodeItem.dDateTime =CivCommonUtils::currentTime(); // 当前时间
        nodeItem.dTime = mSimulTime;
        nodeItem.projCode = mProjCode;
        mProjCache.addNodeItem(nodeItem);
    }
    free(typeCode);
}

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

    for (int i = 1; i <= nLinkCount; i++)
    {
        PorjPipeResultItem 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);// 水头损失

        linkItem.dDateTime = CivCommonUtils::currentTime(); // 当前时间
        linkItem.dTime =mSimulTime ;
        linkItem.projCode = mProjCode;
        mProjCache.addPipeItem(linkItem);
    }
    free(typeCode);
}