#include "Infiltration_StormwaterDevice.h"

//GI_RateOfInfiltration function references infiltration rate computed external to Inflow_StormwaterDevice.cpp, then scales to proper area
void Infiltration_StormwaterDevice::GI_RateOfInfiltration(Inputs* input, CompactRagged* beC,
			map<string, function<void(Inputs*, int) >>& functors, int DataDrawer_ID, int DataFolder_ID, int timeStep) {

	double Storage_SurfaceLayer_m = 0.0;

	//If Area_GI_Unit_Pervious_m2 > zero then enter division by Area_GI_Unit_Pervious_m2
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2") > 0.0) {
		//Storage volumes transformed to storage depths in pervious area
		//Note: Storage_SurfaceLayer_m (m) is quotient of Storage_GI_Surface_m3 and Area_GI_Unit_Pervious_m2
		//Note: Vault is presumed to have area of Area_GI_Unit_m2 for exfiltration, with water otherwise infiltrating, percolating, and evaporating through Area_GI_Unit_Pervious_m2
		Storage_SurfaceLayer_m = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") / beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2");
	}
	//Ponding_on_PerviousArea_PriorTS_m (m) is added to Flux_to_Infiltration_Drainage_m (m) within the InfiltrationExpDecayCalc.cpp and InfiltrationPowDecayCalc.cpp
	//Note: Ponding_on_PerviousArea_PriorTS_m (m) varies with DataFolder Type; for GI it is Storage_GI_Surface_m3 (m) scaled to pervious area
	//Note: Ponding_on_PerviousArea_PriorTS_m (m) represents removal of Evaporation_Surface_m3 (m3) from Storage_GI_Surface_m3 (m3); negative values okay
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Ponding_on_PerviousArea_PriorTS_m") = Storage_SurfaceLayer_m;

	//Flux_to_GI_PerviousArea_BARunon_m (m) goes to functors["calculateInfiltration"] from WaterOnPerviousAreaCalc.cpp
	//Note: Flux_to_GI_PerviousArea_BARunon_m is sum of BulkArea transfers to GI, scaled from folder volume to pervious area depth
	//Note: Any BulkArea transfers to GI with impervious or water cover presumed to drain to GI pervious cover for infiltration

	//calculateInfiltration functor generates variables Drainage_macroPore_m (m) and Infiltration_m (m), which combines Inf_viaEx and Inf_viSat
	//Note: Flux_to_Infiltration_Drainage_m = Flux_to_PerviousArea_Rain_SnowMelt_Irrigation_ImpRunon_m + Flux_to_GI_PerviousArea_BARunon_m + Ponding_on_PerviousArea_PriorTS_m
	//Note: calculateInfiltration combines GI folder K0_mph with BulkArea folder input->InputXml["Parameter_n_KsatPowerDecay"] and input->InputXml["Parameter_m_KsatExpDecay"]
	functors["calculateInfiltration"](input, timeStep);

	//Infiltration_Surface_m3 (m3) is Infiltration_m (m) and Area_GI_Unit_Pervious_m2 (m2), folder pervious area
	//Note: Infiltration_m (m) is sum of satExcessInflow_m and infilExcessInflow_m, weighted by InfiltExcessGovernedArea_frac in calculateInfiltration functor
	//Note: Vault is presumed to have area of Area_GI_Unit_m2 for exfiltration, with water otherwise infiltrating, percolating, and evaporating through Area_GI_Unit_Pervious_m2
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2");

	//Infiltration_Surface_m3 (m3) increases by product of Drainage_macroPore_m (m) and Area_GI_Unit_Pervious_m2 (m2, folder pervious cover
	//Note: Drainage_macroPore_m (m) is the water from Flux_to_Infiltration_m that bypasses infiltration and soil evapotranspiration zone, going directly to unsat zone
	//Note: Consider refactor of GI water balance to allow Drainage_macroPore_m to enter subsurface storage or native soil below top layer
	//Note: Vault is presumed to have area of Area_GI_Unit_m2 for exfiltration, with water otherwise infiltrating, percolating, and evaporating through Area_GI_Unit_Pervious_m2
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Drainage_macroPore_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2");

	//Note: Consider refactor to use input to read Flag_GI_SVAT read from HydroPlusConfig.xml for additional functionality
	//Note: Consider refactor to use input->RepoDict["Groundwater_surficial_frac"] and create Runoff_SatExcess_m3 to remove 
	//Note: ... Runoff_SatExcess_m3 dependence on Infiltration, and should likely occur even if not Infiltration occurs
	//Flag_GI_SVAT read from HydroPlusConfig.xml
	bool Flag_GI_SVAT = 0;
	//If Flag_GI_SVAT equals 1 then enter
	if (Flag_GI_SVAT == 1) {
		//Runoff_SatExcess_m3 (m3) is product of Groundwater_surficial_frac (frac) and sum of all inflow, Flux_to_GI_Precipitation_m3, ...
		//... Flux_BulkArea_to_GI_Runon_m3, and Flux_GI_to_GI_Runon_m3
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_SatExcess_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_to_GI_Precipitation_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_BulkArea_to_GI_Runon_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_to_GI_Runon_m3")) * input->RepoDict["Groundwater_surficial_frac"];

		//Infiltration_Surface_m3 (m3) reduced by Runoff_SatExcess_m3 (m3) due to saturation excess runoff
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_SatExcess_m3");
		//Groundwater_surficial_frac (frac) for GI folder defined from RepoDict Groundwater_surficial_frac, for use later
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Groundwater_surficial_frac") = input->RepoDict["Groundwater_surficial_frac"];
	}

	//If Type equals to RainBarrel or RoofDisconnect then
	//Note: Surface_Berm_Height_m (m) must be greater than zero to move water into the vault
	if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainBarrel" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RoofDisconnect") {
		//Infiltration_Surface_m3 (m3) is Flux_to_GI_Precipitation_m3 + SurfaceInflow_m3 (m3)
		//Note: RainBarrel uses Infiltration_Surface_m3 (m3) to mimic a downspout leading into the storage tank
		//Note: Flux_BulkArea_to_GI_Runon_m3 (m3) presumably represents roof runoff or ground runoff for barrels submerged below grade
		//Note: Flux_GI_to_GI_Runon_m3 (m3) presumably configured to enter barrels by design team
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_to_GI_Precipitation_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_BulkArea_to_GI_Runon_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_to_GI_Runon_m3");

		//Note: Consider refactor to use this alternative approach for RoofDisconnect
		//Infiltration_Surface_m3 (m3) is Storage_GI_Surface_m3 (m3), which balances inflow and outflow
		//beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3");
	}
}
