#include "CivInp.h"
#include<time.h>

CivInp::CivInp(TimeUnit timetype):mTimeUnit(timetype)
{
	writeTitles();
}

bool CivInp::writeToFile(const char* fileName)
{
	writeTextStream();
	FILE* file;
	std::string ss;
	if (file = fopen(fileName, "wb"))
	{
		fprintf(file, mTextStream.str().c_str());
		mTextStream.clear();
		fclose(file);
		return true;
	}
	mTextStream.clear();
	return false;
}

void CivInp::writeComponet(const Civitems& items, SectType type)
{
	switch (type)
	{
	case _TITLE:
		break;
	case _JUNCTIONS:
		mJunctionsItems.insert(mJunctionsItems.end(),items.begin(),items.end());
		break;
	case _RESERVOIRS:
		mReservoirsItems.insert(mReservoirsItems.end(), items.begin(), items.end());
		break;
	case _TANKS:
		mTanksItems.insert(mTanksItems.end(), items.begin(), items.end());
		break;
	case _PIPES:
		mPipesItems.insert(mPipesItems.end(), items.begin(), items.end());
		break;
	case _PUMPS:
		mPumpsItems.insert(mPumpsItems.end(), items.begin(), items.end());
		break;
	case _VALVES:
		mValvesItems.insert(mValvesItems.end(), items.begin(), items.end());
		break;
	case _CONTROLS:
		mControlsItems.insert(mControlsItems.end(), items.begin(), items.end());
		break;
	case _RULES:
		mRulesItems.insert(mRulesItems.end(), items.begin(), items.end());
		break;
	case _DEMANDS:
		mDemandsItems.insert(mDemandsItems.end(), items.begin(), items.end());
		break;
	case _SOURCES:
		mSourceItems.insert(mSourceItems.end(), items.begin(), items.end());
		break;
	case _EMITTERS:
		mEmittersItems.insert(mEmittersItems.end(), items.begin(), items.end());
		break;
	case _PATTERNS:
		mPatternsItems.insert(mPatternsItems.end(), items.begin(), items.end());
		break;
	case _CURVES:
		mCurvesItems.insert(mCurvesItems.end(), items.begin(), items.end());
		break;
	case _QUALITY:
		mQualityItems.insert(mQualityItems.end(), items.begin(), items.end());
		break;
	case _STATUS:
		mStatusItems.insert(mStatusItems.end(), items.begin(), items.end());
		break;
	case _ROUGHNESS:
		break;
	case _ENERGY:
		mEnergyItems.insert(mEnergyItems.end(), items.begin(), items.end());
		break;
	case _REACTIONS:
		mReactionItems.insert(mReactionItems.end(), items.begin(), items.end());
		break;
	case _MIXING:
		mMixingItems.insert(mMixingItems.end(), items.begin(), items.end());
		break;
	case _REPORT:
		mReportItems.insert(mReportItems.end(), items.begin(), items.end());
		break;
	case _TIMES:
		mTImesItems.insert(mTImesItems.end(), items.begin(), items.end());
		break;
	case _OPTIONS:
		mOptionsItems.insert(mOptionsItems.end(), items.begin(), items.end());
		break;
	case _COORDS:
		mCoordinatesItems.insert(mCoordinatesItems.end(), items.begin(), items.end());
		break;
	case _VERTICES:
		mVerticesItems.insert(mVerticesItems.end(), items.begin(), items.end());
		break;
	case _LABELS:
		mLabelsItems.insert(mLabelsItems.end(), items.begin(), items.end());
		break;
	case _BACKDROP:
		mBackdropItems.insert(mBackdropItems.end(), items.begin(), items.end());
		break;
	case _TAGS:
		mTagsItems.insert(mTagsItems.end(), items.begin(), items.end());
		break;
	case _END:
		break;
	default:
		break;
	}
}

void CivInp::writeTextStream()
{
	writeJunctions(mJunctionsItems);
	writeReservoirs(mReservoirsItems);
	writeTanks(mTanksItems);
	writePipes(mPipesItems);
	writePumps(mPumpsItems);
	writeValves(mValvesItems);
	writeTags(mTagsItems);
	writeDemand(mDemandsItems);
	writeStatus(mStatusItems);
	writePatterns(mPatternsItems);
	writeCurves(mCurvesItems);
	writeControls(mControlsItems);
	writeRules(mRulesItems);
	writeEnergy(mEnergyItems);
	writeEmitters(mEmittersItems);
	writeQuality(mQualityItems);
	writeSources(mSourceItems);
	writeReactions(mReactionItems);
	writeMixing(mMixingItems);
	writeTimes(mTImesItems);
	writeOptions(mOptionsItems);
	writeCoordinates(mCoordinatesItems);
	writeVertices(mVerticesItems);
	writeBackdrop(mBackdropItems);
	writeEnd();
}

