#include "CivInpDbHelper.h"
#include "CivTableFields.h"
#include "CivConnection.h"
#include "CivPgDbConnection.h"

#include <algorithm>

CivInpDbHelper::CivInpDbHelper(const std::string& uri)
	:CivInpHelperAbs(uri)
{
	mCondtion = "1=1 ";
	isDelayTime = true;
}

CivInpDbHelper::~CivInpDbHelper()
{
}

bool CivInpDbHelper::getNode(CivNode& node)
{
	JunctionTable nodeTableFields;
	std::vector<std::string> fields;

	fields.push_back(nodeTableFields.sn);
	fields.push_back(nodeTableFields.elev);
	fields.push_back(nodeTableFields.baseDemand);
	fields.push_back(nodeTableFields.demandPattern);

	std::vector<std::map<std::string,std::string>> resultVector;	
	mDbConn->query(PIPENODE, fields, resultVector, mCondtion);

	// 编辑包装结果
	size_t total = resultVector.size();
	for (int i = 0; i < total; i++)
	{
		std::map<std::string, std::string> map = resultVector[i];
		CivNode::NodeTable nodeTable;

		nodeTable.ID = map.find(nodeTableFields.sn)->second;
		nodeTable.Elev = map.find(nodeTableFields.elev)->second;

		std::string patternID = map.find(nodeTableFields.demandPattern)->second;
		std::string demand = map.find(nodeTableFields.baseDemand)->second;

		// 处理延时模拟情况
		handleDelayPattern(demand, patternID, nodeTable.Demand, nodeTable.PatternId);
		
		node.addItem(nodeTable);
	}

	// 添加处理的阀门产生的节点
	size_t size = mNodeVec.size();
	for (int i = 0; i < size; i++)
	{
		node.addItem(mNodeVec[i]);
	}
	return true;
}

bool CivInpDbHelper::getPipe(CivPipe& pipes)
{
	PipeTable pipeTable;

	std::vector<std::string> fields;
	fields.push_back(pipeTable.snNo); 
	fields.push_back(pipeTable.startPoint);
	fields.push_back(pipeTable.endPoint); 
	fields.push_back(pipeTable.length); 
	fields.push_back(pipeTable.diameter); 
	fields.push_back(pipeTable.friction); 
	fields.push_back(pipeTable.localLoss);
	fields.push_back(pipeTable.status);
	fields.push_back(pipeTable.code);
	
	std::vector<std::map<std::string, std::string>> resultVector;

	std::string condition = "\"from_layer\" not in ('阀门','水泵' ) and \"to_layer\" not in ('阀门','水泵' )";
	mDbConn->query(PIPELINE, fields, resultVector, condition);

	size_t total = resultVector.size();
    for (int i = 0; i < total; i++)
    {
        CivPipe::PipesTable pipe;

		std::map<std::string, std::string> map = resultVector[i];

		pipe.ID = map.find(pipeTable.snNo)->second;
		pipe.Node1 = map.find(pipeTable.startPoint)->second;
		pipe.Node2 = map.find(pipeTable.endPoint)->second;
		pipe.Length = map.find(pipeTable.length)->second;
		pipe.Diameter = map.find(pipeTable.diameter)->second;
		pipe.Roughness = map.find(pipeTable.friction)->second;
		pipe.MinorLoss = map.find(pipeTable.localLoss)->second;
		pipe.Status = map.find(pipeTable.status)->second;
		pipe.code = map.find(pipeTable.code)->second;
		pipes.addItem(pipe);
    }
	// 构造的管段
	size_t size = mPipesVec.size();
	for (int i = 0; i < size; i++)
	{
		pipes.addItem(mPipesVec[i]);
	}
	return true;
}

