#include "RoutedRunoff_TimeSeries.h"
#include <math.h>
#include <fstream>
#include <vector>
#include <iostream>
#include <numeric>
#include <string>

//RoutedRunoff_TimeSeries::ScalingRunoffDepth_WritingOutput function scales routed runoff depths (and hence volumes) to match the depth of unrouted water
void RoutedRunoff_TimeSeries::ScalingRunoffDepth_WritingOutput(Inputs* input)
{
	double ratio_unRouted_to_Routed_Impervious = 0.0;
	double ratio_unRouted_to_Routed_Pervious = 0.0;
	double ratio_unRouted_to_Routed_Water = 0.0;
	double ratio_unRouted_to_Routed_Subsurface = 0.0;
	double ratio_unRouted_to_Routed_Total = 0.0;
	double CA_m2;

	//CA_m2 (m2) is catchment area, defined the same for Model equals StatisticalHydro or SpatialTemperatureHydro
	//Note: Optionally, define CA_m2 using sum or average of exact value of map pixel Area_m2 (m2), w input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID] and input->RepoDict["Counter_SimulatedUnit"];
	CA_m2 = input->SimulationNumericalParams["CatchmentArea_m2"];

	string file_path;
	//file_path contains directory and file name
	file_path = input->SimulationStringParams["OutputFolder_Path"] + "TimeSeries_Runoff_and_RunoffRouted_Catchment_m.csv";
	//ofstream{file_path} opens file for output
	ofstream outfile_RunoffVariables_m(file_path);
	if (!outfile_RunoffVariables_m.good()) { return; }
	outfile_RunoffVariables_m.precision(6);
	outfile_RunoffVariables_m.setf(ios::showpoint);

	//file_path contains directory and file name
	file_path = input->SimulationStringParams["OutputFolder_Path"] + "TimeSeries_Runoff_and_RunoffRouted_Catchment_m3.csv";
	//ofstream{file_path} opens file for output
	ofstream outfile_RunoffVariables_m3(file_path);
	if (!outfile_RunoffVariables_m3.good()) { return; }
	outfile_RunoffVariables_m3.precision(6);
	outfile_RunoffVariables_m3.setf(ios::showpoint);

	//Write header to outfile_RunoffVariables_m 
	outfile_RunoffVariables_m << "YYYYMMDD"
		<< "," << "HH:MM:SS"
		<< "," << "Precipitation_Rain_m"
		<< "," << "Precipitation_Snow_WaterEquivalent_m"
		<< "," << "Runoff_All_Catchment_m"
		<< "," << "Runoff_Surface_Catchment_m"
		<< "," << "Runoff_Subsurface_Catchment_m"
		<< "," << "Runoff_Impervious_Catchment_m"
		<< "," << "Runoff_Water_Catchment_m"
		<< "," << "Runoff_Pervious_Catchment_m"
		<< "," << "Runoff_All_R_Catchment_m"
		<< "," << "Runoff_Surface_R_Catchment_m"
		<< "," << "Runoff_Subsurface_R_Catchment_m"
		<< "," << "Runoff_Impervious_R_Catchment_m"
		<< "," << "Runoff_Water_R_Catchment_m"
		<< "," << "Runoff_Pervious_R_Catchment_m"
		<< endl;

	//Write header to outfile_RunoffVariables_m3 
	outfile_RunoffVariables_m3 << "YYYYMMDD"
		<< "," << "HH:MM:SS"
		<< "," << "Precipitation_Rain_m3"
		<< "," << "Precipitation_Snow_WaterEquivalent_m3"
		<< "," << "Runoff_All_Catchment_m3"
		<< "," << "Runoff_Surface_Catchment_m3"
		<< "," << "Runoff_Subsurface_Catchment_m3"
		<< "," << "Runoff_Impervious_Catchment_m3"
		<< "," << "Runoff_Water_Catchment_m3"
		<< "," << "Runoff_Pervious_Catchment_m3"
		<< "," << "Runoff_All_R_Catchment_m3"
		<< "," << "Runoff_Surface_R_Catchment_m3"
		<< "," << "Runoff_Subsurface_R_Catchment_m3"
		<< "," << "Runoff_Impervious_R_Catchment_m3"
		<< "," << "Runoff_Water_R_Catchment_m3"
		<< "," << "Runoff_Pervious_R_Catchment_m3"
		<< endl;

	//Compute scaling ratios to adjust the routed runoff such that it becomes the same total depth as unrouted runoff
	//Note: Unrouted runoff is considered correct, not potentially corrupted by routing algorithm
	//Note: Multiplication of routed runoff by the scaling ratio, which is unrouted / routed, will ensure both runoff types are same total depths
	//Note: Theory with volumes, calling adjusted value normalized: Q_r_normalized (timeStep) = (Q_nr_total_Volume / Q_r_total_Volume) * Q_r (timeStep)
	ratio_unRouted_to_Routed_Impervious = input->SafeDivide(input->RepoDict["Runoff_Impervious_Catchment_m3"] / CA_m2, input->RepoDict["Runoff_Impervious_R_m"]);
	//Create scaling ratio to normalize total routed runoff to total unrouted runoff
	ratio_unRouted_to_Routed_Pervious = input->SafeDivide(input->RepoDict["Runoff_Pervious_Catchment_m3"] / CA_m2, input->RepoDict["Runoff_Pervious_R_m"]);
	//Create scaling ratio to normalize total routed runoff to total unrouted runoff
	ratio_unRouted_to_Routed_Water = input->SafeDivide(input->RepoDict["Runoff_Water_Catchment_m3"] / CA_m2, input->RepoDict["Runoff_Water_R_m"]);
	//Create scaling ratio to normalize total routed runoff to total unrouted runoff
	ratio_unRouted_to_Routed_Subsurface = input->SafeDivide(input->RepoDict["Runoff_Subsurface_Catchment_m3"] / CA_m2, input->RepoDict["Runoff_Subsurface_R_m"]);
	//Create scaling ratio to normalize total routed runoff to total unrouted runoff
	ratio_unRouted_to_Routed_Total = input->SafeDivide(input->RepoDict["Runoff_Catchment_m3"] / CA_m2, input->RepoDict["Runoff_R_m"]);

	//Clear the scalar variables for new values
	input->RepoDict["Runoff_Impervious_R_m"] = 0.0;
	input->RepoDict["Runoff_Pervious_R_m"] = 0.0;
	input->RepoDict["Runoff_Water_R_m"] = 0.0;
	input->RepoDict["Runoff_Subsurface_R_m"] = 0.0;
	input->RepoDict["Runoff_R_m"] = 0.0;

	//Loop through all time steps in simulation, where SimulationTimePeriod_timeSteps
	for (int timeStep = 0; timeStep < input->SimulationTimePeriod_timeSteps; ++timeStep) {

		//DCIAQi_Routed_unscaled_m (m) is runoff depth from input vector at timeStep
		double DCIAQi_Routed_unscaled_m = input->DCIAQi_Routed_m[timeStep];
		//DCIAQi_Routed_scaled_m (m) is product of DCIAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Impervious
		double DCIAQi_Routed_scaled_m = DCIAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Impervious;
		//DCIAQi_Routed_m (m) vector value for position at timeStep becomes scaled runoff
		//input->DCIAQi_Routed_m[timeStep] = DCIAQi_Routed_scaled_m;
		input->DCIAQi_Routed_m.at(timeStep) = DCIAQi_Routed_scaled_m;

		//PAQi_Routed_unscaled_m (m) is runoff depth from input vector at timeStep
		double PAQi_Routed_unscaled_m = input->PAQi_Routed_m[timeStep];
		//PAQi_Routed_scaled_m (m) is product of PAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Pervious
		double PAQi_Routed_scaled_m = PAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Pervious;
		//PAQi_Routed_m (m) vector value for position at timeStep becomes scaled runoff
		input->PAQi_Routed_m.at(timeStep) = PAQi_Routed_scaled_m;

		//WAQi_Routed_unscaled_m (m) is runoff depth from input vector at timeStep
		double WAQi_Routed_unscaled_m = input->WAQi_Routed_m[timeStep];
		//WAQi_Routed_scaled_m (m) is product of WAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Water
		double WAQi_Routed_scaled_m = WAQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Water;
		//WAQi_Routed_m (m) vector value for position at timeStep becomes scaled runoff
		input->WAQi_Routed_m.at(timeStep) = WAQi_Routed_scaled_m;

		//SubQi_Routed_unscaled_m (m) is runoff depth from input vector at timeStep
		double SubQi_Routed_unscaled_m = input->SubQi_Routed_m[timeStep];
		//SubQi_Routed_scaled_m (m) is product of SubQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Subsurface
		double SubQi_Routed_scaled_m = SubQi_Routed_unscaled_m * ratio_unRouted_to_Routed_Subsurface;
		//SubQi_Routed_m (m) vector value for position at timeStep becomes scaled runoff
		input->SubQi_Routed_m.at(timeStep) = SubQi_Routed_scaled_m;

		//Qi_Routed_unscaled_m (m) is runoff depth from input vector at timeStep
		double Qi_Routed_unscaled_m = input->Qi_Routed_m[timeStep];
		//Qi_Routed_scaled_m (m) is product of Qi_Routed_unscaled_m * ratio_unRouted_to_Routed_Total
		double Qi_Routed_scaled_m = Qi_Routed_unscaled_m * ratio_unRouted_to_Routed_Total;
		//Qi_Routed_m (m) vector value for position at timeStep becomes scaled runoff
		input->Qi_Routed_m.at(timeStep) = Qi_Routed_scaled_m;

		//SurfQi_Routed_m (m) vector value is sum of all surface runoff terms
		input->SurfQi_Routed_m.at(timeStep) = DCIAQi_Routed_scaled_m + PAQi_Routed_scaled_m + WAQi_Routed_scaled_m;

		//Store total catchment routed runoff depth (m) as sum of vector values
		//Runoff_Impervious_R_m (m) increased by DCIAQi_Routed_m
		input->RepoDict["Runoff_Impervious_R_m"] = input->RepoDict["Runoff_Impervious_R_m"] + input->DCIAQi_Routed_m[timeStep];
		//Runoff_Pervious_R_m (m) increased by PAQi_Routed_m
		input->RepoDict["Runoff_Pervious_R_m"] = input->RepoDict["Runoff_Pervious_R_m"] + input->PAQi_Routed_m[timeStep];
		//Runoff_Water_R_m (m) increased by PAQi_Routed_m
		input->RepoDict["Runoff_Water_R_m"] = input->RepoDict["Runoff_Water_R_m"] + input->WAQi_Routed_m[timeStep];
		//Runoff_Surface_R_m (m) increased by SurfQi_Routed_m
		input->RepoDict["Runoff_Surface_R_m"] = input->RepoDict["Runoff_Surface_R_m"] + input->SurfQi_Routed_m[timeStep];
		//Runoff_Subsurface_R_m (m) increased by SubQi_Routed_m
		input->RepoDict["Runoff_Subsurface_R_m"] = input->RepoDict["Runoff_Subsurface_R_m"] + input->SubQi_Routed_m[timeStep];
		//Runoff_R_m (m) increased by Qi_Routed_m
		input->RepoDict["Runoff_R_m"] = input->RepoDict["Runoff_R_m"] + input->Qi_Routed_m[timeStep];

		//Write catchment unrouted and routed runoff depth (m) to output
		outfile_RunoffVariables_m << input->SimulationDate_Output_GD[timeStep]
			<< "," << input->SimulationTime_Output_HMS[timeStep]
			<< "," << input->Rain_m[timeStep]
			<< "," << input->Snow_m[timeStep]
			<< "," << input->Qi_m[timeStep]
			<< "," << input->SurfQi_m[timeStep]
			<< "," << input->SubQi_m[timeStep]
			<< "," << input->DCIAQi_m[timeStep]
			<< "," << input->WAQi_m[timeStep]
			<< "," << input->PAQi_m[timeStep]
			<< "," << input->Qi_Routed_m[timeStep]
			<< "," << input->SurfQi_Routed_m[timeStep]
			<< "," << input->SubQi_Routed_m[timeStep]
			<< "," << input->DCIAQi_Routed_m[timeStep]
			<< "," << input->WAQi_Routed_m[timeStep]
			<< "," << input->PAQi_Routed_m[timeStep]
			<< endl;

		//Write catchment unrouted and routed runoff volume (m3) to output
		outfile_RunoffVariables_m3 << input->SimulationDate_Output_GD[timeStep]
			<< "," << input->SimulationTime_Output_HMS[timeStep]
			<< "," << input->Rain_m[timeStep] * CA_m2
			<< "," << input->Snow_m[timeStep] * CA_m2
			<< "," << input->Qi_m[timeStep] * CA_m2
			<< "," << input->SurfQi_m[timeStep] * CA_m2
			<< "," << input->SubQi_m[timeStep] * CA_m2
			<< "," << input->DCIAQi_m[timeStep] * CA_m2
			<< "," << input->WAQi_m[timeStep] * CA_m2
			<< "," << input->PAQi_m[timeStep] * CA_m2
			<< "," << input->Qi_Routed_m[timeStep] * CA_m2
			<< "," << input->SurfQi_Routed_m[timeStep] * CA_m2
			<< "," << input->SubQi_Routed_m[timeStep] * CA_m2
			<< "," << input->DCIAQi_Routed_m[timeStep] * CA_m2
			<< "," << input->WAQi_Routed_m[timeStep] * CA_m2
			<< "," << input->PAQi_Routed_m[timeStep] * CA_m2
			<< endl;
	}
}