void CivInp::writeSources(Civitems items)
{
	writeString("[SOURCES]");  // 先写入标签
	writeString(";Node            	Type        	Quality     	Pattern");
	writeItems(items);

	writeString("");
}

void CivInp::writeTimes(Civitems items)
{
	writeString("[TIMES]");  // 先写入标签
	writeString(";Tank            	Model");
	writeItems(items);

	writeString("");
}

void CivInp::writeMixing(Civitems items)
{
	writeString("[MIXING]");  // 先写入标签
	writeString(";Tank            	Model");
	writeItems(items);

	writeString("");
}

void CivInp::writeEmitters(Civitems items)
{
	writeString("[EMITTERS]");  // 先写入标签
	writeString(";Junction        	Coefficient");
	writeItems(items);

	writeString("");
}

void CivInp::writeQuality(Civitems items)
{
	writeString("[QUALITY]");  // 先写入标签
	writeString(";Node            	InitQual");
	writeItems(items);

	writeString("");
}

void CivInp::writeEnergy(Civitems items)
{
	writeString("[ENERGY]");  // 先写入标签
	writeItems(items);

	writeString("");
}

void CivInp::writeReactions(Civitems items)
{
	writeString("[REACTIONS]");  // 先写入标签
	writeString(";Type     	Pipe/Tank       	Coefficient");
	writeItems(items);

	writeString("");
}

void CivInp::writeRules(Civitems items)
{
	writeString("[RULES]");  // 先写入标签
	writeItems(items);

	writeString("");
}

void CivInp::writeCurves(Civitems items)
{
	writeString("[CURVES]");  // 先写入标签
	writeString(";ID              	X-Value     	Y-Value");
	writeItems(items);

	writeString("");
}

void CivInp::writeControls(Civitems items)
{
	writeString("[CONTROLS]");  // 先写入标签
	writeItems(items);

	writeString("");
}

void CivInp::writeStatus(Civitems items)
{
	writeString("[STATUS]");  // 先写入标签
	writeString(";ID              	Status/Setting");
	writeItems(items);

	writeString("");
}

void CivInp::writeTags(Civitems items)
{
	writeString("[TAGS]");  // 先写入标签
	writeItems(items);

	writeString("");
}

void CivInp::writeTitles()
{
	writeString("[TITLE]");  // 先写入标签
	writeString("Scenario: Base");
	writeString("Date:");
	writeString("");
	writeString("");
}