bool CivInpDbHelper::getTank(CivTank& tanks)
{
	TankTable tankTable;

	std::vector<std::string> fields;

	fields.push_back(tankTable.sn);
	fields.push_back(tankTable.elev);
	fields.push_back(tankTable.initLevel);
	fields.push_back(tankTable.minLevel);
	fields.push_back(tankTable.maxLevel);
	fields.push_back(tankTable.diametor);
	fields.push_back(tankTable.minVolume);
	fields.push_back(tankTable.volumeCurve);

	std::vector<std::map<std::string, std::string>> resultVector;
	mDbConn->query(TANK, fields, resultVector, mCondtion);

	size_t total = resultVector.size();
	for (int i = 0; i < total; i++)
	{
		CivTank::TankTable tank;
		std::map<std::string, std::string>map = resultVector[i];

		tank.ID = map.find(tankTable.sn)->second;
		tank.Elev = map.find(tankTable.elev)->second;
		tank.InitLevel = map.find(tankTable.initLevel)->second;
		tank.MinLevel = map.find(tankTable.minLevel)->second;
		tank.MaxLevel = map.find(tankTable.maxLevel)->second;
		tank.Diameter = map.find(tankTable.diametor)->second;
		tank.MinVol = map.find(tankTable.minVolume)->second;
		tank.VolCurve = map.find(tankTable.volumeCurve)->second;
		
		tanks.addItem(tank);
	}
	return true;
}

bool CivInpDbHelper::getValve(CivValve& valves)
{
	size_t size = mValuvesVec.size();
	for (int i = 0; i < size; i++)
	{
		valves.addItem(mValuvesVec[i]);
	}
	return true;
}

bool CivInpDbHelper::getPumps(CivPumps& pumps)
{
	PumpTable pmTable;
	std::vector<std::string> fields;

	fields.push_back(pmTable.sn);
	fields.push_back(pmTable.startPoint);
	fields.push_back(pmTable.endPoint);
	fields.push_back(pmTable.headCurve);
	fields.push_back(pmTable.ratio);
	fields.push_back(pmTable.power);

	std::vector<std::map<std::string, std::string>> resultVector;
	mDbConn->query(PUMP, fields, resultVector, mCondtion);
	
	size_t totals = resultVector.size();
	for (int i = 0; i < totals; i++)
	{
		CivPumps::PumpTable pump;
		std::map<std::string, std::string> map = resultVector[i];

		pump.ID = map.find(pmTable.sn)->second;
		pump.Node1 = map.find(pmTable.startPoint)->second;
		pump.Node2 = map.find(pmTable.endPoint)->second;
		std::string param;
		
		std::string curve = map.find(pmTable.headCurve)->second;
		if (curve != "")
			param.append("head " + curve);

		std::string power = map.find(pmTable.power)->second;
		if (power != "")
			param.append(" power " + power);
	
		std::string speedRatio = map.find(pmTable.ratio)->second;
		if (speedRatio != "")
			param.append(" SPEED " + speedRatio);

		pump.Parameters = param;
		pumps.addItem(pump);
	}
	return true;
}

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

	std::vector<std::string> fields;

	fields.push_back(restemTable.sn);
	fields.push_back(restemTable.totalHead);
	fields.push_back(restemTable.headPattern);

	std::vector<std::map<std::string, std::string>> resultVector;
	mDbConn->query(RESIVOIR, fields, resultVector, mCondtion);

	size_t totals = resultVector.size();
	for (int i = 0; i < totals; i++)
	{
		CivReservoirs::ReservoirsTable resTable;
		std::map<std::string, std::string> map = resultVector[i];

		resTable.ID = map.find(restemTable.sn)->second;
		resTable.Head = map.find(restemTable.totalHead)->second;
		resTable.Pattern = map.find(restemTable.headPattern)->second;

		reservoirs.addItem(resTable);
	}
	return true;
}

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

	std::vector<std::string> fields;

	fields.push_back(nodeTable.sn);
	fields.push_back(nodeTable.xCoord);
	fields.push_back(nodeTable.yCoord);
	fields.push_back(nodeTable.code);

	std::vector<std::map<std::string, std::string>> resultVector;
	mDbConn->query(PIPENODE, fields, resultVector, mCondtion);
	mDbConn->query(TANK, fields, resultVector, mCondtion);
	mDbConn->query(RESIVOIR, fields, resultVector, mCondtion);

	size_t totals = resultVector.size();
	for (int i = 0; i < totals; i++)
	{
		CivCoordinates::CoordTable coordTable;
		std::map<std::string, std::string> map = resultVector[i];

		coordTable.ID = map.find(fields[0])->second;
		coordTable.XCoord = map.find(fields[1])->second;
		coordTable.YCoord = map.find(fields[2])->second;
		coordTable.code = map.find(nodeTable.code)->second;

		coord.addItem(coordTable);
	}
	// 加入阀门处理的节点坐标
	size_t size = mCoords.size();
	for (int i = 0; i < size; i++)
	{
		coord.addItem(mCoords[i]);
	}

	return true;
}

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

	std::vector<std::string> fields;

	fields.push_back(nodeTable.sn);
	fields.push_back(nodeTable.initQuality);
	fields.push_back(nodeTable.chlorine);

	std::vector<std::map<std::string, std::string>> resultVector;
	mDbConn->query(PIPENODE, fields, resultVector, mCondtion);
	mDbConn->query(RESIVOIR, fields, resultVector,mCondtion);
	mDbConn->query(TANK, fields, resultVector, mCondtion);

	size_t totals = resultVector.size();
	for (int i = 0; i < totals; i++)
	{
		CivQuality::QualityTable quliTable;

		std::map<std::string, std::string> map = resultVector[i];
		quliTable.ID = map.find(nodeTable.sn)->second;
		switch (mQualityType)
		{
		
		case Chlorine:
			quliTable.InitQuality = map.find(nodeTable.chlorine)->second;
			break;
		case Age:
		default:
			quliTable.InitQuality = map.find(nodeTable.initQuality)->second;
			break;
		}

		quality.addItem(quliTable);
	}

	return true;
}

