#include "DepressionPerviousCalc.h"

//DepressionPervious::DepressionPervious function regulates depression storage after infiltration routine has identified infiltration excess runoff
//Note: Function applies only for infiltration excess water, not saturation excess water
//Consider Refactor to keep saturation excess runoff within depression storage if its depth is less than max storage
//Ponding (p) of infiltration excess; if p > 0 then it can evaporate or infiltrate (next timestep); if p > max ponding depth, p_max, then runoff = (p_max - p) 
void DepressionPerviousCalc::DepressionPervious(Inputs* input, CompactRagged* beC, int MapPixel_ID, int DataFolder_ID, int timeStep, map<string, function<void(Inputs*, int)> >& functors)
{

	//If timeStep equals zero then initialize Storage_PerviousPondedWater_m (m) to zero
	if (timeStep == 0) {
		beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") = 0.0;
	}

	//Storage_PerviousPondedWater_m (m) is Flux_InfilEx_to_Ponding_m (m), the infiltration excess depth in InfiltrationExpDecayCalc.cpp and InfiltrationPowDecayCalc.cpp
	//Note: Flux_to_Infiltration_m (m) includes Ponding_on_PerviousArea_PriorTS_m from Flux_to_Infiltration_Drainage_m, water bypassing macropores
	//Note: Flux_to_Infiltration_Drainage_m (m) is Ponding_on_PerviousArea_PriorTS_m + Flux_to_PerviousArea_Rain_SnowMelt_Irrigation_ImpRunon_m + Flux_to_GI_PerviousArea_BARunon_m
	beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Flux_InfilEx_to_Ponding_m");

	//Storage_PerviousPondedWater_Max_m (m) is converted from PerviousDepressionStorage_mm given in HydroPlusConfig.xml as maximum storage; Ratio_m_to_mm to convert from mm to meters
	beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_Max_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousDepressionStorage_mm") * Ratio_m_to_mm;

	//calculatePerDepEvap functor computes Evaporation_PerviousPondedWater_m in OpenWaterEvaporationCalc::calculatePerDepEvapStatistical or ::calculatePerDepEvapTemperature function
	functors["calculatePerDepEvap"](input, timeStep);

	//If Evaporation_PerviousPondedWater_m (m) > Storage_PerviousPondedWater_m (m) then set to Storage_PerviousPondedWater_m (m)
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Evaporation_PerviousPondedWater_m") > beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m")) {
		//Evaporation_PerviousPondedWater_m (m) is set to Storage_PerviousPondedWater_m (m)
		beC->by_key(MapPixel_ID, DataFolder_ID, "Evaporation_PerviousPondedWater_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m");
	}

	//If Storage_Snow_noCanopy_m (m) > 0, there is snow on ground and liquid evaporation from storage is zero for this timestep
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_Snow_noCanopy_m") > 0.0) {
		beC->by_key(MapPixel_ID, DataFolder_ID, "Evaporation_PerviousPondedWater_m") = 0.0;
	}

	//Storage_PerviousPondedWater_m (m) equals Storage_PerviousPondedWater_m (m) minus Evaporation_PerviousPondedWater_m (m), which is removing water evaporating during time step
	beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") -
		beC->by_key(MapPixel_ID, DataFolder_ID, "Evaporation_PerviousPondedWater_m");

	//if Storage_PerviousPondedWater_m (m) is less than or equal to Storage_PerviousPondedWater_Max_m (m), then there is no excess water nor any Runoff_InfilExcess_m (m)
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") <= beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_Max_m")) {
		//Runoff_InfilExcess_m (m) is zero
		beC->by_key(MapPixel_ID, DataFolder_ID, "Runoff_InfilExcess_m") = 0;
	}

	//if Storage_PerviousPondedWater_m (m) is greater than Storage_PerviousPondedWater_Max_m (m), and then the excess water is sent to Runoff_InfilExcess_m (m)
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") > beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_Max_m")) {
		//Runoff_InfilExcess_m (m) is generated when Storage_PerviousPondedWater_m (m) is greater than Storage_PerviousPondedWater_Max_m (m)
		beC->by_key(MapPixel_ID, DataFolder_ID, "Runoff_InfilExcess_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") - beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_Max_m");

		//Storage_PerviousPondedWater_m (m) set to Storage_PerviousPondedWater_Max_m (m), which goes to infiltration next timestep
		beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_Max_m");
	}

	//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) changes value with DataFolder Type; for BulkArea it is Storage_PerviousPondedWater_m (m)
	beC->by_key(MapPixel_ID, DataFolder_ID, "Ponding_on_PerviousArea_PriorTS_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_PerviousPondedWater_m");

}
