///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                    Module Library:                    //
//                      ihacres_cal2                     //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                    ihacres_cal.cpp                    //
//                                                       //
//                 Copyright (C) 2008 by                 //
//                     Stefan Liersch                    //
//-------------------------------------------------------//
//                                                       //
//    e-mail:     stefan.liersch@ufz.de                  //
//                stefan.liersch@gmail.com                   //
//                                                       //
//                     2008-01-15                        //
///////////////////////////////////////////////////////////
//                   
//-------------------------------------------------------//
// References:											 
// Jakeman, A.J. / Hornberger, G.M (1993).				 
//   How Much Complexity Is Warranted in a				 
//	 Rainfall-Runoff Model?								 
//	 Water Resources Research, (29), NO. 8 (2637-2649)   
// Kokkonen, T. S. et al. (2003).
//   Predicting daily flows in ungauged catchments:
//   model regionalization from catchment descriptors
//   at the Coweeta Hydrologic Laboratory, North Carolina
//   Hydrological Processes (17), 2219-2238
// Croke, B. F. W., W. S. Merritt, et al. (2004).
//   A dynamic model for predicting hydrologic response
//   to land cover changes in gauged and
//   ungauged catchments.
//   Journal Of Hydrology 291(1-2): 115-131.
//-------------------------------------------------------//

//---------------------------------------------------------
// ToDo
//---------------------------------------------------------
//	- beste Simulation automatisch rausschreiben
//---------------------------------------------------------
#include <iostream> // used for textfile output (test only)
#include <fstream>  // used for textfile output (test only)

#include <stdlib.h> // random numbers
#include <time.h>	// random numbers

#include "ihacres_cal2.h"
// #include ".\..\model_tools.h" // already in ihacres_eq.h
#include "convert_sl.h"
//---------------------------------------------------------

///////////////////////////////////////////////////////////////////////
//
//		Constructor
//
///////////////////////////////////////////////////////////////////////

Cihacres_cal2::Cihacres_cal2(void)
{
	//-----------------------------------------------------
	// 1. Info...
	Set_Name("IHACRES Calibration (2)");

	Set_Author("copyrights (c) 2008 Stefan Liersch");

	Set_Description("Calibration Tool for the Model IHACRES \n \n \n"
		"Reference: \n \n"
		"Jakeman, A.J. / Hornberger, G.M. (1993). \n"
		"How Much Complexity Is Warranted in a Rainfall-Runoff Model? \n"
		"Water Resources Research, (29), NO. 8 (2637-2649) \n \n"   
		"Kokkonen, T. S. et al. (2003). \n"
		"Predicting daily flows in ungauged catchments:"
		"model regionalization from catchment descriptors"
		"at the Coweeta Hydrologic Laboratory, North Carolina \n "
		"Hydrological Processes (17), 2219-2238 \n \n"
		"Croke, B. F. W., W. S. Merritt, et al. (2004).\n"
		"A dynamic model for predicting hydrologic response"
		"to land cover changes in gauged and"
		"ungauged catchments. \n"
		"Journal Of Hydrology 291(1-2): 115-131."
	);

	Parameters.Add_Table_Output(
		NULL	, "TABLEout"	, _TL("Table"),
		""
	);

	//-----------------------------------------------------
	// Create First Module Dialog
	_CreateDialog1();
	//-----------------------------------------------------
}

///////////////////////////////////////////////////////////////////////
//
//		Destructor
//
///////////////////////////////////////////////////////////////////////

Cihacres_cal2::~Cihacres_cal2(void)
{
	//if (m_bSnowModule)
	//{
	//	delete m_pSnowModule;
	//	delete[] m_pMeltRate;
	//}
}


///////////////////////////////////////////////////////////////////////
//
//		On_Execute()
//
///////////////////////////////////////////////////////////////////////


