#include "CivOptSchedEngine.h"
#include "CivInpConvertor.h"
#include "GenAlg.h"
#include "FirstOptScheduling.h"
#include "CivPumpHelper.h"
#include "Genome.h"
#include "CivCommonUtils.h"
#include "CivSysLog.h"
#include "CivSchedulingCompute.h"

CivOptSchedEngine::CivOptSchedEngine(const string& uri)
	:mUri(uri),mMutRate(0.45),mCrossRate(0.07), popsize(10)
{
	// 初始化计算

}

bool CivOptSchedEngine::optimalScheduling(int time)
{
	// 计算初始化
	if (!beginCompute())
	{
		return false;
	}
		
	// 开始遗传算法
	std::shared_ptr<OptScheduling> optScheduling(new FirstOptScheduling());

	// 编码转换
	auto minIter = mMinMonitorVals.begin();
	map<string, double> minMonitorVals;
	for (; minIter != mMinMonitorVals.end(); minIter++)
	{
		string code = minIter->first;
		auto szNoIter = find(mMonitorsVec.begin(), mMonitorsVec.end(), code);
		if (szNoIter != mMonitorsVec.end())
		{
			code = *szNoIter;
		}
		minMonitorVals.insert(pair<string, double>(code, minIter->second));
	}

	optScheduling->setMinMonitorsVals(minMonitorVals);

	// 编码转换
	auto maxIter = mMaxMonitorVals.begin();
	map<string, double> maxMonitorVals;
	for (; maxIter != mMaxMonitorVals.end(); maxIter++)
	{
		string code = maxIter->first;
		auto szNoIter = find(mMonitorsVec.begin(), mMonitorsVec.end(), code);
		if (szNoIter != mMonitorsVec.end())
		{
			code = *szNoIter;
		}
		maxMonitorVals.insert(pair<string, double>(code, maxIter->second));
	}
	optScheduling->setMaxMonitorVals(mMaxMonitorVals);

	GenAlg genAlg(optScheduling);
	genAlg.setPumpVec(mPumpVec);

	// 种群初始化
	popsize = 10;
	genAlg.init(popsize, mMutRate, mCrossRate, mGenLength, 0, 1);
	
	// 开始迭代计算
	int index = 0;

	// 迭代次数
	int generation = 20;

	mSchedulingCompute->clearLastVals();
	while (index++ < generation)
	{
		string infoLog = "第" + to_string(index) + "迭代训练开始";
		CivSysLog::getInstance()->info(infoLog, "CivOptSchedEngine", __FUNCTION__);

		// 管网平差计算
		if (index >1)
		{
			double gg = 0.9;
		}
		vector<map<string, float>>  pumpSpeedMapVec;
		genAlg.decoding(pumpSpeedMapVec);

		// 计算种群个体的每个
		size_t mSize = pumpSpeedMapVec.size();
		for (int i = 0; i < mSize; i++)
		{
			map<string, float> pumpSpeedMap = pumpSpeedMapVec[i];
			mSchedulingCompute->updatePumpSpeed(pumpSpeedMap);
			if (!mSchedulingCompute->calculate())
				continue;

			map<string, float>::const_iterator const_iter = pumpSpeedMap.cbegin();

			string logStr = "第" + to_string(i) + "个体：";
			for (; const_iter != pumpSpeedMap.cend(); const_iter++)
			{
				logStr.append(const_iter->first + ":" + to_string(const_iter->second)+"   ");
			}

			// 获取计算的监测点的值
			map<string, double> monitorCalcMapValues;
			mSchedulingCompute->getMonitorsValue(mPeriod, monitorCalcMapValues);

			// 获取消耗的能量值
			float cost = mSchedulingCompute->totalEnergy(mPeriod);
			
			// 计算个体自适度
			double fitness = genAlg.fitnessfunction(cost, monitorCalcMapValues);

			if (fitness >= 1)
				fitness = 0;

			logStr.append(" 适应度值:" + to_string(fitness));
			CivSysLog::getInstance()->info(logStr, "CivOptSchedEngine", __FUNCTION__);

			// 更新个体的自适应度
			genAlg.updateGenomeFitNess(i, fitness);
			
			mSchedulingCompute->clearLastVals();
		}

		// 产生下一代种群
		std::vector<Genome> newGenmeVec;
		genAlg.epoch(newGenmeVec);
	}

	genAlg.calculateBestWorstAvTot();
	Genome genome = genAlg.bestFitness();
	vector<double> genVec = genome.vecGenome;

	// 
	size_t totalGenVec = genVec.size();
	size_t pumpSize = mPumpVec.size();
	if (totalGenVec != pumpSize)
	{
		CivSysLog::getInstance()->error("水泵个数与计算的属性值不匹配", "CivOptSchedEngine", __FUNCTION__);
		return false;
	}
	
	// 水泵，
	string infoStr  = "最优水泵组合值：";
	for (int i = 0; i < totalGenVec; i++)
	{
		infoStr.append(mPumpVec[i] +": " + to_string(genVec[i]) +"  ");
		mPumpBestSpeed.insert(pair<string, double>(mPumpVec[i], genVec[i]));
	}
	infoStr.append(" 最佳适应度：" + to_string(genome.fitness));
	CivSysLog::getInstance()->error(infoStr, "CivOptSchedEngine", __FUNCTION__);

	mSchedulingCompute->clearLastVals();
	// 再做一次水力计算，计算调度后的值
	mSchedulingCompute->updatePumpSpeed(mPumpBestSpeed);
	if (!mSchedulingCompute->calculate())
		return false;

	// 最优调度值
	mSchedulingCompute->getMonitorsValue(mPeriod,mAfterSchedulingResults);

	// 结束计算
	endCompute();

	return true;
}