void CivInp::writeJunctions(Civitems items)
{
	writeString("[JUNCTIONS]");
	writeString(";ID              	Elev        	Demand      	Pattern    ");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeItems(const Civitems& items)
{
	size_t rows = items.size();
	for (int i = 0; i < rows; i++)
	{
		CivItem item = items[i];
		size_t itemSize = item.size();
		int index = 0;
		std::string itemStr = item[0] + "  ";
		while ((++index) < itemSize)
			itemStr +=( item[index] + "   ");
		writeString(itemStr);
	}
}

void CivInp::writePipes(Civitems items)
{
	writeString("[PIPES]");
	writeString(";ID  Node1   Node2   Length   Diameter  	Roughness  MinorLoss  Status");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeTanks(Civitems items)
{
	writeString("[TANKS]");
	writeString("; ID              	Elevation   	InitLevel   	MinLevel    	MaxLevel    	Diameter    	MinVol      	VolCurve");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeReservoirs(Civitems items)
{
	writeString("[RESERVOIRS]");
	writeString(";ID              	Head        	Pattern ");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writePumps(Civitems items)
{
	writeString("[PUMPS]");
	writeString(";ID              	Node1           	Node2           	Parameters");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeValves(Civitems items)
{
	writeString("[VALVES]");
	writeString(";ID              	Node1           	Node2           	Diameter    	Type	Setting     	MinorLoss  ");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeCoordinates(Civitems items)
{
	writeString("[COORDINATES]");
	writeString(";Node            	X-Coord         	Y-Coord");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeLabels(Civitems items)
{
	writeString("[LABELS]");
	writeString(";X-Coord           Y-Coord          Label & Anchor Node");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeVertices(Civitems items)
{
	writeString("[VERTICES]");
	writeString(";Link            	X-Coord         	Y-Coord");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeDemand(Civitems items)
{
	writeString("[DEMANDS]");
	writeString(";Junction        	Demand      	Pattern         	Category");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeOptions(const Civitems& items)
{
	writeString("[OPTIONS]");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writePatterns(Civitems items)
{
	writeString("[PATTERNS]");
	writeString(";ID              	Multipliers");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeBackdrop(Civitems items)
{
	writeString("[BACKDROP]");
	writeItems(items);

	writeString("");
	writeString("");
}

void CivInp::writeEnd()
{
	writeString("[END]");
}

void CivInp::writeString(const std::string& s)
{
	mTextStream << s << "\n";
}

void CivInp::setPattern(StrQuote pId, std::vector<Str> pValue)
{

}

void CivInp::setOption(Options options, const std::map<std::string, std::string>& others)
{
	// 流量被表达的单位：
	CivItem unitItem;
	unitItem.push_back("UNITS");

	Str unit = "LPS";
	switch (options.units)
	{
	case Options::UNITS::AFD:
		unit = "AFD";
		break;
	case Options::UNITS::CFS:
		unit = "CFS";
		break;
	case Options::UNITS::CMG:
		unit = "CMG";
		break;
	case Options::UNITS::CMH:
		unit = "CMH";
		break;
	case Options::UNITS::GPM:
		unit = "GPM";
		break;
	case Options::UNITS::IMGD:
		unit = "IMGD";
		break;
	case Options::UNITS::LPM:
		unit = "LPM";
		break;
	case Options::UNITS::LPS:
		unit = "LPS";
		break;
	case Options::UNITS::MGD:
		unit = "MGD";
		break;
	case Options::UNITS::MLD:
		unit = "MLD";
		break;
	default:
		break;
	}
	unitItem.push_back(unit);
	mOptionsItems.push_back(unitItem);

	CivItem headLossItem;
	headLossItem.push_back("HEADLOSS");

	Str lossValue = "H-W";
	switch (options.headLoss)
	{
	case Options::HEADLOSS::HW:
		lossValue = "H-W";
		break;
	case Options::HEADLOSS::CM:
		lossValue = "C-M";
		break;
	case Options::HEADLOSS::DW:
		lossValue = "D-W";
		break;
	default:
		break;
	}
	headLossItem.push_back(lossValue);
	mOptionsItems.push_back(headLossItem);


	// 水质
	CivItem qualityItem;
	qualityItem.push_back("QUALITY");
	Str qualityValue = "NONE";

	switch (options.quality)
	{
	case Options::QUALITY::NONE:
		qualityValue = "NONE";
		break;
	case Options::QUALITY::AGE:
		qualityValue = "AGE";
		break;
	case Options::QUALITY::CHEMICAL:
		qualityValue = "CHEMICAL  mg/L";
		break;
	case Options::QUALITY::TRACE:
		qualityValue = "TRACE";
		break;
	default:
		break;
	}
	qualityItem.push_back(qualityValue);
	mOptionsItems.push_back(qualityItem);
	mOptionsItems.push_back({ "ACCURACY",options.ACCURACY });
	mOptionsItems.push_back({ "Pattern" ,options.Pattern});
	mOptionsItems.push_back({ "Unbalanced" ,options.UNBALANCED});
	mOptionsItems.push_back({ "Demand Multiplier",options.DEMANDMULTIPLIER });
	mOptionsItems.push_back({ "Emitter Exponent",options.EMITTEREXPONENT });
	mOptionsItems.push_back({ "Diffusivity",options.DIFFUSIVITY });
	mOptionsItems.push_back({ "Trials",options.TRIALS });
	mOptionsItems.push_back({ "Viscosity",options.VISCOSITY });
	mOptionsItems.push_back({ "SPECIFIC GRAVITY",options.SpecificGravity });

	// 附加选项
	for (auto iter = others.cbegin(); iter != others.cend(); iter++)
	{
		mOptionsItems.push_back({ iter->first,iter->second });
	}
}

void CivInp::setDuration(int duration)
{
	Str timeUnit = getTimeUnit(mTimeUnit);
	mTImesItems.push_back({ "DURATION",std::to_string(duration),timeUnit });
}

void CivInp::setTimestep(Str type, int step)
{
	Str timeUnit = getTimeUnit(mTimeUnit);
	mTImesItems.push_back({ type+"  TIMESTEP",std::to_string(step),timeUnit });
}

void CivInp::setTimeStart(Str type, int step)
{
	Str timeUnit = getTimeUnit(mTimeUnit);
	mTImesItems.push_back({ type + "  START",std::to_string(step),timeUnit });
}

void CivInp::setTimeOthers(Str type, Str val)
{
	mTImesItems.push_back({ type ,val });
}

Str CivInp::getTimeUnit(TimeUnit timetype)
{
	Str timeUnit = "";
	switch (timetype)
	{
	case TimeUnit::SECONDS:
		timeUnit = "SEC";
		break;
	case TimeUnit::HOURS:
		timeUnit = "";
		break;
	case TimeUnit::MINUTES:
		timeUnit = "MIN";
		break;
	case TimeUnit::DAYS:
		timeUnit = "DAYS";
		break;
	default:
		break;
	}

	return timeUnit;
}