//---------------------------------------------------------
// This function is executed when the user is pressing the OK button
// in the first module dialog
bool Cihacres_cal2::On_Execute(void)
{
	int			first, last;
	double		NSE_temp	= 0.0;
	double		NSE_max		= -9999.9;
	string		nse, nse_text;

	//---------------------------------------------------------
	// Assign parameters from First Module Dialog
	m_pTable		= Parameters("TABLE")			->asTable();
	// Field numbers
	m_dateField		= Parameters("DATE_Field")		->asInt();
	m_dischargeField= Parameters("DISCHARGE_Field")	->asInt();
	m_pcpField		= Parameters("PCP_Field")		->asInt();
	m_tmpField		= Parameters("TMP_Field")		->asInt();
	m_inflowField	= Parameters("INFLOW_Field")	->asInt();

	m_bUpstream		= Parameters("bUPSTREAM")		->asBool();

	m_bTMP			= Parameters("USE_TMP")			->asBool();

	m_nsim			= Parameters("NSIM")			->asInt();
	m_area			= Parameters("AREA")			->asDouble();
	m_dev_eRainDis	= Parameters("DEV_ERAINDIS")	->asDouble();
	m_dev_eRainPCP	= Parameters("DEV_ERAINPCP")	->asDouble();
	m_storconf		= Parameters("STORAGE")			->asInt();
	m_IHAC_version	= Parameters("IHACVERS")		->asInt();
	m_bSnowModule	= Parameters("SNOW_MODULE")		->asBool();
	first = last	= 0;
	//---------------------------------------------------------

	//---------------------------------------------------------
	// After pressing OK in the first Dialog Dialog2 appears.
	// In the sec
	if ( _CreateDialog2() )
	//---------------------------------------------------------
	{
		//---------------------------------------------------------
		// Searching the first and the last record of the time range
		ihacres.AssignFirstLastRec(*m_pTable, first, last, m_date1, m_date2, m_dateField);
		//---------------------------------------------------------

		//---------------------------------------------------------
		// Initialize arrays
		m_nValues = last - first + 1;
		_InitPointers();
		//---------------------------------------------------------

		//---------------------------------------------------------
		// Assign selected time range to vector m_vec_date, 
		// discharge[], pcp[], and tmp[]
		_ReadInputTable(first, last);
		//---------------------------------------------------------

		//---------------------------------------------------------
		// Convert streamflow from m3/s to mm/day
		if (m_bUpstream)
		{
			// if the subbasin is upstream (without external inflow) then everything
			// is as it should be.
			m_p_Q_obs_mmday = model_tools::m3s_to_mmday(m_p_Q_obs_m3s,m_p_Q_obs_mmday,m_nValues,m_area);
		} else {
			// if the subbasin is downstream of other subbasins, thus there
			// are external inflows the array m_p_Q_obs_mmday must be calculated as following:
			// m_p_Q_obs_mmday =
			// (observed streamflow at the outlet of the subbasin) - (observed inflow from the upstream subbasin(s))
			_Calc_ObsMinInflow();
			m_p_Q_obs_mmday = model_tools::m3s_to_mmday(m_p_Q_dif_m3s, m_p_Q_obs_mmday, m_nValues, m_area);
		}
		// calculate sum of observed discharge in [mm]
		m_sum_obsDisMM = ihacres.SumVector(m_p_Q_obs_mmday, m_nValues);
		//---------------------------------------------------------

		//---------------------------------------------------------
		m_pTable = SG_Create_Table();
		_CreateOutputTable();
		m_counter = 0;
		//---------------------------------------------------------

		///////////////////////////////////////////////////////////
		//
		//		SIMULATION
		//
		///////////////////////////////////////////////////////////
		
		// initialize random function
		srand((unsigned) time(NULL)); // using time.h

		for (int sim = 0; sim < m_nsim && Set_Progress(sim, m_nsim); sim++)
		{
			_CalcNonLinearModule();

			_CalcLinearModule();

			_CalcEfficiency();

			// write in output table if criterion is fulfilled
			NSE_temp = ihacres._Assign_NSE_temp(m_obj_func, m_NSE, m_NSE_highflow, m_NSE_lowflow);

			if (NSE_temp > m_NSEmin)
			{
				if (NSE_temp > NSE_max)
				{
					NSE_max = NSE_temp;
					nse = convert_sl::Double2String(NSE_max).c_str();
					nse_text = "max. NSE " + nse;
					Process_Set_Text(nse_text.c_str());
				}

				_WriteOutputTable();
			}
		}
		//---------------------------------------------------------
		m_pTable->Set_Name("IHACRES_cal2");
		Parameters("TABLEout")->Set_Value(m_pTable);



		//---------------------------------------------------------
		_DeletePointers();
		//---------------------------------------------------------

		return(true);

	} // end if (_CreateDialog2())


	return(false);
}


///////////////////////////////////////////////////////////////////////
//
//		PRIVATE FUNCTIONS
//
///////////////////////////////////////////////////////////////////////