void CivOptSchedEngine::serializeToInpFile(string& inpName)
{

}

void CivOptSchedEngine::schedulingResultToJson(string& json)
{
	// 水泵:组合
	json.append("{\"水泵状态\":{");

	map<string, float>::iterator iter = mPumpBestSpeed.begin();
	for (;iter!= mPumpBestSpeed.end();iter++)
	{
		// 水泵编号
		string szNo = iter->first;

		// 编码转换
		auto pumpIter = mPumpSzMap.find(szNo);
		if (pumpIter != mPumpSzMap.end())
		{
			szNo = pumpIter->second;
		}

		json.append(szNo + ":" + to_string(iter->second));
		json.append(",");
	}
	json = json.substr(0, json.length() - 1);
	json.append("},");

	// 调度组合
	json.append("\"监测点:\"");

	json.append("{");
	for (auto iter = mBforeSchedulingResults.begin(); iter != mBforeSchedulingResults.end(); iter++)
	{
		string monitorName = iter->first;

		double beforeMonitorVal = iter->second;

		auto afteriter = mAfterSchedulingResults.find(monitorName);
		if (afteriter == mAfterSchedulingResults.end())
			continue;

		double afterMonitorvVal = afteriter->second;

		// 编码替换成code
		auto monitorIter = mMonitorsSnMap.find(monitorName);
		if (monitorIter != mMonitorsSnMap.end())
		{
			monitorName = monitorIter->second;
		}

		json.append("\""+monitorName+"\":[");
		json.append(to_string(beforeMonitorVal));
		json.append(",");
		json.append(to_string(afterMonitorvVal));
		json.append("],");
	}
	json = json.substr(0, json.length() - 1);
	json.append("}");

}

void CivOptSchedEngine::updateMonitorsVals(const map<string, double>& monitorVals)
{
	mCurrentMonitorVals = monitorVals;
}

bool CivOptSchedEngine::beginCompute()
{
	// 转inp文件
	CivInpConvertor convertor(mUri);
	string inpFile = convertor.convertBaseInp();

	mSchedulingCompute = std::make_shared<CivSchedulingCompute>(CivSchedulingCompute::PumpScheduling);
	

	// 获取水泵个数,根据水泵个数确定基因编码长度
	CivPumpHelper pumpHelper(mUri);
	mGenLength = pumpHelper.getPumpNumbers();
	if (mGenLength <= 0)
	{
		CivSysLog::getInstance()->error("CivOptSchedEngine","获取不到水泵",__FUNCTION__);
		return false;
	}
		
	// 获取本点号和code的映射
	map<string, string> snToCodeMap;
	pumpHelper.getMap("本点号", "code", snToCodeMap);

	// 获取本点号集合
	pumpHelper.getPumpSn(mPumpVec, mPumpSzMap);
	pumpHelper.getMonitors(mMonitorsVec,mMonitorsSnMap);

	/*string temp = "{";
	for (int i = 0; i < mMonitorsVec.size(); i++)
	{
		temp.append("\\\"" + mMonitorsVec[i] + "\\\":{\\\"min\\\":20,\\\"max\\\":48},");
	}
	temp = temp.substr(0, temp.length() - 1);
	temp.append("}");*/

	// 构造水力计算对象
	mSchedulingCompute->setMonitors(mMonitorsVec);
	if (!mSchedulingCompute->openFile(inpFile))
	{
		CivSysLog::getInstance()->info(inpFile,"CivOptSchedEngine",__FUNCTION__);
		return false;
	}
	
	// 原始管网计算一次水力，保留调度前的水力计算结果
	if (!mSchedulingCompute->calculate())
		return false;

	// 保存原始管网监测点的模拟值
	mSchedulingCompute->getMonitorsValue(mPeriod, mBforeSchedulingResults);
}

void CivOptSchedEngine::endCompute()
{
	mSchedulingCompute->close();
}

void CivOptSchedEngine::setMonitors(const vector<string>& monitor)
{
	mMonitorsVec = monitor;
}