bool CivInpDbHelper::getStatus(CivStatus& status)
{
	// 阀门状态值，
	size_t statuSize = mStatusVec.size();
	for (int i = 0; i < statuSize; i++)
	{
		status.addItem(mStatusVec[i]);
	}
	
	return true;
}

void CivInpDbHelper::handlePump()
{
	
}

bool CivInpDbHelper::handleValves2()
{
	std::string sql = splicingSql("节点");

	if (!mDbConn->execSql(sql))
	{
		std::string error = mDbConn->getLastError();
		return false;
	}

	// 查询与阀门关联的管段，和节点
	std::vector<std::map<std::string, std::string>> valvesPipes;
	mDbConn->queryResult(valvesPipes);

	// 非
	std::string sql2 = splicingSql("水库","0","1");
	if (!mDbConn->execSql(sql2))
	{
		std::string error = mDbConn->getLastError();
		return false;
	}

	mDbConn->queryResult(valvesPipes);

	// 总个数
	size_t total = valvesPipes.size();
	for (int i = 0; i < total; i++)
	{
		std::map<std::string,std::string> valvePipe = valvesPipes[i];

		std::string vaSzNo = valvePipe.find("本点号")->second;
		std::string vaXcoord = valvePipe.find("阀门横坐标")->second;
		std::string vaYcoord = valvePipe.find("阀门纵坐标")->second;
		std::string vaStatus = valvePipe.find("阀门固定状态")->second;
		std::string vaType = valvePipe.find("阀门类型")->second;
		std::string vaSetting = valvePipe.find("阀门设置")->second;
		std::string vaLoss = valvePipe.find("阀门水损系数")->second;
		std::string upperPipeSzNo = valvePipe.find("上游管段编号")->second;
		std::string upperPipeCode = valvePipe.find("上游管段code")->second;
		std::string upperPipeLength = valvePipe.find("上游管长")->second;
		std::string upperPipeDiametor = valvePipe.find("上游管径")->second;
		std::string upperPipeFriction = valvePipe.find("下游管段摩阻系数")->second;
		std::string upperNodeSz = valvePipe.find("上游节点")->second;
		std::string upperNodeHeight = valvePipe.find("上游节点高程")->second;
		std::string upperNodePattern = valvePipe.find("上游节点蓄水量模式")->second;
		std::string upperNodeDemand = valvePipe.find("上游节点基本需水量")->second;
		std::string upperNodeXcoord = valvePipe.find("上游节点横坐标")->second;
		std::string upperNodeYcoord = valvePipe.find("上游节点纵坐标")->second;
		std::string upperNodeQuality = valvePipe.find("上游节点初始水质")->second;
		std::string donwPipeSz = valvePipe.find("下游管段编号")->second;
		std::string donwPipeCode = valvePipe.find("下游管段code")->second;
		std::string donwPipeLength = valvePipe.find("下游管段管长")->second;
		std::string donwPipeDiametor = valvePipe.find("下游管段管径")->second;
		std::string downPipeFraction = valvePipe.find("下游管段摩阻系数")->second;
		std::string donwNodeSz = valvePipe.find("下游节点")->second;
		std::string donwNodeHeight = valvePipe.find("下游节点高程")->second;
		std::string donwNodePattern = valvePipe.find("下游节点蓄水量模式")->second;
		std::string donwNodeDemand = valvePipe.find("下游节点基本需水量")->second;
		std::string donwNodeXcoord = valvePipe.find("下游节点横坐标")->second;
		std::string donwNodeYcoord = valvePipe.find("下游节点纵坐标")->second;
		std::string donwNodeQuality = valvePipe.find("下游节点初始水质")->second;

		// 判断阀门类型
		std::string upperVaType = vaType;
		std::transform(vaType.begin(), vaType.begin(), vaType.end(), ::toupper);

		// 阀门需要构造两个虚拟节点，两个节点尽可能接近
		CivNode::NodeTable startNodeTable;
		CivCoordinates::CoordTable startNodeCoord; // 节点坐标

		// 节点信息
		startNodeTable.ID = "VUP"+vaSzNo;
		startNodeTable.Elev = upperNodeHeight;
		startNodeTable.Demand = "0";

		// 两点之间直线
		double vupperXcoord = (atof(upperNodeXcoord.c_str()) - atof(vaXcoord.c_str()))/10+atof(vaXcoord.c_str());
		double vupperYcoord = (atof(upperNodeYcoord.c_str()) - atof(vaYcoord.c_str()))/10 + atof(vaYcoord.c_str());

		// 节点坐标
		startNodeCoord.ID = "VUP" + vaSzNo;
		startNodeCoord.XCoord = std::to_string(vupperXcoord);
		startNodeCoord.YCoord = std::to_string(vupperYcoord);
		
		// 终止节点构造
		CivNode::NodeTable endNodeTable; // 终止节点
		CivCoordinates::CoordTable endNodeCoord; // 终止节点坐标

		// 终止节点信息
		endNodeTable.ID = "VDW" + vaSzNo;
		endNodeTable.Elev = upperNodeHeight;
		endNodeTable.Demand = "0";

		mNodeVec.push_back(startNodeTable);
		mCoords.push_back(startNodeCoord);

		// 两点之间直线
		double vdownXcoord = (atof(donwNodeXcoord.c_str()) - atof(vaXcoord.c_str())) / 10 + atof(vaXcoord.c_str());
		double vdownYcoord = (atof(donwNodeYcoord.c_str()) - atof(vaYcoord.c_str())) / 10 + atof(vaYcoord.c_str());

		// 终止节点坐标信息
		endNodeCoord.ID = "VDW" + vaSzNo;
		endNodeCoord.XCoord = std::to_string(vdownXcoord);
		endNodeCoord.YCoord = std::to_string(vdownYcoord);

		mNodeVec.push_back(endNodeTable);
		mCoords.push_back(endNodeCoord);

		// 构造上游管段的
		CivPipe::PipesTable upperPipeTable;
		CivPipe::PipesTable downPipeTable;

		// 上游管段属性
		upperPipeTable.code = upperPipeCode;
		upperPipeTable.ID = upperPipeSzNo;
		upperPipeTable.Node1 = upperNodeSz;
		upperPipeTable.Node2 = startNodeTable.ID;
		upperPipeTable.Length = upperPipeLength;
		upperPipeTable.Diameter = upperPipeDiametor;
		upperPipeTable.Roughness = upperPipeFriction;
		upperPipeTable.Status = "Open";
		upperPipeTable.MinorLoss = vaLoss;

		// 下游管段属性
		downPipeTable.code = donwPipeCode;
		downPipeTable.ID = donwPipeSz;
		downPipeTable.Node1 =  endNodeTable.ID;
		downPipeTable.Node2 = donwNodeSz;
		downPipeTable.Length = donwPipeLength;
		downPipeTable.Diameter = donwPipeDiametor;
		downPipeTable.Roughness = upperPipeFriction;
		downPipeTable.Status = "Open";
		downPipeTable.MinorLoss = vaLoss;

		mPipesVec.push_back(downPipeTable);
		mPipesVec.push_back(upperPipeTable);
		
		// 普通阀门等效于管段
		if (upperVaType == "BV")
		{
			// 构造一条虚拟管段
			CivPipe::PipesTable vPipeTable;
			vPipeTable.ID = "VG"+vaSzNo;
			vPipeTable.Node1 = startNodeTable.ID;
			vPipeTable.Node2 = endNodeTable.ID;
			vPipeTable.Length = donwPipeLength;
			vPipeTable.Diameter = donwPipeDiametor;
			vPipeTable.Roughness = upperPipeFriction;
			vPipeTable.Status = vaStatus;
			vPipeTable.MinorLoss = vaLoss;

			mPipesVec.push_back(vPipeTable);

		}
		else
		{
			// 阀门
			CivValve::ValveTable valveTable;
			valveTable.ID = vaSzNo;
			valveTable.Node1 = startNodeTable.ID;
			valveTable.Node2 = endNodeTable.ID;
			valveTable.Diameter = upperPipeDiametor;
			valveTable.Type = vaType;
			valveTable.Setting =vaSetting;
			valveTable.MinorLoss = vaLoss; 

			mValuvesVec.push_back(valveTable);
			
			// 阀门状态组件
			CivStatus::StatusTable statusTable;
			statusTable.ID = vaSzNo;
			statusTable.Setting = vaStatus;

			mStatusVec.push_back(statusTable);
		}
	}
}