//---------------------------------------------------------------------
//		InitPointers()
//---------------------------------------------------------------------
void Cihacres_cal2::_InitPointers()
{
	int n = m_nValues;

	m_vec_date.resize(n);
	if (!m_bUpstream)
	{
		m_p_Q_Inflow_m3s = new double[n];
		m_p_Q_dif_m3s	 = new double[n];
	}
	m_p_Q_obs_m3s	= new double[n];
	m_p_Q_obs_mmday	= new double[n];
	m_p_Q_sim_mmday	= new double[n];
	m_pPCP			= new double[n];
	m_pTMP			= new double[n];
	m_pExcessRain	= new double[n];
	m_pTw			= new double[n];
	m_pWI			= new double[n];
	if (m_bSnowModule)
		m_pMeltRate	= new double[n];
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//		DeletePointers()
//---------------------------------------------------------------------
void Cihacres_cal2::_DeletePointers()
{
	m_vec_date.resize(0);
	if (!m_bUpstream)
	{
		delete[] m_p_Q_Inflow_m3s;
		delete[] m_p_Q_dif_m3s;
	}
	delete[] m_p_Q_obs_m3s;
	delete[] m_p_Q_obs_mmday;
	delete[] m_p_Q_sim_mmday;
	delete[] m_pPCP;
	delete[] m_pTMP;
	delete[] m_pExcessRain;
	delete[] m_pTw;
	delete[] m_pWI;
	if (m_bSnowModule)
		delete[] m_pMeltRate;
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//		ReadInputTable()
//---------------------------------------------------------------------
void Cihacres_cal2::_ReadInputTable(int first, int last)
{
	int j, k;

	for (j = 0, k = first; j < m_nValues, k < last + 1; j++, k++)
	{
		// put the date string into the vector
		m_vec_date[j].append(m_pTable->Get_Record(k)->asString(m_dateField));
		m_p_Q_obs_m3s[j]= m_pTable->Get_Record(k)->asDouble(m_dischargeField);
		m_pPCP[j]		= m_pTable->Get_Record(k)->asDouble(m_pcpField);
		m_pTMP[j]		= m_pTable->Get_Record(k)->asDouble(m_tmpField);
		if (!m_bUpstream)
			m_p_Q_Inflow_m3s[j] = m_pTable->Get_Record(k)->asDouble(m_inflowField);
	}
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//		Calculate observed streamflow time series if inflow occurs
//---------------------------------------------------------------------
void Cihacres_cal2::_Calc_ObsMinInflow()
{
	for (int i = 0; i < m_nValues; i++)
	{
		m_p_Q_dif_m3s[i] = m_p_Q_obs_m3s[i] - m_p_Q_Inflow_m3s[i];
		if (m_p_Q_dif_m3s[i] < 0.0) m_p_Q_obs_mmday[i] = 0;
	}
}
//---------------------------------------------------------------------



///////////////////////////////////////////////////////////////////////
//
//
//							SIMULATION
//
//
///////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////
//
//		NON-LINEAR MODULE
//
///////////////////////////////////////////////////////////////////////

void Cihacres_cal2::_CalcNonLinearModule()
{
	double eR_init = 0.0;
	//-------------------------------------------------------------
	// Assign random values
	//-------------------------------------------------------------
	if (m_bSnowModule)
	{
		m_SnowParms.T_Rain	= model_tools::Random_double(m_T_Rain_lb, m_T_Rain_ub);
		m_SnowParms.T_Melt	= model_tools::Random_double(m_T_Melt_lb, m_T_Melt_ub);
		m_SnowParms.DD_FAC	= model_tools::Random_double(m_DD_FAC_lb, m_DD_FAC_ub);

		m_pSnowModule = new CSnowModule(m_pTMP, m_pPCP, m_nValues,
			m_SnowParms.T_Rain, m_SnowParms.T_Melt, m_SnowParms.DD_FAC);

		m_pMeltRate = m_pSnowModule->Get_MeltRate(m_pMeltRate, m_nValues);
		delete m_pSnowModule;
	}

	m_Tw	= model_tools::Random_double(m_TwConst_lb, m_TwConst_ub);
	m_f		= model_tools::Random_double(m_f_lb, m_f_ub);
	m_c		= model_tools::Random_double(m_c_lb, m_c_ub);

	if (m_IHAC_version == 1) { // Croke etal. (2005)
		m_l	= model_tools::Random_double(m_l_lb, m_l_ub);
		m_p	= model_tools::Random_double(m_p_lb, m_p_ub);
	}
	//-------------------------------------------------------------

	//-------------------------------------------------------------
	// Simulation (non-linear module)
	//-------------------------------------------------------------
	switch(m_IHAC_version)
	{		
	case 0: // Jakeman & Hornberger (1993)
		if (m_bTMP)
		{
			ihacres.CalcWetnessTimeConst(m_pTMP, m_pTw, m_Tw, m_f, m_nValues);
		}

		if (m_bSnowModule)
		{
			ihacres.CalcWetnessIndex(m_pTw, m_pPCP, m_pTMP,	m_pWI, 0.5, m_c,
				m_bSnowModule, m_SnowParms.T_Rain, m_nValues);

			ihacres.CalcExcessRain(m_pPCP, m_pTMP, m_pWI,m_pExcessRain,eR_init,
				m_sum_eRainGTpcp, m_nValues, m_bSnowModule,
				m_SnowParms.T_Rain, m_SnowParms.T_Melt, m_pMeltRate);
		} else {
			ihacres.CalcWetnessIndex(m_pTw, m_pPCP, m_pTMP, m_pWI, 0.5, m_c,
				m_bSnowModule, 0, m_nValues);

			ihacres.CalcExcessRain(m_pPCP, m_pTMP, m_pWI, m_pExcessRain,eR_init,
				m_sum_eRainGTpcp, m_nValues, m_bSnowModule,
				0,0,0);
		} // end if (m_bSnowModule)

		break;
	case 1: // Croke et al. (2005) Redesign
		if (m_bTMP)
		{
			ihacres.CalcWetnessTimeConst_Redesign(m_pTMP, m_pTw, m_Tw, m_f, m_nValues);
		}

		if (m_bSnowModule)
		{
			ihacres.CalcWetnessIndex_Redesign(m_pTw, m_pPCP, m_pWI, 0.5,
				m_bSnowModule, m_SnowParms.T_Rain, m_nValues);

			ihacres.CalcExcessRain_Redesign(m_pPCP, m_pTMP, m_pWI, m_pExcessRain, eR_init,
				m_sum_eRainGTpcp, m_nValues, 
				m_c, m_l, m_p, 
				m_bSnowModule, m_SnowParms.T_Rain, m_SnowParms.T_Melt, m_pMeltRate);
		} else {
			ihacres.CalcWetnessIndex_Redesign(m_pTw, m_pPCP, m_pWI, 0.5,
				m_bSnowModule, 0, m_nValues);

			ihacres.CalcExcessRain_Redesign(m_pPCP, m_pTMP, m_pWI, m_pExcessRain, eR_init,
				m_sum_eRainGTpcp, m_nValues, 
				m_c, m_l, m_p,
				m_bSnowModule, 0,0,0);
		}
		break;
	} // end switch(m_IHAC_version)
}
//---------------------------------------------------------------------



///////////////////////////////////////////////////////////////////////
//
//		LINEAR MODULE
//
///////////////////////////////////////////////////////////////////////

void Cihacres_cal2::_CalcLinearModule()
{
	//-------------------------------------------------------------
	// Assign random values
	//-------------------------------------------------------------
	switch(m_storconf)
	{
	case 0: // single storage
		m_a		= model_tools::Random_double(m_a_lb, m_a_ub);
		m_b		= model_tools::Random_double(m_b_lb, m_b_ub);
		break;
	case 1: // two storages in parallel
		do
		{
			m_aq		= model_tools::Random_double(m_aq_lb, m_aq_ub);
			m_as		= model_tools::Random_double(m_as_lb, m_as_ub);
			m_bq		= model_tools::Random_double(m_bq_lb, m_bq_ub);
			// Calculate parameter m_vq to check parms aq and bq
			// Equation after Jakeman & Hornberger (1993)
			m_vq	= m_bq / ( 1 + m_aq );
		}
		while (m_vq < 0.0 || m_vq > 1.0);
		m_bs = ihacres.Calc_Parm_BS(m_aq, m_as, m_bq);
		break;
	}
	//-------------------------------------------------------------

	//-------------------------------------------------------------
	// Simulate streamflow (linear module)
	//-------------------------------------------------------------
	switch(m_storconf)
	{
	case 0: // single storage
		ihacres.SimStreamflowSingle(m_pExcessRain, m_p_Q_obs_mmday[0],
			m_p_Q_sim_mmday, m_delay, m_a, m_b, m_nValues);
		break;
	case 1: // two storages in parallel
		ihacres.SimStreamflow2Parallel(m_pExcessRain, m_p_Q_sim_mmday, m_p_Q_obs_mmday[0],
			m_aq, m_as, m_bq, m_bs, m_vq, m_vs, m_IHAC_version, m_nValues, m_delay);
		break;
	case 2: // two storages in series
		break;
	} // end switch(m_StorConf)
}
//---------------------------------------------------------------------



///////////////////////////////////////////////////////////////////////
//
//		EFFICIENCY
//
///////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------
//		Nash-Sutcliffe efficiency
//---------------------------------------------------------------------
void Cihacres_cal2::_CalcEfficiency()
{
	m_NSE			= model_tools::CalcEfficiency(m_p_Q_obs_mmday, m_p_Q_sim_mmday,m_nValues);
	m_NSE_highflow	= model_tools::Calc_NSE_HighFlow(m_p_Q_obs_mmday, m_p_Q_sim_mmday, m_nValues);
	m_NSE_lowflow	= model_tools::Calc_NSE_LowFlow(m_p_Q_obs_mmday, m_p_Q_sim_mmday, m_nValues);
	m_PBIAS			= model_tools::Calc_PBIAS(m_p_Q_obs_mmday, m_p_Q_sim_mmday, m_nValues);
}
//---------------------------------------------------------------------





/////////////////////////////////////////////////////////////////////////////
//
//							CREATE TABLES
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------
//		Create output table
//---------------------------------------------------------------------
void Cihacres_cal2::_CreateOutputTable()
{
	// creating the column titles
	m_pTable->Add_Field("NSE",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("NSE_high",			TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("NSE_low",			TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("PBIAS",			TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("eR_ovest",			TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("vq",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("vs",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("T(q)",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("T(s)",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("Tw",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("f",				TABLE_FIELDTYPE_Double);
	m_pTable->Add_Field("c",				TABLE_FIELDTYPE_Double);
	if ( m_IHAC_version == 1 ) // Croke etal. (2005)
	{
		m_pTable->Add_Field("l",			TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("p",			TABLE_FIELDTYPE_Double);
	}
	if (m_bSnowModule)
	{
		m_pTable->Add_Field("T_Rain",		TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("T_Melt",		TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("DD_FAC",		TABLE_FIELDTYPE_Double);
	}
	switch(m_storconf)
	{
	case 0: // single
		m_pTable->Add_Field("a",			 TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("b",			 TABLE_FIELDTYPE_Double);
		break;
	case 1: // two storages in parallel
		m_pTable->Add_Field("aq",			 TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("as",			 TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("bq",			 TABLE_FIELDTYPE_Double);
		m_pTable->Add_Field("bs",			 TABLE_FIELDTYPE_Double);
		break;
	}
}
//---------------------------------------------------------------------


//---------------------------------------------------------------------
//		Create output table
//---------------------------------------------------------------------
void Cihacres_cal2::_WriteOutputTable()
{
	int					field = 0;
	CSG_Table_Record	*pRecord;

	// add a new record to the table
	m_pTable->Add_Record();
	pRecord	= m_pTable->Get_Record(m_counter);

	// writing the data to the current row
	pRecord->Set_Value(field,m_NSE); field++;
	pRecord->Set_Value(field,m_NSE_highflow); field++;
	pRecord->Set_Value(field,m_NSE_lowflow); field++;
	pRecord->Set_Value(field,m_PBIAS); field++;
	pRecord->Set_Value(field,m_sum_eRainGTpcp); field++;
	pRecord->Set_Value(field,m_vq); field++;
	pRecord->Set_Value(field,m_vs); field++;
	pRecord->Set_Value(field,ihacres.Calc_TimeOfDecay(m_aq)); field++;
	pRecord->Set_Value(field,ihacres.Calc_TimeOfDecay(m_as)); field++;
	pRecord->Set_Value(field,m_Tw); field++;
	pRecord->Set_Value(field,m_f); field++;
	pRecord->Set_Value(field,m_c); field++;
	if ( m_IHAC_version == 1 ) // Croke et al. (2005)
	{
		pRecord->Set_Value(field,m_l); field++;
		pRecord->Set_Value(7+field,m_p); field++;
	}
	if ( m_bSnowModule )
	{
		pRecord->Set_Value(field,m_SnowParms.T_Rain); field++;
		pRecord->Set_Value(field,m_SnowParms.T_Melt); field++;
		pRecord->Set_Value(field,m_SnowParms.DD_FAC); field++;
	}
	switch(m_storconf)
	{
	case 0: // single
		pRecord->Set_Value(field,m_a); field++;
		pRecord->Set_Value(field,m_b); field++;
		break;
	case 1: // two storages in parallel
		pRecord->Set_Value(field,m_aq); field++;
		pRecord->Set_Value(field,m_as); field++;
		pRecord->Set_Value(field,m_bq); field++;
		pRecord->Set_Value(field,m_bs); field++;
		break;
	}
	m_counter++; // record counter
}
//---------------------------------------------------------------------






///////////////////////////////////////////////////////////////////////
//
//		DIALOGS
//
///////////////////////////////////////////////////////////////////////


//---------------------------------------------------------------------
//		DIALOG 1
//---------------------------------------------------------------------
void Cihacres_cal2::_CreateDialog1()
{
	CSG_Parameter	*pNode;
	CSG_String s;

	pNode = Parameters.Add_Table(
		NULL	, "TABLE"	, _TL("Table"),
		"",
		PARAMETER_INPUT
	);

	Parameters.Add_Table_Field(
		pNode	, "DATE_Field"	, _TL("Date Column"),
		"Select the column containing the Date"
	);

	Parameters.Add_Table_Field(
		pNode	, "DISCHARGE_Field"	, _TL("Streamflow Column"),
		"Select the Column containing Discharge Values"
	);

	Parameters.Add_Table_Field(
		pNode	, "PCP_Field"	, _TL("Precipitation Column"),
		"Select the Column containing precipitation Values"
	);

	Parameters.Add_Table_Field(
		pNode	, "TMP_Field"	, _TL("Temperature Column"),
		"Select the Column containing Temperature Values"
	);
	
	Parameters.Add_Table_Field(
		pNode	, "INFLOW_Field"	, _TL("Subbasin Inflow"),
		"Select the column containing inflow data to the subbasin"
	);
	
	Parameters.Add_Value(
		pNode,	"bUPSTREAM",	_TL("Is the subbasin upstream (no external inflow)"),
		_TL("If checked, it means there is no external inflow to the subbasin"),
		PARAMETER_TYPE_Bool, true
	);

	Parameters.Add_Value(
		pNode,	"USE_TMP",	_TL("Using temperature data?"),
		_TL("If checked, then temperature data are used."),
		PARAMETER_TYPE_Bool, true
	);

	pNode = Parameters.Add_Value(
		NULL,	"NSIM",	_TL("Number of Simulations"),
		_TL("Number of Simulations for Calibration"),
		PARAMETER_TYPE_Int,
		1000, 1, true, 10000000, true
	);

	pNode = Parameters.Add_Value(
		NULL,	"AREA",	_TL("Area of the Watershed in [km2]"),
		_TL("Area of the Watershed in [km2] used for unit conversion"),
		PARAMETER_TYPE_Double,
		100.0, 0.00001, true, 0.0, false
	);

	s.Printf("Node2", 2);
		pNode = Parameters.Add_Node(NULL,s,"Non-Linear Module","");

	Parameters.Add_Value(
		pNode,	"DEV_ERAINDIS",	_TL("Maximum Deviation: ExcessRain-Streamflow [%]"),
		_TL("Maximum Deviation between estimated excess rainfall and observed streamflow volumes"),
		PARAMETER_TYPE_Double,
		5.0, 0.0, true, 50.0, true
	);

	Parameters.Add_Value(
		pNode,	"DEV_ERAINPCP",	_TL("Maximum Overestimation of ExcessRain [%]"),
		_TL("Maximum Sum of overestimated ExcessRain to total ExcessRain in [%]"),
		PARAMETER_TYPE_Double,
		5.0, 0.0, true, 50.0, true
	);

	s.Printf("Node3", 3);
	pNode = Parameters.Add_Node(NULL,s,"Storage Configuration","");

	Parameters.Add_Choice(
		pNode	, "STORAGE"		, "Storage",
		"",
		CSG_String::Format("%s|%s|%s|",
			_TL("Single Storage"),			//  0
			_TL("Two Parallel Storages"),	//  1 
			_TL("Two Storages in Series")	//  2 
		)
	);

	s.Printf("Node4", 4);
	pNode = Parameters.Add_Node(NULL,s,"IHACRES Version","");

	Parameters.Add_Choice(
		pNode	, "IHACVERS"		, "IHACRES Version",
		"",
		CSG_String::Format("%s|%s|",
			_TL("Jakeman & Hornberger (1993)"),	//  0
			_TL("Croke et al. (2005)")			//	1
		)
	);

	Parameters.Add_Value(
		pNode,	"SNOW_MODULE",	_TL("Snow Module on/off"),
		_TL("If checked the snow module is active"),
		PARAMETER_TYPE_Bool, true
	);

	Parameters.Add_Table_Output(
		NULL	, "TABLEout"	, _TL("Table"),
		""
	);
	Parameters.Add_Table_Output(
		NULL	, "TABLEparms"	, _TL("Table"),
		""
	);
}
//---------------------------------------------------------------------


//---------------------------------------------------------------------
//		DIALOG 2
//---------------------------------------------------------------------
bool Cihacres_cal2::_CreateDialog2()
{
	CSG_String		s;
	CSG_Parameters	P;  // used to add Parameters in the second dialog
	CSG_Parameter	*pNode, *pNode1;


	//	Dialog design
	P.Set_Name(_TL("Choose Time Range"));

	s.Printf("Node1", 1);
	pNode = P.Add_Node(NULL,s,"Time Range","");

	s.Printf("FDAY" , 1-1);
	P.Add_String(pNode,s,_TL("First Day"),_TL(""),
		m_pTable->Get_Record(0)->asString(m_dateField));

	s.Printf("LDAY" , 1-2);
	P.Add_String(pNode,s,_TL("Last Day"),_TL(""),
		m_pTable->Get_Record(m_pTable->Get_Record_Count()-1)->asString(m_dateField));

	//-----------------------------------------------------------------
	// Non-linear parameters
	//-----------------------------------------------------------------
	s.Printf("Node2", 2);
		pNode = P.Add_Node(NULL,s,"Non-Linear Module","");

	P.Add_Value(
		pNode,	"TwFAC_lb",	_TL("(Tw) wetness decline time constant [lower bound]"),
		_TL("Tw is approximately the time constant, or inversely,"
		"the rate at which the catchment wetness declines in the absence of rainfall"),
		PARAMETER_TYPE_Double,
		1.0, 0.01, true, 150.0, true
	);
	P.Add_Value(
		pNode,	"TwFAC_ub",	_TL("(Tw) wetness decline time constant [upper bound]"),
		_TL("Tw is approximately the time constant, or inversely,"
		"the rate at which the catchment wetness declines in the absence of rainfall"),
		PARAMETER_TYPE_Double,
		1.0, 0.01, true, 150.0, true
		);

	if (m_bTMP) // if observed temperature data are used
	{
		P.Add_Value(
			pNode	, "TFAC_lb"		, "(f) Temperature Modulation Factor [lower bound]",
			_TL("Temperature Modulation Factor f"),
			PARAMETER_TYPE_Double,
			0.05, 0.0001, true, 5.0, true
		);
		P.Add_Value(
			pNode	, "TFAC_ub"		, "(f) Temperature Modulation Factor [upper bound]",
			_TL("Temperature Modulation Factor f"),
			PARAMETER_TYPE_Double,
			0.5, 0.0001, true, 5.0, true
		);
	}

	P.Add_Value(
		pNode,	"CFAC_lb",	_TL("(c) Parameter [lower bound]"),
		_TL("Parameter (c) to fit streamflow volume"),
		PARAMETER_TYPE_Double,
		0.001, 0.0, true, 1.0, true
	);
	P.Add_Value(
		pNode,	"CFAC_ub",	_TL("(c) Parameter [upper bound]"),
		_TL("Parameter (c) to fit streamflow volume"),
		PARAMETER_TYPE_Double,
		0.01, 0.0, true, 1.0, true
	);

	if (m_IHAC_version == 1) // Croke et al. (2005) Redesign
	{
		s.Printf("Node2-2", 2-2);
		pNode1 = P.Add_Node(pNode,s,"Soil moisture index threshold","");

		P.Add_Value(
			pNode1	, "SMI_L_lb"		, "Soil moisture index (l) [lower bound]",
			_TL("Soil moisture index threshold (l), lower bound"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
		P.Add_Value(
			pNode1	, "SMI_L_ub"		, "Soil moisture index (l) [upper bound]",
			_TL("Soil moisture index threshold (l), upper bound"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
		s.Printf("Node2-3", 2-3);
		pNode1 = P.Add_Node(pNode,s,"Power on soil moisture","");

		P.Add_Value(
			pNode1	, "SM_P_lb"		, "Power on soil (p) [lower bound]",
			_TL("Power on soil moisture (p), lower bound"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
		P.Add_Value(
			pNode1	, "SM_P_ub"		, "Power on soil (p) [upper bound]",
			_TL("Power on soil moisture (p), upper bound"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
	}
	//-----------------------------------------------------------------
	// Linear module
	//-----------------------------------------------------------------
	switch(m_storconf)
	{
	case 0: // single storage
		s.Printf("Node3", 3);
		pNode = P.Add_Node(NULL,s,"Linear Module","");

		s.Printf("Node3-1", 3-1);
		pNode1 = P.Add_Node(pNode,s,"Parameter (a)","");

		P.Add_Value(
			pNode1,	"AFAC_lb",	_TL("(a) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.5, -0.99, true, -0.01, true
		);
		P.Add_Value(
			pNode1,	"AFAC_ub",	_TL("(a) [upper bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.9, -0.99, true, -0.01, true
		);

		s.Printf("Node3-2", 3-2);
		pNode1 = P.Add_Node(pNode,s,"Parameter (b)","");

		P.Add_Value(
			pNode1,	"BFAC_lb",	_TL("(b) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			0.0, 0.001, true, 1.0, true
		);
		P.Add_Value(
			pNode1,	"BFAC_ub",	_TL("(b) [upper bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			1.0, 0.001, true, 1.0, true
		);
		break;

	case 1: // two parallel storages
		s.Printf("Node3", 3);
		pNode = P.Add_Node(NULL,s,"Linear Module","");

		// Parameter a
		s.Printf("Node3-1", 3-1);
		pNode1 = P.Add_Node(pNode,s,"Parameter (a)","");

		P.Add_Value(
			pNode1,	"AQ_lb",	_TL("a(q) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.5, -0.99, true, -0.01, true
		);
		P.Add_Value(
			pNode1,	"AQ_ub",	_TL("a(q) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.9, -0.99, true, -0.01, true
		);
		P.Add_Value(
			pNode1,	"AS_lb",	_TL("a(s) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.5, -0.99, true, -0.01, true
		);
		P.Add_Value(
			pNode1,	"AS_ub",	_TL("a(s) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.9, -0.99, true, -0.01, true
		);

		// Parameter b
		s.Printf("Node3-2", 3-2);
		pNode1 = P.Add_Node(pNode,s,"Parameter (b)","");

		P.Add_Value(
			pNode1,	"BQ_lb",	_TL("b(q) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 1.0, true
		);
		P.Add_Value(
			pNode1,	"BQ_ub",	_TL("b(q) [lower bound]"),
			_TL(""),
			PARAMETER_TYPE_Double,
			1.0, 0.0, true, 1.0, true
		);
		break;
	case 2: // two storages in series
		break;
	} // end switch (m_storconf)


	//-----------------------------------------------------------------
	// Snow module
	//-----------------------------------------------------------------
	if (m_bSnowModule) // if snow module is active
	{
		s.Printf("Node2-4", 2-4);
		pNode = P.Add_Node(NULL,s,"Snow Module","");

		P.Add_Value(
			pNode,	"T_RAIN_lb",	"Temperature Threshold for Rainfall (lower bound)",
			"Below this threshold precipitation will fall as snow",
			PARAMETER_TYPE_Double,
			-1.0, -10.0, true, 10.0, true
		);
		P.Add_Value(
			pNode,	"T_RAIN_ub",	"Temperature Threshold for Rainfall (upper bound)",
			"Below this threshold precipitation will fall as snow",
			PARAMETER_TYPE_Double,
			1.0, -10.0, true, 10.0, true
		);
		P.Add_Value(
			pNode,	"T_MELT_lb",	"Temperature Threshold for Melting (lower bound)",
			"Above this threshold snow will start to melt",
			PARAMETER_TYPE_Double,
			-1.0, -5.0, true, 10.0, true
		);
		P.Add_Value(
			pNode,	"T_MELT_ub",	"Temperature Threshold for Melting (upper bound)",
			"Above this threshold snow will start to melt",
			PARAMETER_TYPE_Double,
			1.0, -5.0, true, 10.0, true
		);
		P.Add_Value(
			pNode,	"DD_FAC_lb",	"Day-Degree Factor (lower bound)",
			"Day-Degree Factor depends on catchment characteristics",
			PARAMETER_TYPE_Double,
			0.7, 0.7, true, 9.2, true
		);
		P.Add_Value(
			pNode,	"DD_FAC_ub",	"Day-Degree Factor (upper bound)",
			"Day-Degree Factor depends on catchment characteristics",
			PARAMETER_TYPE_Double,
			9.2, 0.7, true, 9.2, true
		);
	}



	s.Printf("Node4", 4);
	pNode = P.Add_Node(NULL,s,"Time Delay after Start of Rainfall (INTEGER)","");
		
	P.Add_Value(
		pNode1,	"DELAY",	"Time Delay (Rain-Runoff)",
		"The delay after the start of rainfall, before the discharge starts to rise.",
		PARAMETER_TYPE_Int,
		0, 1, true, 100, true
	);

	s.Printf("Node6", 6);
	pNode = P.Add_Node(NULL,s,"Nash-Sutcliffe Efficiency","");

	P.Add_Choice(
		pNode, "OBJ_FUNC"		, "Objective Function",
		"",
		"NSE|NSE high flow|NSE low flow"
	);

	P.Add_Value(
		pNode,	"NSEMIN",	"Minimum Nash-Sutcliffe Efficiency",
		"Minimum Nash-Sutcliffe Efficiency required to print simulation to calibration table",
		PARAMETER_TYPE_Double,
		0.7, 0.1, true, 1.0, true
	);
	// End of second dialog design


	if( SG_UI_Dlg_Parameters(&P, _TL("Choose Time Range")) )
	{
		// assign data from second dialog

		m_date1			= P(CSG_String::Format("FDAY",m_dateField).c_str())->asString();
		m_date2			= P(CSG_String::Format("LDAY",m_dischargeField).c_str())->asString();

		//-------------------------------------------------
		// assign non-linear module parameters
		//-------------------------------------------------
		m_TwConst_lb	= P("TwFAC_lb")					->asDouble();
		m_TwConst_ub	= P("TwFAC_ub")					->asDouble();
		m_c_lb			= P("CFAC_lb")					->asDouble();
		m_c_ub			= P("CFAC_ub")					->asDouble();

		if (m_bTMP) // if observed temperature data are used
		{
			m_f_lb		= P("TFAC_lb")					->asDouble();
			m_f_ub		= P("TFAC_ub")					->asDouble();
		}
		if (m_IHAC_version == 1)
		{
			m_l_lb		= P("SMI_L_lb")					->asDouble();
			m_l_ub		= P("SMI_L_ub")					->asDouble();
			m_p_lb		= P("SM_P_lb")					->asDouble();
			m_p_ub		= P("SM_P_ub")					->asDouble();
		}
		//-------------------------------------------------

		//-------------------------------------------------
		// assign linear module parameters
		//-------------------------------------------------
		switch (m_storconf)
		{
		case 0:
			m_a_lb		= P("AFAC_lb")				->asDouble();
			m_a_ub		= P("AFAC_ub")				->asDouble();
			m_b_lb		= P("BFAC_lb")				->asDouble();
			m_b_ub		= P("BFAC_ub")				->asDouble();
			m_delay		= P("DELAY")				->asInt();
			m_NSEmin	= P("NSEMIN")				->asDouble();
			break;
		case 1: // two parallel storages
			m_aq_lb		= P("AQ_lb")				->asDouble();
			m_aq_ub		= P("AQ_ub")				->asDouble();
			m_as_lb		= P("AS_lb")				->asDouble();
			m_as_ub		= P("AS_ub")				->asDouble();
			m_bq_lb		= P("BQ_lb")				->asDouble();
			m_bq_ub		= P("BQ_ub")				->asDouble();

			m_delay		= P("DELAY")				->asInt();
			m_obj_func	= P("OBJ_FUNC")				->asInt();
			m_NSEmin	= P("NSEMIN")				->asDouble();
			break;
		case 2: // two storages in series
			break;
		} // end switch
		//-------------------------------------------------

		if (m_bSnowModule)
		{
			m_T_Rain_lb	= P("T_RAIN_lb")			->asDouble();
			m_T_Rain_ub	= P("T_RAIN_ub")			->asDouble();
			m_T_Melt_lb	= P("T_MELT_lb")			->asDouble();
			m_T_Melt_ub	= P("T_MELT_ub")			->asDouble();
			m_DD_FAC_lb	= P("DD_FAC_lb")			->asDouble();
			m_DD_FAC_ub	= P("DD_FAC_ub")			->asDouble();
		}
		return(true);
	} else {
		return(false);
	}
}
