#include "CivPgConn.h"
#include "CivCommonUtils.h"

CivPgConn::CivPgConn(char* uri)
	:mUri(uri), CivDbConn()
{
	mConn = NULL;
	mResult = NULL;
}

CivPgConn::~CivPgConn()
{

}

bool CivPgConn::open()
{
    mConn = PQconnectdb(mUri);
    if (PQstatus(mConn) == CONNECTION_BAD) {
        mConn = NULL;
        PQfinish(mConn);
        return false;
    }
    mIsOpen = true;
    return true;
}

void CivPgConn::close()
{
    if (mConn != NULL)
        PQfinish(mConn);
    mIsOpen = false;
}

bool CivPgConn::tableExist(StrQuote tableName)
{
    char sql[256] = "select count(*) from pg_class where relname = '";
    strcat_s(sql, tableName.c_str());
    strcat_s(sql, "'");

    if (!execSql(sql))
        return false;

    char* res = PQgetvalue(mResult, 0, 0);
    PQclear(mResult);
    int number = atoi(res);

    return number > 0 ? true : false;
}

bool CivPgConn::execSql(Str sql)
{
    if (mConn == nullptr)
        return false;

    if (sql.empty())
        return false;

    mResult = PQexec(mConn, sql.c_str());
    char* error = PQresultErrorMessage(mResult);
    std::string errorStr = error;

    if (!errorStr.empty())
    {
        mLastError = error;
        PQclear(mResult);
        return false;
    }

    return true;
}

bool CivPgConn::getNode(CivNode& node)
{
    
    CivJunctionTableTemp::JunctionTable nodeTable;

    char sql[256] = "select ";
    strcat_s(sql, nodeTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.elev.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.pattern.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.demand.c_str());
    strcat_s(sql, " from 节点");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivNode::NodeTable nodeTable;
        nodeTable.ID = PQgetvalue(mResult, i, 0);
        nodeTable.Elev = PQgetvalue(mResult, i, 1);
        nodeTable.Demand = PQgetvalue(mResult, i, 2);
        nodeTable.PatternId = PQgetvalue(mResult, i, 3);
        node.addItem(nodeTable);
    }
   PQclear(mResult);
    return true;
}

