#include "EnergyLoad_Calc.h"

//Note: Big Ladder on output : 
// https://bigladdersoftware.com/epx/docs/8-2/input-output-reference/output-table-summaryreports.html#outputtablesummaryreports
//Note : EPW file explained here : 
// https://bigladdersoftware.com/epx/docs/8-3/auxiliary-programs/energyplus-weather-file-epw-data-dictionary.html
//Note : Command Line here : 
// https://github.com/NREL/EnergyPlus/blob/develop/doc/running-energyplus-from-command-line.md


//file_EP_Exists function declared 
bool file_EP_Exists(const string& filePath);

//EnergyLoad function initalizes ....
//Note: Consider refactor to call the model twice, with and without trees and then read E+ output to determine load savings
void EnergyLoad_Calc::EnergyLoad(Inputs* input, WeatherProcessor* WeatherPro)
{
	//CreateFile_EPW creates CreateFile_EPW_obj as instance of class CreateFile_EPW, needed for non-static classes
    CreateFile_EPW CreateFile_EPW_obj;
	//CreateFile_IDF creates CreateFile_IDF_obj as instance of class CreateFile_IDF, needed for non-static classes
	CreateFile_IDF CreateFile_IDF_obj;

	//CreateFile_EPW::Create_EPW_file called, sending input folder
    CreateFile_EPW_obj.Create_EPW_file(input);

	//Tree_ID_Count defined as CoolBuildingNumericalParams["Tree_ID_Count"]
	int Tree_ID_Count = input->CoolBuildingNumericalParams["Tree_ID_Count"];
	//numberScenarios initialized to 1, default base case
	int numberScenarios = 1;
	//Flag_CoolBuilding_ScenarioActive initialized
	int Flag_CoolBuilding_ScenarioActive = 0;

	//If SimulationStringParams map contains the key Flag_CoolBuilding_ScenarioActive then enter
	if (input->SimulationScenarios.count("Flag_CoolBuilding_ScenarioActive")) {
		Flag_CoolBuilding_ScenarioActive = input->SimulationScenarios["Flag_CoolBuilding_ScenarioActive"];
		//If Flag_CoolBuilding_ScenarioActive not 0 or 1 set to 0
		if (Flag_CoolBuilding_ScenarioActive != 0 && Flag_CoolBuilding_ScenarioActive != 1) {
			//Flag_CoolBuilding_ScenarioActivedefault setting is 0, no change
			Flag_CoolBuilding_ScenarioActive = 0;
		}
	}
	//If Flag_CoolBuilding_ScenarioActive > 0 and Tree_ID_Count > 0 then simulate tree and no-tree scenarios
	if (Flag_CoolBuilding_ScenarioActive > 0 && Tree_ID_Count > 0) {
		numberScenarios = 2;
	}

	//For loop of scenario_ID in numberScenarios, with scenario_ID 1 = NoTree, and 2 = Tree
	for (int scenario_ID = 1; scenario_ID <= numberScenarios; ++scenario_ID) {
		//scenarioCoolBuilding is NoTree or Tree based on the value of scenario_ID and Tree_ID_Count
		string scenarioCoolBuilding = "Unknown";

		//If (scenario_ID = 1 and numberScenarios = 2) or Tree_ID_Count = 0 then simulate no-tree
		if ((scenario_ID == 1 && numberScenarios == 2) || Tree_ID_Count <= 0) {
			scenarioCoolBuilding = "NoTree";
		}
		//Else If scenario_ID == 2 or (numberScenarios = 1 and Tree_ID_Count > 0) then simulate tree
		else if (scenario_ID == 2 || (numberScenarios == 1 && Tree_ID_Count > 0)) {
			scenarioCoolBuilding = "Tree";
		}

		//CreateFile_EPW::Create_IDF_file called, sending input folder
		CreateFile_IDF_obj.Create_IDF_file(input, scenarioCoolBuilding);

		//cout of i-Tree CoolBuilding scenario
		cout << "i-Tree CoolBuilding scenario: " << scenarioCoolBuilding << endl;

		//outputDirectory = input->SimulationStringParams["OutputFolder_Path"]
		string outputDirectory = input->SimulationStringParams["OutputFolder_Path"];
		//prefix_OutputFile_base defined for "a_EP_" + scenarioCoolBuilding
		string prefix_OutputFile_base = "a_Scenario_" + scenarioCoolBuilding + "_";

		//commandPrompt_Argument = "energyplus.exe -p " + prefix_OutputFile_base + " -w " + outputDirectory + "iTreeWeatherRadiation.epw" + outputDirectory + "iTreeEnergyLoad.idf" " -d " + outputDirectory;
		//Note: Computer PATH environment variable must contain directory with energyplus.exe, Energy+.idd, and other functions
		//Note: -p defines prefix to all output files; 
		//Note: -w defines weather EPW input; 
		//Note: -r defines scenario IDF input; 
		//Note: -d defines output folder
		//Note: -m run EPMacro prior to simulation
		//Note: -x runs expandobjects.exe prior to simulation
		//Note: Whitespace needs to precede -w, -r, -d, -m, -x, -p
		//Note: Command Line info: https://energyplus.readthedocs.io/en/latest/essentials/essentials.html
		//Note: Command Line info: https://github.com/NREL/EnergyPlus/blob/develop/doc/readthedocs/sphinx/essentials/essentials.rst
		//Note: Command Line info: https://github.com/NREL/EnergyPlus/blob/develop/doc/running-energyplus-from-command-line.md

		//commandPrompt_Argument initialized as ""
		string commandPrompt_Argument = "";

		//If CoolBuildingStringParams["EnergyPlus_HVAC"] == "IdealLoadsAirSystem" then call EnergyPlus
		if (input->CoolBuildingStringParams["EnergyPlus_HVAC"] == "IdealLoadsAirSystem") {
			commandPrompt_Argument = "energyplus.exe -p " +
				prefix_OutputFile_base +
				" -w " + outputDirectory + "iTreeWeatherRadiation.epw " +
				outputDirectory + "iTreeCoolBuilding_" + scenarioCoolBuilding + ".idf" +
				" -d " + outputDirectory;
		}
		//If CoolBuildingStringParams["EnergyPlus_HVAC"] == "HVACTemplate:Zone:PTHP" then call EnergyPlus with macro expandobjects
		else if (input->CoolBuildingStringParams["EnergyPlus_HVAC"] == "HVACTemplate:Zone:PTHP") {
			commandPrompt_Argument = "energyplus.exe -m -x -p " +
				prefix_OutputFile_base +
				" -w " + outputDirectory + "iTreeWeatherRadiation.epw " +
				outputDirectory + "iTreeCoolBuilding_" + scenarioCoolBuilding + ".idf" +
				" -d " + outputDirectory;
		}

		//Suppress command prompt messages by redirecting stderr to stdout, and stdout to nowhere.
		string suppressOutput = "";
		#if defined(__linux__) || defined(__gnu_linux__)
			suppressOutput = " > /dev/null 2>&1";
		#endif
		#if defined(_WIN32) || defined(_WIN64) || defined(_WIN16)
			suppressOutput = " > nul 2>&1";
		#endif

		//commandPrompt_suppressOutput defined to add suppressOutput to commandPrompt_Argument
		string commandPrompt_suppressOutput = commandPrompt_Argument + suppressOutput;

		//system(commandPrompt_suppressOutput.c_str()) sends commandPrompt_Argument 
		//Note: result contains a 0 if program executes properly
		int result = system(commandPrompt_suppressOutput.c_str());
		
		//cout Pausing information to run the program
		cout << "Pausing for 3 seconds..." << endl;
		pause_for_seconds(3);
		cout << "Resuming now." << endl;

		//filesToDelete vector contains EnergyPlus output that can be deleted as the default 
		//Note: Best practices is to print the .err file, even if there are no errors 
		vector<string> filesToDelete = {
			outputDirectory + prefix_OutputFile_base + "out.audit",
			outputDirectory + prefix_OutputFile_base + "out.bnd",
			outputDirectory + prefix_OutputFile_base + "out.eio",
			outputDirectory + prefix_OutputFile_base + "out.end",
			outputDirectory + prefix_OutputFile_base + "out.err",
			//Optional: outputDirectory + prefix_OutputFile_base + "out.eso",
			outputDirectory + prefix_OutputFile_base + "out.mdd",
			outputDirectory + prefix_OutputFile_base + "out.mtd",
			outputDirectory + prefix_OutputFile_base + "out.mtr",
			outputDirectory + prefix_OutputFile_base + "out.mvi",
			//Optional: outputDirectory + prefix_OutputFile_base + "out.rdd",
			outputDirectory + prefix_OutputFile_base + "out.rvi",
			outputDirectory + prefix_OutputFile_base + "out.rvaudit",
			outputDirectory + prefix_OutputFile_base + "out.shd",
			outputDirectory + prefix_OutputFile_base + "shading.csv",
		};

		//For loop auto detect through the files and delete if they exist
		//Note: Consider refactor to check if out.err file exists and write ReadMe_error.txt to explain 
		//Note: .err file may contain: Warning ** Temperature out of range [-100. to 200.] (PsyPsatFnTemp)
		//Note: It is caused by wet-bulb calculation error in EnergyPlus when dry bulb temperature and humidity ratio are low
		for (const auto& file : filesToDelete) {
			if (file_EP_Exists(file)) {
				//remove (file.c_str()) function to remove file in filesToDelete
				remove(file.c_str());
			}
		}
		// Check the result
		if (result != 0) {
			cerr << "\n" << endl;
			cerr << "Warning: CoolBuilding could not fully execute a command line call to EnergyPlus.exe." << endl;
			cerr << "Aborting: This warning triggers the CoolBuilding simulation to abort." << endl;
			cerr << "Explanation: EnergyPlus.exe may not be accessible, or the .idf or .epw files may contain errors." << endl;
			cerr << "Correction: Check that all components of this commmand line works on your system:" << endl;
			cerr << commandPrompt_Argument << endl;
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}
	}
	//end numberScenarios loop
}
//bool file_EP_Exists function to check if a file exists using <fstream>
bool file_EP_Exists(const string& filePath) {
	ifstream file(filePath);
	return file.good();
}

//pause_for_seconds function to allow energyplus.exe to complete run
void EnergyLoad_Calc::pause_for_seconds(int seconds) {
	auto start_time = chrono::steady_clock::now();
	while (chrono::steady_clock::now() - start_time < chrono::seconds(seconds)) {
		// Busy wait
	}
}