///////////////////////////////////////////////////////////
//                 ihacres_cimate_scen.h                 //
//                                                       //
//                 Copyright (C) 2008 by                 //
//                     Stefan Liersch                    //
//-------------------------------------------------------//
//    e-mail:     stefan.liersch@ufz.de                  //
//                stefan.liersch@gmail.com               //
//                     2008-01-28                        //
//-------------------------------------------------------//
///////////////////////////////////////////////////////////


//*******************************************************//
//                        ToDo                           //
//-------------------------------------------------------//
// - 
//*******************************************************//
#include <iostream>
#include <sstream>
#include "ihacres_climate_scen_db.h"
#include "convert_sl.h"
#include <fstream>

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

Cihacres_climate_scen_db::Cihacres_climate_scen_db(void)
{
	//-----------------------------------------------------
	// 1. Info...
	Set_Name("IHACRES Climate Scenarios database");

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

	Set_Description("The Model IHACRES used to simulate flood events\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"),
		""
	);


	_ZeroPointers();

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


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

Cihacres_climate_scen_db::~Cihacres_climate_scen_db(void)
{
	_DeletePointers();
}


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


//---------------------------------------------------------------------
// This function is executed when the user is pressing the OK button
// in the first module dialog
//---------------------------------------------------------------------
bool Cihacres_climate_scen_db::On_Execute(void)
{
	//---------------------------------------------------------
	// Assign Parameters from first Module Dialog
	//---------------------------------------------------------
	m_host			= Parameters("HOST")				->asString();
	m_port			= Parameters("PORT")				->asString();
	m_options		= Parameters("OPTIONS")				->asString();
	m_tty			= Parameters("TTY")					->asString();
	m_dbname		= Parameters("DBNAME")				->asString();
	m_user			= Parameters("USER")				->asString();
	m_password		= Parameters("PW")					->asString();

	m_nDaysPeriod	= Parameters("N_DAYS_PERIOD")		->asInt();
	m_Area			= Parameters("AREA")				->asDouble();
	m_IHAC_version	= Parameters("IHACVERS")			->asInt();
	m_StorConf		= Parameters("STORAGE")				->asInt();
	m_bSnowModule	= Parameters("SNOW_MODULE")			->asBool();
	//---------------------------------------------------------

	//---------------------------------------------------------
	// Assign number of storages
	m_nStorages = ihacres.Assign_nStorages(m_StorConf);
	m_p_linparms = new C_IHAC_LinearParms(1,m_nStorages);
	m_p_nonlinparms = new C_IHAC_NonLinearParms(1);
	//---------------------------------------------------------

	if (m_DB.ConnectToDB(m_host,m_port,m_options,m_tty,m_dbname,m_user,m_password) ) {
		if (_CreateDialog2() ) {

			if ( _Initialize() ) {

				if ( _CreateOutputTable() ) {
					Process_Set_Text("Output Table created");
					Message_Add("Output Table created",true);

					//-----------------------------------------------------------------
					//	SIMULATION
					//-----------------------------------------------------------------
					Process_Set_Text("Simulate...");
					Message_Add("Simulate...",true);
					string msg = "";
					int scenario_count = 1;
					for (unsigned int scenario = 0; scenario < m_nClimateScenarios && Set_Progress(scenario,m_nClimateScenarios); scenario++)
					{
						msg = "";
						msg = "Scenario ";
						msg += convert_sl::Int2String(scenario);
						Process_Set_Text(msg.c_str());

						// set current simulation values (rainfall and temperature)
						_SetSimulationValues(m_pPCP, scenario, m_res_pcp, PQnfields(m_res_pcp));
						_SetSimulationValues(m_pTMP, scenario, m_res_tmp, PQnfields(m_res_tmp));

						for (unsigned int combination = 0; combination < m_nParameterCombinations; combination++)
						{
							_Simulate(scenario, combination);

							_WriteOutputTable(scenario_count, scenario, combination);

							scenario_count++;
						}
					}
					//-----------------------------------------------------------------
				} else { // if ( _CreateOutputTable())
					_DeletePointers();
					Process_Set_Text("Unable to create output table!");
				}
				_DeletePointers();
			} else { // if (_Initialize())
				return(false);
			}

		} else { // if (_CreateDialog2())
			return(false);
		}
		
		return(true);
	} else {
		Process_Set_Text("Database connection failed!");
		Message_Add("Database connection failed!", true);
	}
	return(false);
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
void Cihacres_climate_scen_db::_ZeroPointers()
{
	m_res_pcp = NULL;
	m_res_tmp = NULL;
	m_p_Q_sim_mmday = NULL;
	m_pTw = NULL;
	m_pWI = NULL;
	m_pER = NULL;
	m_pMeltRate = NULL;
	m_pPCP = NULL;
	m_pTMP = NULL;
	m_p_linparms = NULL;
	m_p_nonlinparms = NULL;
	m_pInit = NULL;
}

//---------------------------------------------------------------------
void Cihacres_climate_scen_db::_DeletePointers()
{
	PQclear(m_res_pcp);
	PQclear(m_res_tmp);
	delete[] m_p_Q_sim_mmday;
	delete[] m_pTw;
	delete[] m_pWI;
	delete[] m_pER;
	delete[] m_pMeltRate;
	delete[] m_pPCP;
	delete[] m_pTMP;
	delete[] m_p_linparms;
	delete[] m_p_nonlinparms;
	delete[] m_pInit;
}

//---------------------------------------------------------------------
//		SIMULATION
//---------------------------------------------------------------------
void Cihacres_climate_scen_db::_Simulate(int scenario, int combination)
{
	if (m_bSnowModule)
	{
		m_pSnowModule = new CSnowModule(m_pTMP, m_pPCP, m_nDaysPeriod+1,
			m_snowparms.T_Rain, m_snowparms.T_Melt, m_snowparms.DD_FAC);
		m_pMeltRate = m_pSnowModule->Get_MeltRate(m_pMeltRate, m_nDaysPeriod+1);
		delete m_pSnowModule;
	}

	_Simulate_NonLinearModule(scenario, combination);
	_Simulate_Streamflow(combination);
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//		SIMULATE NON-LINEAR MODULE
//---------------------------------------------------------------------
void Cihacres_climate_scen_db::_Simulate_NonLinearModule(int scenario, int combination)
{
	unsigned int nval = m_nDaysPeriod + 1;
	double sum_eRainGTpcp;
	//----------------------------------------------------------
	// calculate excess rainfall time series
	//----------------------------------------------------------
	switch(m_IHAC_version)
	{
	case 0: // Jakeman & Hornberger (1993)
		// The parameter index (fourth parameter) is zero here, because 
		// the parameter settings of the non-linear module are equal in all equal simulations.
		// If they should be different the index parameter can be used to identify the
		// corresponding elevation band.
		ihacres.CalcWetnessTimeConst_scen(m_pTMP, m_pTw,
				m_p_nonlinparms, 0, nval); 
				// 0 = index (only one instance of m_p_nonlinparms)

		if (m_bSnowModule)
		{
			ihacres.CalcWetnessIndex(m_pTw, m_pPCP,
				m_pTMP, m_pWI, m_pInit->pAPI[combination], m_p_nonlinparms->mp_c[0],
				m_bSnowModule, m_snowparms.T_Rain, nval);

			ihacres.CalcExcessRain(m_pPCP, m_pTMP,
				m_pWI, m_pER, m_pInit->pER[combination], sum_eRainGTpcp, nval, m_bSnowModule,
				m_snowparms.T_Rain, m_snowparms.T_Melt,
				m_pMeltRate);
		} else {

			ihacres.CalcWetnessIndex(m_pTw, m_pPCP,
				m_pTMP, m_pWI, m_pInit->pAPI[combination], m_p_nonlinparms->mp_c[0],
				m_bSnowModule, 0, nval);

			ihacres.CalcExcessRain(m_pPCP, m_pTMP,
				m_pWI, m_pER, m_pInit->pER[combination],
				sum_eRainGTpcp, nval, m_bSnowModule,
				0,0,0);
		}
		break;
	case 1: // Croke et al. (2005)
		ihacres.CalcWetnessTimeConst_Redesign(m_pTMP, m_pTw,
			m_p_nonlinparms, 0, nval);	// 0 = index (only one instance of m_p_nonlinparms)

		if (m_bSnowModule)
		{
			ihacres.CalcWetnessIndex_Redesign(m_pTw, m_pPCP, m_pWI, m_pInit->pAPI[combination],
				m_bSnowModule, m_snowparms.T_Rain, nval);

			ihacres.CalcExcessRain_Redesign(m_pPCP, m_pTMP, m_pWI, 
				m_pER, m_pInit->pER[combination],sum_eRainGTpcp, nval, 
				m_p_nonlinparms->mp_c[0], m_p_nonlinparms->mp_l[0], m_p_nonlinparms->mp_p[0],
				m_bSnowModule, m_snowparms.T_Rain, m_snowparms.T_Melt, m_pMeltRate);
		} else {
			ihacres.CalcWetnessIndex_Redesign(m_pTw, m_pPCP, m_pWI, m_pInit->pAPI[combination],
				m_bSnowModule, 0, nval);

			ihacres.CalcExcessRain_Redesign(m_pPCP, m_pTMP, m_pWI, 
				m_pER, m_pInit->pER[combination],sum_eRainGTpcp, nval, 
				m_p_nonlinparms->mp_c[0], m_p_nonlinparms->mp_l[0], m_p_nonlinparms->mp_p[0],
				m_bSnowModule, 0,0,0);
		}
		break;
	} // end switch(m_IHAC_vers)
}
//---------------------------------------------------------------------


//---------------------------------------------------------------------
//		SIMULATE STREAMFLOW
//---------------------------------------------------------------------
void Cihacres_climate_scen_db::_Simulate_Streamflow(int combination)
{
	//----------------------------------------------------------
	unsigned int nval = m_nDaysPeriod + 1;
	double vq, vs;
	//----------------------------------------------------------
	// calculate streamflow
	//----------------------------------------------------------
	switch(m_StorConf)
	{
	case 0: // single storage
		ihacres.SimStreamflowSingle(m_pER, m_pInit->pQ_mmday[combination],
			m_p_Q_sim_mmday, m_delay,
			m_p_linparms->a[0], m_p_linparms->b[0], nval);
		break;
	case 1: // two storages in parallel
		ihacres.SimStreamflow2Parallel(m_pER,
			m_p_Q_sim_mmday, m_pInit->pQ_mmday[combination],
			m_p_linparms, 0, vq, vs, nval, m_delay);
		break;
	case 2: // two storages in series
		break;
	} // end switch(m_StorConf)
}
//---------------------------------------------------------------------


void Cihacres_climate_scen_db::_SetSimulationValues(double *array, int scenario, PGresult *res, int nfields)
{
	int plus = nfields - m_nDaysPeriod;
	array[0] = 0.0;
	for (unsigned int day = 0; day < m_nDaysPeriod; day++) {
		array[day+1] = convert_sl::StringToDouble(PQgetvalue(res,scenario,day + plus));
	}
}
//---------------------------------------------------------------------


//---------------------------------------------------------------------
// INITIALIZE
//---------------------------------------------------------------------
bool Cihacres_climate_scen_db::_Initialize()
{
	unsigned int	nval = m_nDaysPeriod + 1;

	m_p_Q_sim_mmday = new double[nval];
	m_pTw			= new double[nval];
	m_pWI			= new double[nval];
	m_pER			= new double[nval];
	m_pMeltRate		= new double[nval];
	m_pPCP			= new double[nval];
	m_pTMP			= new double[nval];

	m_res_pcp		= NULL;
	m_res_tmp		= NULL;

	// read initial combinations
	if ( m_DB.CheckAccessibility(m_apiqTable) ) {
		m_nParameterCombinations = m_DB.GetNumberRows(m_apiqTable.c_str());;
		m_pInit = new CInit_values(m_nParameterCombinations);
		if ( _ReadAPIQTable() ){

			// check scenario tables
			if ( m_DB.CheckAccessibility(m_rainfallTable) &&
				 m_DB.CheckAccessibility(m_temperatureTable) ) {
				
				// assign number of scenarios
				m_nClimateScenarios = m_DB.GetNumberRows(m_rainfallTable.c_str());
				m_nScenarios = m_nParameterCombinations * m_nClimateScenarios;

				// read rainfall and temperature scenario tables
			    Process_Set_Text("Reading Scenario tables...");
				Message_Add("Reading Scenario tables...");
				if ( _GetRainfallTable(m_rainfallTable) &&
					 _GetTemperatureTable(m_temperatureTable) ) {
					return(true);

				} else {
					Process_Set_Text("Could not read input tables!");
					return(false);
				}
			} else { // check scenario tables
				return(false);
				Process_Set_Text("Could not access scenario table!");
				Message_Add("Could not access scenario table!!",true);
			}
		} else { // if (_ReadAPIQTable())
			return(false);
		}
			
	} else { // if ( m_DB.CheckAccessibitlity(m_apiqTable) )
		Process_Set_Text("Could not access scenario table!");
		Message_Add("Could not access scenario table!",true);
		return(false);
	}
	return(true);
}
//---------------------------------------------------------------------

//---------------------------------------------------------------------

void Cihacres_climate_scen_db::_WriteOutputTable(int scenario_count, int scenario, int combination)
{
	std::string sql;
	sql = _SQL_INSERT_INTO(scenario_count, scenario, combination);

	m_DB.ExecSQL_str(sql);
}
//---------------------------------------------------------------------

string Cihacres_climate_scen_db::_SQL_INSERT_INTO(int scenario_count, int scenario, int combination)
{
	std::ostringstream ost;

	ost << "INSERT INTO ";
	ost << m_tableOut;
	ost << " (ID, idinit, idclimate, initAPI, initQ, initPCP, stormPCP, ";
	for (unsigned int i = 0; i < m_nDaysPeriod; i++) {
		ost << "Q_";
		ost << i+1;
		if (i == m_nDaysPeriod-1) {
			ost << ") ";
		} else {
			ost << ", ";
		}
	}
	ost << "VALUES (";
	ost << scenario_count;
	ost << ", ";
	ost << combination+1;
	ost << ", ";
	ost << scenario+1;
	ost << ", ";
	ost << m_pInit->pAPI[combination];
	ost << ", ";
	ost << m_pInit->pQ_mmday[combination] * m_Area / 86.4;
	ost << ", ";
	ost << PQgetvalue(m_res_pcp,scenario,1); // initPCP
	ost << ", ";
	ost << PQgetvalue(m_res_pcp,scenario,2); // stormPCP
	ost << ", ";
	for (unsigned int i = 1; i < m_nDaysPeriod+1; i++) {
		ost << m_p_Q_sim_mmday[i] * m_Area / 86.4;
		if (i == m_nDaysPeriod) {
			ost << ");";
		} else {
			ost << ", ";
		}
	}

	return(ost.str());
}
//---------------------------------------------------------------------
bool Cihacres_climate_scen_db::_CreateOutputTable()
{
	string sql = _SQL_CREATE();

	if ( m_DB.CheckAccessibility(m_tableOut) ) {
		m_DB.DropTable(m_tableOut);
	}

	if ( m_DB.ExecSQL_str(sql) ) {
		return(true);
	}
	return(false);
}
//---------------------------------------------------------------------
string Cihacres_climate_scen_db::_SQL_CREATE()
{
	string sql = "CREATE TABLE ";
	sql += m_tableOut;
	sql += " (ID int4 primary key, idinit int4, idclimate int4, initAPI float4, initQ float4, initPCP float4, stormPCP float4, ";
	for (unsigned int i = 0; i < m_nDaysPeriod; i++) {
		sql += "Q_";
		sql += convert_sl::Int2String(i+1);
		sql += " float4";
		if (i == m_nDaysPeriod-1) {
			sql += ");";
		} else {
			sql += ", ";
		}
	}
	return(sql);
}
//---------------------------------------------------------------------

bool Cihacres_climate_scen_db::_ReadAPIQTable()
{
	PGresult* res;
	string sql = _SQL_SELECT(m_apiqTable);

	res = PQexec (m_DB.conn, sql.c_str());
	if (!res || PQresultStatus (res) != PGRES_TUPLES_OK)
	{
		PQclear (res);
		//PQfinish (conn);
		return(false);
	} else {
		// read table
		for (unsigned int row = 0; row < m_nParameterCombinations; row++) {
			m_pInit->pAPI[row] = convert_sl::StringToDouble(PQgetvalue(res,row,0));
			m_pInit->pQ_mmday[row] = convert_sl::StringToDouble(PQgetvalue(res,row,1)) * 86.4 / m_Area;
			m_pInit->pER[row] = convert_sl::StringToDouble(PQgetvalue(res,row,2));
		}
		PQclear(res);
		return(true);
	}

	return(false);

}
//---------------------------------------------------------------------

bool Cihacres_climate_scen_db::_GetScenarioTable(PGresult* res, std::string tablename)
{
	string sql = _SQL_SELECT(tablename);

	res = PQexec(m_DB.conn, sql.c_str());
	if (!res || PQresultStatus (res) != PGRES_TUPLES_OK)
	{
		PQclear (res);
		return(false);
	} else {
		return(true);
	}
}
//---------------------------------------------------------------------

bool Cihacres_climate_scen_db::_GetRainfallTable(std::string tablename)
{
	string sql = _SQL_SELECT(tablename);

	m_res_pcp = PQexec(m_DB.conn, sql.c_str());
	if (!m_res_pcp || PQresultStatus (m_res_pcp) != PGRES_TUPLES_OK)
	{
		PQclear (m_res_pcp);
		return(false);
	} else {
		return(true);
	}
}
//---------------------------------------------------------------------

bool Cihacres_climate_scen_db::_GetTemperatureTable(std::string tablename)
{
	string sql = _SQL_SELECT(tablename);

	m_res_tmp = PQexec(m_DB.conn, sql.c_str());
	if (!m_res_tmp || PQresultStatus (m_res_tmp) != PGRES_TUPLES_OK)
	{
		PQclear (m_res_tmp);
		return(false);
	} else {
		return(true);
	}
}
//---------------------------------------------------------------------

string Cihacres_climate_scen_db::_SQL_SELECT(string tablename)
{
	string sql = "SELECT * FROM ";
	sql += tablename;
	return(sql);
}
//---------------------------------------------------------------------

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


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

	s.Printf("Node01", 01);
	pNode = Parameters.Add_Node(NULL,s,"Database connection parameters","");

	Parameters.Add_String(
		pNode	, "HOST"	, LNG("Host"),
		"",
		"localhost"
	);
	Parameters.Add_String(
		pNode	, "PORT"	, LNG("Port"),
		"",
		"5432"
	);
	Parameters.Add_String(
		pNode	, "OPTIONS"	, LNG("Options"),
		"",
		""
	);
	Parameters.Add_String(
		pNode	, "TTY"	, LNG("tty"),
		"",
		""
	);
	Parameters.Add_String(
		pNode	, "DBNAME"	, LNG("Database Name"),
		"",
		""
	);
	Parameters.Add_String(
		pNode	, "USER"	, LNG("User"),
		"",
		""
	);
	Parameters.Add_String(
		pNode	, "PW"		, LNG("Password"),
		"",
		"", false, true
	);

	//-----------------------------------------------------------------
	//		MODEL PARAMETERS
	//-----------------------------------------------------------------
	s.Printf("Node02", 02);
	pNode = Parameters.Add_Node(NULL,s,"Model parameters","");

	Parameters.Add_Value(
		pNode,	"N_DAYS_PERIOD",	_TL("Number of Days in a Simulation"),
		_TL("Number of days in a simulation period"),
		PARAMETER_TYPE_Int
	);

	Parameters.Add_Value(
		pNode,	"AREA", _TL("Catchment Area [km2]"),
			_TL(""),
			PARAMETER_TYPE_Double
	);

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

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

	Parameters.Add_Value(
		pNode,	"SNOW_MODULE",	_TL("Using the snow-melt module?"),
		_TL("If checked, snow-melt module is used."),
		PARAMETER_TYPE_Bool, false
	);
	//-----------------------------------------------------------------

}
//---------------------------------------------------------------------

//---------------------------------------------------------------------
//		DIALOG 2
//---------------------------------------------------------------------
bool Cihacres_climate_scen_db::_CreateDialog2()
{
	CSG_Parameter	*pNode, *pNode1;
	CSG_Parameters	P;
	CSG_String s;

	P.Set_Name(_TL("IHACRES Climate Scenarios (Dialog 2)"));

	//-----------------------------------------------------------------
	// climate scenario input tables
	//-----------------------------------------------------------------
	s.Printf("Node01", 01);
	pNode = P.Add_Node(NULL,s,"API-Q-Table","");

	P.Add_Choice(
		pNode	, "APIQER"		, "API-Q table",
		"",
		m_DB.GetDBTables().c_str()
	);

	s.Printf("Node02", 02);
	pNode = P.Add_Node(NULL,s,"Rainfall sceanrios","");

	P.Add_Choice(
		pNode	, "PCPTABLE"		, "Rainfall scenario table",
		"",
		m_DB.GetDBTables().c_str()
	);
	
	s.Printf("Node03", 03);
	pNode = P.Add_Node(NULL,s,"Temperature sceanrios","");

	P.Add_Choice(
		pNode	, "TMPTABLE"		, "Temperature scenario table",
		"",
		m_DB.GetDBTables().c_str()
	);

	s.Printf("Node031", 031);
	pNode = P.Add_Node(NULL,s,"Simulation table name","");

	P.Add_String(pNode, "TABLEOUT", "Simulation table (output)",
		"", ""
	);
	
	//-----------------------------------------------------------------

	//-----------------------------------------------------------------
	//		MODEL PARAMETERS
	//-----------------------------------------------------------------
	// Parameters of non-linear module -------------------------
	s.Printf("Node033", 033);
	pNode1 = P.Add_Node(NULL,s,"IHACRES model parameters","");

	s.Printf("Node40", 40);
	pNode = P.Add_Node(pNode1,s,"Non-Linear Module","");
	P.Add_Value(
		pNode,	"TwFAC",	_TL("Wetness decline time constant (Tw)"),
		_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	, "TFAC"		, "Temperature Modulation Factor (f)",
		_TL("Temperature Modulation Factor f"),
		PARAMETER_TYPE_Double,
		1.0, 0.0001, true, 10.0, true
	);
	P.Add_Value(
		pNode,	"CFAC",	_TL("Parameter (c)"),
		_TL("Parameter (c) to fit streamflow volume"),
		PARAMETER_TYPE_Double,
		0.001, 0.0, true, 1.0, true
	);
	switch(m_IHAC_version)
	{
	case 0: // Jakeman & Hornberger (1993)
		break;
	case 1: // Croke et al. (2005)
		s.Printf("Node41", 41);
		pNode = P.Add_Node(pNode1,s,"Soil Moisture Power Eq.","");

		P.Add_Value(
			pNode,	"LFAC",	_TL("Parameter (l)"),
			_TL("Soil moisture index threshold"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
		P.Add_Value(
			pNode,	"PFAC",	_TL("Parameter (p)"),
			_TL("non-linear response term"),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 5.0, true
		);
			break;
	}
	// Parameters of non-linear module -------------------------

	// Parameters of linear module -----------------------------
	switch(m_StorConf)
	{
	case 0: // single storage
		s.Printf("Node50", 50);
		pNode = P.Add_Node(pNode1,s,"Linear Module","");

		P.Add_Value(
			pNode,	"AFAC",	_TL("(a)"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.8, -0.99, true, -0.01, true
		);

		P.Add_Value(
			pNode,	"BFAC",	_TL("(b)"),
			_TL(""),
			PARAMETER_TYPE_Double,
			0.2, 0.001, true, 1.0, true
		);
		break;

	case 1: // two parallel storages
		s.Printf("Node50", 50);
		pNode = P.Add_Node(pNode1,s,"Linear Module","");

		// Parameter a
		P.Add_Value(
			pNode,	"AQ",	_TL("a(q)"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.7, -0.99, true, -0.01, true
		);
		P.Add_Value(
			pNode,	"AS",	_TL("a(s)"),
			_TL(""),
			PARAMETER_TYPE_Double,
			-0.9, -0.99, true, -0.01, true
		);

		// Parameter b
		P.Add_Value(
			pNode,	"BQ",	_TL("b(q)"),
			_TL(""),
			PARAMETER_TYPE_Double,
			0.0, 0.0, true, 1.0, true
		);
		break;

	case 2: // two storages in series
		break;
	} // end switch (storconf)
	// Parameters of linear module -----------------------------

	s.Printf("Node55", 55);
	pNode = P.Add_Node(pNode1,s,"Time Delay after Start of Rainfall (INTEGER)","");
		
	P.Add_Value(
		pNode,	"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
	);

	// snow module parameters ----------------------------------
	if (m_bSnowModule)
	{
	s.Printf("Node60", 60);
	pNode = P.Add_Node(pNode1,s,"Snow Module Parameters","");
		
		P.Add_Value(
			pNode,	"T_RAIN",	"Temperature Threshold for Rainfall",
			"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",	"Temperature Threshold for Melting",
			"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",	"Day-Degree Factor",
			"Day-Degree Factor depends on catchment characteristics",
			PARAMETER_TYPE_Double,
			0.7, 0.7, true, 9.2, true
		);
	}
	// snow module parameters ----------------------------------

	if( SG_UI_Dlg_Parameters(&P, _TL("IHACRES Climate Scenarios (Dialog 2)")) )
	{
		m_apiqTable			= P("APIQER")		->asString();
		m_rainfallTable		= P("PCPTABLE")		->asString();
		m_temperatureTable	= P("TMPTABLE")		->asString();
		m_tableOut			= P("TABLEOUT")		->asString();

		// non-linear module parameters
		m_p_nonlinparms->mp_tw[0]	= P("TwFAC")		->asDouble();
		m_p_nonlinparms->mp_f[0]	= P("TFAC")			->asDouble();
		m_p_nonlinparms->mp_c[0]	= P("CFAC")			->asDouble();
		switch(m_IHAC_version)
		{
		case 0: // Jakeman & Hornberger (1993)
			break;
		case 1: // Croke et al. (2005)
			m_p_nonlinparms->mp_l[0]= P("LFAC")			->asDouble();
			m_p_nonlinparms->mp_p[0]= P("PFAC")			->asDouble();
		}

		// linear module parameters
		switch(m_nStorages)
		{
		case 1: // single storage
			m_p_linparms->a[0]		= P("AFAC")			->asDouble();
			m_p_linparms->b[0]		= P("BFAC")			->asDouble();
			break;
		case 2: // two storages
			m_p_linparms->aq[0]		= P("AQ")			->asDouble();
			m_p_linparms->bq[0]		= P("BQ")			->asDouble();
			m_p_linparms->as[0]		= P("AS")			->asDouble();
			m_p_linparms->bs[0] = ihacres.Calc_Parm_BS(m_p_linparms->aq[0],m_p_linparms->as[0],m_p_linparms->bq[0]);
			break;
		}

		m_delay						= P("DELAY")		->asInt();	

		if (m_bSnowModule)
		{
			m_snowparms.T_Rain		= P("T_RAIN")		->asDouble();
			m_snowparms.T_Melt		= P("T_MELT")		->asDouble();
			m_snowparms.DD_FAC		= P("DD_FAC")		->asDouble();
		}

		return(true);
	}
	return(false);
}