bool CivPgConn::getPipe(CivPipe& pipe)
{
    CivPipeTableTemp::PipeTable pipeTable;

    //;ID              	Node1           	Node2           	Length      	Diameter    	Roughness   	MinorLoss   	Status
    char sql[256] = "select ";
    strcat_s(sql, pipeTable.snNo.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.lastPoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.length.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.diameter.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.friction.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.localHeadLoss.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pipeTable.status.c_str());
    strcat_s(sql, " from  管段");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivPipe::PipesTable pipeTable;
        pipeTable.ID = PQgetvalue(mResult, i, 0);
        pipeTable.Node1 = PQgetvalue(mResult, i, 1);
        pipeTable.Node2 = PQgetvalue(mResult, i, 2);
        pipeTable.Length = PQgetvalue(mResult, i, 3);
        pipeTable.Diameter = PQgetvalue(mResult, i, 4);
        pipeTable.Roughness = PQgetvalue(mResult, i, 5);
        pipeTable.MinorLoss = PQgetvalue(mResult, i, 6);
        pipeTable.Status = PQgetvalue(mResult, i, 7);

        pipe.addItem(pipeTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getTank(CivTank& tank)
{
    CivTankTableTemp::TankTable tankTable;

    //;ID              	Elevation   	InitLevel   	MinLevel    	MaxLevel    	Diameter    	MinVol      	VolCurve
    char sql[512] = "select ";
    strcat_s(sql, tankTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.elev.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.initLevel.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.lowLevel.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.highLevel.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.diametor.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.capacity.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, tankTable.volCurve.c_str());
    strcat_s(sql, " from  水池");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivTank::TankTable tankTable;
        tankTable.ID= PQgetvalue(mResult, i, 0);
        tankTable.Elev = PQgetvalue(mResult, i, 1);
        tankTable.InitLevel= PQgetvalue(mResult, i, 2);
        tankTable.MinLevel= PQgetvalue(mResult, i, 3);
        tankTable.MaxLevel= PQgetvalue(mResult, i, 4);
        tankTable.Diameter= PQgetvalue(mResult, i, 5);
        tankTable.MinVol= PQgetvalue(mResult, i, 6);
        tankTable.VolCurve= PQgetvalue(mResult, i, 7);
     
        tank.addItem(tankTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getValve(CivValve& valve)
{
    CivValveTableTemp::ValveTable vaveTable;

    //;ID              	Node1           	Node2           	Length      	Diameter    	Roughness   	MinorLoss   	Status
    char sql[256] = "select ";
    strcat_s(sql, vaveTable.id.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.startPoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.endPoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.diameter.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.type.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.setting.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, vaveTable.loss.c_str());
    strcat_s(sql, " from  阀门");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivValve::ValveTable vaveTable;
        vaveTable.ID = PQgetvalue(mResult, i, 0);
        vaveTable.Node1 = PQgetvalue(mResult, i, 1);
        vaveTable.Node2 = PQgetvalue(mResult, i, 2);
        vaveTable.Diameter= PQgetvalue(mResult, i, 3);
        vaveTable.Type = PQgetvalue(mResult, i, 4);
        vaveTable.Setting = PQgetvalue(mResult, i, 5);
        vaveTable.MinorLoss = PQgetvalue(mResult, i, 6);
    
        valve.addItem(vaveTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getPumps(CivPumps& pump)
{
    CivPumpTableTemp::PumpTable pmTable;

    //;ID              	Node1           	Node2           	Length      	Diameter    	Roughness   	MinorLoss   	Status
    char sql[256] = "select ";
    strcat_s(sql, pmTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pmTable.startPoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pmTable.endPoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, pmTable.headCurve.c_str());
    strcat_s(sql, " from  水泵");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivPumps::PumpTable pumpTable;
        pumpTable.ID = PQgetvalue(mResult, i, 0);
        pumpTable.Node1 = PQgetvalue(mResult, i, 1);
        pumpTable.Node2 = PQgetvalue(mResult, i, 2);
        pumpTable.Parameters = PQgetvalue(mResult, i, 3);
      
        pump.addItem(pumpTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getReservoirs(CivReservoirs& reservoirs)
{
    CivResourcesTableTemp::ResourcesTable restemTable;

    //;ID              	Head        	Pattern     
    char sql[512] = "select ";
    strcat_s(sql, restemTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, restemTable.head.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, restemTable.headPattern.c_str());
    strcat_s(sql, " from  public.\"__pattern__\"");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivReservoirs::ReservoirsTable resTable;
        resTable.ID = PQgetvalue(mResult, i, 0);
        resTable.Head = PQgetvalue(mResult, i, 1);
        resTable.Pattern = PQgetvalue(mResult, i, 2);
     
        reservoirs.addItem(resTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getEmitters(CivEmitters& emitter)
{
    return true;
}

bool CivPgConn::getCoordinates(CivCoordinates& coord)
{
    CivJunctionTableTemp::JunctionTable nodeTable;

    char sql[256] = "select ";
    strcat_s(sql, nodeTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.xCoord.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.yCoord.c_str());
    strcat_s(sql, " from 节点");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivCoordinates::CoordTable coordTable;
        nodeTable.ID = PQgetvalue(mResult, i, 0);
        coordTable.XCoord = PQgetvalue(mResult, i, 1);
        coordTable.YCoord = PQgetvalue(mResult, i, 2);
        
        coord.addItem(coordTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getMixing(CivMixing& mixing)
{
    return true;
}

bool CivPgConn::getParameter(std::vector<CivParameter>& params)
{
    CivParametorTableTemp::ParametorTable restemTable;

    char sql[512] = "select ";
    strcat_s(sql, restemTable.name.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, restemTable.val.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, restemTable.type.c_str());
    strcat_s(sql, " from  public.\"__parameter__\"");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    std::map<std::string, std::vector<CivParameter::ParamTable>> tempMap;
    CivParameter::ParamTable resTable;
    for (int i = 0; i < rows; i++)
    {
        CivParameter::ParamTable pTable;
        pTable.name = PQgetvalue(mResult, i, 0);
        pTable.val = PQgetvalue(mResult, i, 1);

        char* type = PQgetvalue(mResult, i, 1);
        tempMap[type].push_back(pTable);
    }
    // 遍历临时存储的数据拼接参数对象
    for (auto iter = tempMap.begin(); iter != tempMap.end(); iter++)
    {
        CivParameter param;
        std::string type = iter->first;
        std::vector<CivParameter::ParamTable> paramTables = iter->second;

        param.setType(type);

        int total = paramTables.size();
        for (int i = 0; i < total; i++)
            param.addItem(paramTables[i]);
       
        params.push_back(param);
    }
    PQclear(mResult);

    return true;
}

bool CivPgConn::getPatterns(CivPatterns& patterns)
{
    CivPatternTableTemp::PatternTable patternTable;

    char sql[512] = "select ";
    strcat_s(sql, patternTable.Name.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, patternTable.time.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, patternTable.Value.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, patternTable.type.c_str());
    strcat_s(sql, " from  public.\"__pattern__\"");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    std::map<std::string, std::vector<std::string>> typeMap;
    for (int i = 0; i < rows; i++)
    {
        
       char* val  = PQgetvalue(mResult, i, 2);
       char* type = PQgetvalue(mResult, i, 3);

       typeMap[type].push_back(val);
    }
   
    for (auto iter = typeMap.begin(); iter != typeMap.end(); iter++)
    {
        CivPatterns::PatternTable pTable;
        pTable.name = iter->first;
        
        std::vector<std::string> valVec = iter->second;
        int total = valVec.size();
        // 拼接字符串
        char value[512] = "";
        for (int i = 0; i < total; i++)
        {
            strcat_s(value, valVec[i].c_str());
            strcat_s(value, "  ");
        }
        pTable.val = value;

        patterns.addItem(pTable);
    }
    PQclear(mResult);

    return true;
}

bool CivPgConn::getCurves(CivCurves& curves)
{
    CivCurveTableTemp::CurveTable curveTable;

    char sql[512] = "select ";
    strcat_s(sql, curveTable.Label.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, curveTable.XCoord.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, curveTable.YCoord.c_str());
    strcat_s(sql, " from  public.\"__curve__\"");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivCurves::CurvesTable cTable;
        cTable.ID = PQgetvalue(mResult, i, 0);
        cTable.XCoord = PQgetvalue(mResult, i, 1);
        cTable.YCoord =  PQgetvalue(mResult, i,2);
        curves.addItem(cTable);
    }
    PQclear(mResult);
    return true;
}   

bool CivPgConn::getDemands(CivDemands& demands)
{
    return true;
}

bool CivPgConn::getSources(CivSources& sources)
{
    return true;
}

bool CivPgConn::getStatus(CivStatus& status)
{
    return true;
}

bool CivPgConn::getQuality(CivQuality& quality)
{
    CivJunctionTableTemp::JunctionTable nodeTable;

    char sql[256] = "select ";
    strcat_s(sql, nodeTable.thePoint.c_str());
    strcat_s(sql, ",");
    strcat_s(sql, nodeTable.initQuality.c_str());
    strcat_s(sql, " from 节点");

    std::string utf8Sql = TransUTFCoding(sql);
    if (!execSql(utf8Sql))
        return false;

    int rows = PQntuples(mResult);
    int columns = PQnfields(mResult);
    for (int i = 0; i < rows; i++)
    {
        CivQuality::QualityTable quliTable;
        quliTable.ID = PQgetvalue(mResult, i, 0);
        quliTable.InitQuality = PQgetvalue(mResult, i, 1);
   
        quality.addItem(quliTable);
    }
    PQclear(mResult);
    return true;
}

bool CivPgConn::getLabels(CivLabels& labels)
{
    return true;
}

bool CivPgConn::getTags(CivTags& tags)
{
    return true;
}