void CivInpDbHelper::handleValve()
{
	handleValves2();
	return;	
}

std::string CivInpDbHelper::splicingSql(const std::string& rightTable, const std::string& demandName , const std::string& demandPattern)
{

	std::string upcondition;
	std::string downcondition;
	if (rightTable == "节点")
	{
		upcondition = "pipe.\"from_code\" = node.\"code\"  AND pipe.\"to_code\" = junc.\"code\"";
		downcondition = "pipe.\"to_code\" = node.\"code\" AND pipe.\"from_code\" = junc.\"code\"";
	}
	else
	{
		upcondition = "(pipe.\"to_code\" = node.\"code\"\
				AND pipe.\"from_code\" = junc.\"code\") or\
			(pipe.\"from_code\" = node.\"code\"\
				AND pipe.\"to_code\" = junc.\"code\")";

		downcondition = "(pipe.\"to_code\" = node.\"code\"\
				AND pipe.\"from_code\" = junc.\"code\") or\
			(pipe.\"from_code\" = node.\"code\"\
				AND pipe.\"to_code\" = junc.\"code\")";
	}
	std::string sql2 = "SELECT  A.*, B.*  FROM (SELECT\
			node.\"本点号\",\
			node.\"横坐标\" AS 阀门横坐标,\
			node.\"纵坐标\" AS 阀门纵坐标,\
			node.\"固定状态\" AS 阀门固定状态,\
			node.\"类型\" AS 阀门类型,\
			node.\"设置\" AS 阀门设置,\
			node.\"水损系数\" AS 阀门水损系数,\
			pipe.编号 AS 上游管段编号,\
			pipe.\"管长\" AS 上游管长,\
			pipe.\"管径\" AS 上游管径,\
			pipe.\"摩阻系数\" AS 上游管段摩阻系数,\
			junc.\"本点号\" AS 上游节点,\
			junc.\"code\" AS 上游节点code,\
			junc.\"高程\" AS 上游节点高程,\
			"+ demandPattern + " AS 上游节点蓄水量模式,\
			"+demandName + "  AS 上游节点基本需水量,\
			junc.\"横坐标\" AS 上游节点横坐标,\
			junc.\"纵坐标\" AS 上游节点纵坐标,\
			junc.\"初始水质\" AS 上游节点初始水质\
			FROM\
			阀门 AS node, 管段 AS pipe, "+rightTable+" AS junc\
			WHERE "+ upcondition+") A,\
		(\
			SELECT\
			pipe.编号 AS 下游管段编号,\
			pipe.\"管长\" AS 下游管段管长,\
			pipe.\"管径\" AS 下游管段管径,\
			pipe.\"摩阻系数\" AS 下游管段摩阻系数,\
			node.\"本点号\",\
			junc.\"本点号\" AS 下游节点,\
			junc.\"code\" AS 上游节点code,\
			junc.\"高程\" AS 下游节点高程,\
			junc.\"需水量模式\" AS 下游节点蓄水量模式,\
			junc.\"基本需水量\" AS 下游节点基本需水量,\
			junc.\"横坐标\" AS 下游节点横坐标,\
			junc.\"纵坐标\" AS 下游节点纵坐标,\
			junc.\"初始水质\" AS 下游节点初始水质\
			FROM\
			阀门 AS node, 管段 AS pipe, 节点 AS junc\
			WHERE "+downcondition+") B\
		WHERE\
		A.\"本点号\" = b.\"本点号\"";

	return sql2;
}