#include "gr4j_cal.h"
//#include "model_tools.h"
#include ".\..\model_tools.h"
#include "convert_sl.h"

#include <time.h>	// random numbers initialization
#include <string>

#include <fstream>

Cgr4j_cal::Cgr4j_cal()
{
	//-----------------------------------------------------
	// 1. Info...
	Set_Name("GR4J Calibration");

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

	Set_Description("The Rainfall-Runoff Model GR4J \n \n \n"
		"Reference: \n \n"
		"Perrin, C., Michel, C., Andreassian, V. (2003). \n"
		"Improvement of a parsimonious model for streamflow simulation \n"
		"Journal of Hydrology, 279, p. 275-289. \n"
	);

	///////////////////////////////////////////////////////////////////
	// FIRST MODULE DIALOG
	_CreateDialog1();
	///////////////////////////////////////////////////////////////////
}

Cgr4j_cal::~Cgr4j_cal()
{
}

bool Cgr4j_cal::On_Execute()
{
	//---------------------------------------------------------------
	//				PARAMETERS
	//---------------------------------------------------------------
	CSG_Table		*pTable, *pTable_out, *pTable_sim, *pTable_snow, *pTable_snow_parms;
	// table field numbers
	int				dateField;
	int				dischargeField;
	int				pcpField;
	int				pet_tmpField;
	// used time series (0 = ETp, 1 = temperature)
	int				Choice_ETp_TMP;

	CSG_String		date1, date2;
	int				first, last;
	double			Latitude;

	// Assign Parameters from Module Dialog
	//---------------------------------------------------------
	pTable			= Parameters("TABLE")			->asTable();
	// Field numbers
	dateField		= Parameters("DATE_Field")		->asInt();
	dischargeField	= Parameters("DISCHARGE_Field")	->asInt();
	pcpField		= Parameters("PCP_Field")		->asInt();
	pet_tmpField	= Parameters("ETP_TMP_Field")	->asInt();
	// used time series
	Choice_ETp_TMP	= Parameters("ETP_TMP_TS")		->asInt();
	m_bSnowModule	= Parameters("bSNOW")			->asBool();
	m_nsim			= Parameters("NSIM")			->asInt();
	m_nbestsim		= Parameters("NbestSIM")		->asInt();
	m_NSE_MIN		= Parameters("MIN_NSE")			->asDouble();
	// Parameters
	X_lb.X1			= Parameters("X1_lb")			->asDouble();
	X_ub.X1			= Parameters("X1_ub")			->asDouble();
	X_lb.X2			= Parameters("X2_lb")			->asDouble();
	X_ub.X2			= Parameters("X2_ub")			->asDouble();
	X_lb.X3			= Parameters("X3_lb")			->asDouble();
	X_ub.X3			= Parameters("X3_ub")			->asDouble();
	X_lb.X4			= Parameters("X4_lb")			->asDouble();
	X_ub.X4			= Parameters("X4_ub")			->asDouble();
	//---------------------------------------------------------

	//---------------------------------------------------------
	// Create Second Dialog and assign parameters
	if ( _CreateDialog2(pTable, dateField, date1, date2, Choice_ETp_TMP, m_bSnowModule, Latitude, m_area) )
	{
		//---------------------------------------------------------

		//---------------------------------------------------------
		// searching the first and the last record of the time range
		gr4j.AssignFirstLastRec(*pTable, first, last, date1, date2, dateField);
		sizeAll = last - first + 1;
		//---------------------------------------------------------

		//---------------------------------------------------------
		// initialize struct Input
		_InitInput(Input, sizeAll, Choice_ETp_TMP, m_area, Latitude, pTable,
					dateField, dischargeField, pcpField, pet_tmpField,
					first, last);
		//---------------------------------------------------------

		//---------------------------------------------------------
		//		MONTE CARLO SIMULATION
		//---------------------------------------------------------
		X				= new GR4J_Parameters[m_nsim];
		m_pNSE			= new double[m_nsim];
		m_pNSE_highflow	= new double[m_nsim];
		//---------------------------------------------------------
		// simulate discharge (not using the snow module here)
		// goodness of simulations are stored in m_pNSE
		_Simulate(m_NSE_MIN);
		//---------------------------------------------------------

		//---------------------------------------------------------
		// Find best m_nbestsim simulations
		// assign 'm_bestsimcount'
		_Find_BestSimulations(m_nbestsim);
		//---------------------------------------------------------

		//*********************************************************
		// If the SNOW MODULE is active the best simulation will
		// be used to calibrate the snow module using Monte Carlo Simulation
		if (m_bSnowModule)
		{
			_Calibrate_SnowModule();
			// calculate m_nbestsim simulations
			Process_Set_Text("Calculate best simulations...");
			_Calc_BestSimulationsSnow();
		} else {
			// if the snow module is not active
			_Calc_BestSimulationsNoSnow();
		}
		//*********************************************************


		//---------------------------------------------------------
		// write calibration parameters and NSE in output table
		Process_Set_Text("Write output tables...");
		pTable_out = SG_Create_Table();
		if (!m_bSnowModule)
			_CreateTableCal(pTable_out, X, m_pNSE, m_pNSE_highflow, m_NSE_MIN, m_nsim);
		else
			//_CreateTableCal(pTable_out, X, m_pNSE_SNOW, m_NSE_MIN, m_nsim, 
			_CreateTableCal(pTable_out, X, m_pNSE_SNOW, m_pNSE_highflow, m_NSE_MIN, m_nsim_snow, 
							mT_Rain[m_pTopNSE_SNOW[0]], mT_Melt[m_pTopNSE_SNOW[0]], mDD_FAC[m_pTopNSE_SNOW[0]]);

		pTable_out->Set_Name("GR4J_Cal");
		Parameters("TABLEout")->Set_Value(pTable_out);
		// write m_nbestsim simulations in output table
		if (m_bSnowModule)
		{
			pTable_snow = SG_Create_Table();
			_CreateTableSnow(pTable_snow, m_bestsimcount*2, Input, m_pQ_sim_best, sizeAll, m_area);
			pTable_snow->Set_Name("GR4J_SimSnow");
			Parameters("TABLEsnow")->Set_Value(pTable_snow);

			pTable_snow_parms = SG_Create_Table();
			_CreateTableSnowParms(pTable_snow_parms,m_nsim_snow, m_pNSE_SNOW,mT_Rain, mT_Melt, mDD_FAC);
			pTable_snow_parms->Set_Name("GR4J_SnowParms");
			Parameters("TABLEsnowparms")->Set_Value(pTable_snow_parms);
		} else {
			pTable_sim = SG_Create_Table();
			_CreateTableSim(pTable_sim, m_nbestsim, Input, m_pQ_sim_best, sizeAll, m_area);
			pTable_sim->Set_Name("GR4J_Sim");
			Parameters("TABLEsim")->Set_Value(pTable_sim);
		}
		//---------------------------------------------------------


		Input.date.resize(0);
		delete[] Input.pET;
		delete[] Input.precipitation;
		delete[] Input.Q_obs;
		if (Choice_ETp_TMP == 1)
		{
			delete[] temperature;
			//delete ETp; wird bereits in _InitInput deleted
		}
		delete[] X;
		delete[] m_pNSE;
		delete[] m_pNSE_highflow;
		delete[] m_TopNSE;
		if (!m_bSnowModule)
		{
			for (int i = 0; i < m_bestsimcount; i++)
				delete[] m_pQ_sim_best[i].Q_sim;
			delete[] m_pQ_sim_best;
		}
		if (m_bSnowModule)
		{
			delete[] mT_Rain;
			delete[] mT_Melt;
			delete[] mDD_FAC;
			delete[] m_pTopNSE_SNOW;
			delete[] m_pNSE_SNOW;
			for (int i = 0; i < m_bestsimcount*2; i++)
				delete[] m_pQ_sim_best[i].Q_sim;
			delete[] m_pQ_sim_best;
		}

		return(true);
	}
	return(false);
}
//-------------------------------------------------------------------

void Cgr4j_cal::_Simulate(double NSE_MIN)
{
	string			nse;
	string			nse_text;
	// efficiency output parameters to status bar
	double			NSE_temp = -100.0;

	//		Generate Random Numbers
	// initialize random function
	srand((unsigned) time(NULL)); // using time.h
	for (int sim = 0; sim < m_nsim && Set_Progress(sim,m_nsim); sim++)
	{
		X[sim].X1 = model_tools::Random_double(X_lb.X1, X_ub.X1);
		X[sim].X2 = model_tools::Random_double(X_lb.X2, X_ub.X2);
		X[sim].X3 = model_tools::Random_double(X_lb.X3, X_ub.X3);
		X[sim].X4 = model_tools::Random_double(X_lb.X4, X_ub.X4);
		//-----------------------------------------------------
		//		STREAMFLOW SIMULATION
		gr4j.Simulation(Input, X[sim]);
		//-----------------------------------------------------
		//		Calculate Efficiency
		m_pNSE[sim] = model_tools::CalcEfficiency(Input.Q_obs, gr4j.Q_sim, sizeAll);
		m_pNSE_highflow[sim] = model_tools::Calc_NSE_HighFlow(Input.Q_obs, gr4j.Q_sim, sizeAll);
		// write current efficiency value to status bar
		if (m_pNSE[sim] > NSE_temp)
		{
			NSE_temp = m_pNSE[sim];
			nse = convert_sl::Double2String(NSE_temp);
			if (NSE_temp > NSE_MIN)
			{
				nse_text = "max. Nash Sutcliffe Efficiency: " + nse;
				Process_Set_Text(nse_text.c_str());
			}
		}
		//-----------------------------------------------------
		// delete pointers that were created with 'new' in gr4j.Simulation()
		gr4j.free_memory();
		//-----------------------------------------------------
	}
}
//-------------------------------------------------------------------

void Cgr4j_cal::_Find_BestSimulations(int nbestsim)
{
	m_TopNSE = new int[m_nbestsim];
	model_tools::FindHighestIndices(m_pNSE, m_nsim, m_TopNSE, m_nbestsim, m_NSE_MIN);
	// count number of best simulations
	m_bestsimcount = 0;
	for (int i = 0; i < m_nbestsim; i++)
		if (m_TopNSE[i] > -1) m_bestsimcount++;
}
//-------------------------------------------------------------------

void Cgr4j_cal::_Calibrate_SnowModule()
{
		Process_Set_Text("Calibrate Snow Module...");
		m_nsim_snow = 1000;
		m_pNSE_SNOW = new double[m_nsim_snow];
		mT_Rain = new double[m_nsim_snow];
		mT_Melt = new double[m_nsim_snow];
		mDD_FAC = new double[m_nsim_snow];

		srand((unsigned) time(NULL)); // using time.h
		for (int i = 0; i < m_nsim_snow && Set_Progress(i,m_nsim_snow); i++)
		{
			// assign random parameters
			mT_Rain[i] = model_tools::Random_double(mT_Rain_lb, mT_Rain_ub);
			mT_Melt[i] = model_tools::Random_double(mT_Melt_lb, mT_Melt_ub);
			mDD_FAC[i] = model_tools::Random_double(mDD_FAC_lb, mDD_FAC_ub);

			pSnowModule = new CSnowModule(temperature, Input.precipitation,
										  mT_Rain[i], mT_Melt[i], mDD_FAC[i], sizeAll);

			pgr4j = new Cgr4j(Input, temperature, pSnowModule);
			pgr4j->Simulation(Input, X[m_TopNSE[0]]);
			m_pNSE_SNOW[i] = model_tools::CalcEfficiency(Input.Q_obs, pgr4j->Q_sim, sizeAll);

			delete pSnowModule;
			pgr4j->free_memory();
			delete pgr4j;
		}
		//---------------------------------------------------------
		// Find best m_nbestsim simulations
		m_pTopNSE_SNOW = new int[m_nbestsim];
		model_tools::FindHighestIndices(m_pNSE_SNOW, m_nsim_snow, m_pTopNSE_SNOW, m_nbestsim, m_NSE_MIN);
		//---------------------------------------------------------	
		// perform best streamflow simulation with best snow module simulation
		pSnowModule = new CSnowModule(temperature, Input.precipitation,
									  mT_Rain[m_pTopNSE_SNOW[0]], mT_Melt[m_pTopNSE_SNOW[0]], mDD_FAC[m_pTopNSE_SNOW[0]], sizeAll);
		pgr4j = new Cgr4j(Input, temperature, pSnowModule);
		pgr4j->Simulation(Input, X[m_TopNSE[0]]);

		ofstream snowsim("snowsim.txt");
		snowsim << "Date, obs, sim_Snow" << endl;
		for (int j = 0; j < sizeAll; j++)
			snowsim << Input.date[j] << ", " << ", " << Input.Q_obs[j] << ", " << pgr4j->Q_sim[j]* m_area / 86.4 << endl;

		delete pSnowModule;
		pgr4j->free_memory();
		delete pgr4j;
		
		//delete[] m_pNSE_SNOW;
}
//-------------------------------------------------------------------
void Cgr4j_cal::_Calc_BestSimulationsSnow()
{

	pSnowModule = new CSnowModule(temperature, Input.precipitation,
								  mT_Rain[m_pTopNSE_SNOW[0]], mT_Melt[m_pTopNSE_SNOW[0]], mDD_FAC[m_pTopNSE_SNOW[0]], sizeAll);

	int top_index = 0;
	m_pQ_sim_best = new Q_sim_out[m_bestsimcount*2];
	for (int i = 0; i < m_bestsimcount*2; i+=2)
	{
		m_pQ_sim_best[i].Q_sim = new double[sizeAll];
		// simulate streamflow without snow module
		gr4j.Simulation(Input, X[m_TopNSE[top_index]]);
		for (int j = 0; j < sizeAll; j++)
			m_pQ_sim_best[i].Q_sim[j] = gr4j.Q_sim[j] * m_area / 86.4;
		gr4j.free_memory();

		// simulate streamflow with snow module
		m_pQ_sim_best[i+1].Q_sim = new double[sizeAll];
		pgr4j = new Cgr4j(Input, temperature, pSnowModule);
		pgr4j->Simulation(Input, X[m_TopNSE[top_index]]);
		for (int j = 0; j < sizeAll; j++)
			m_pQ_sim_best[i+1].Q_sim[j] = pgr4j->Q_sim[j] * m_area / 86.4;
			pgr4j->free_memory();
		delete pgr4j;
		top_index++;
	}
	delete pSnowModule;
}
//-------------------------------------------------------------------

void Cgr4j_cal::_Calc_BestSimulationsNoSnow()
{
	m_pQ_sim_best = new Q_sim_out[m_bestsimcount];
	for (int i = 0; i < m_bestsimcount; i++)
	{
		m_pQ_sim_best[i].Q_sim = new double[sizeAll];
		// simulate streamflow
		gr4j.Simulation(Input, X[m_TopNSE[i]]);
		for (int j = 0; j < sizeAll; j++)
			m_pQ_sim_best[i].Q_sim[j] = gr4j.Q_sim[j] * m_area / 86.4;
		gr4j.free_memory();
	}
}
//-------------------------------------------------------------------

void Cgr4j_cal::_InitInput(InputData& Input, int sizeAll, int Choice_ETp_TMP,
						   double area, double Latitude, CSG_Table* pTable,
						   int dateField, int dischargeField,
						   int pcpField, int pet_tmpField,
						   int first, int last)
{
	int j, k;
	// initialize struct Input
	Input.date.resize(sizeAll);
	Input.Q_obs = new double[sizeAll];
	Input.precipitation = new double[sizeAll];
	Input.pET = new double[sizeAll];
	Input.size = sizeAll;
	if (Choice_ETp_TMP == 1) temperature = new double[sizeAll];
	//---------------------------------------------------------
	// assign data to struct Input
	//for (int i = 0; i < sizeAll; i++)
	for (j = 0, k = first; j < sizeAll, k < last + 1; j++, k++)
	{
		// put the date string into the vector
		Input.date[j].append(pTable->Get_Record(k)->asString(dateField));
		//Input.date[i].append(pTable->Get_Record(i)->asString(dateField));
		// convert Q_obs from m3/s to mm/day
		Input.Q_obs[j] = (pTable->Get_Record(k)->asDouble(dischargeField) * 86.4 / area);
		Input.precipitation[j] = (pTable->Get_Record(k)->asDouble(pcpField));
		if (Choice_ETp_TMP == 0) // if ETp data was selected
			Input.pET[j] = (pTable->Get_Record(k)->asDouble(pet_tmpField));
		else
			temperature[j] = (pTable->Get_Record(k)->asDouble(pet_tmpField));
	}
	// if no ETp data available the temperature time series is used
	// to calculate ETp after Hamon (1961)
	if (Choice_ETp_TMP == 1) // if temperature data was selected
	{
		int first_year, month, day;
		_Get_Date_Int(Input.date[0], first_year, month, day);
		// calculate ETp
		ETp = new CpET(temperature, sizeAll, Latitude, first_year);
		// assign ETp to Input.pET
		for (int i = 0; i < sizeAll; i++)
			Input.pET[i] = ETp->Get_pET_Hamon(i);
	
		delete ETp;
		//delete[] temperature;
	}
}
//-------------------------------------------------------------------

///////////////////////////////////////////////////////////////////////
//
//                          CREATE OUTPUT TABLES
//
///////////////////////////////////////////////////////////////////////

void Cgr4j_cal::_CreateTableCal(CSG_Table *pTable,
								GR4J_Parameters* X,
								double* NSE, double* NSE_high, double NSE_MIN,
								int nsim)
{
	int i = 0; // used in function Get_Record(i)
	CSG_Table_Record	*pRecord;

	// creating the column titles
	pTable->Add_Field("NSE",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("NSE_high",	TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X1",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X2",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X3",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X4",			TABLE_FIELDTYPE_Double);

	for (int j = 0; j < nsim; j++)
	{
		if (NSE[j] >= NSE_MIN)
		{
			pTable->Add_Record();
			pRecord = pTable->Get_Record(i);

			// writing the data into the rows
			pRecord->Set_Value(0,NSE[j]);
			pRecord->Set_Value(1,NSE_high[j]);
			pRecord->Set_Value(2,X[j].X1);
			pRecord->Set_Value(3,X[j].X2);
			pRecord->Set_Value(4,X[j].X3);
			pRecord->Set_Value(5,X[j].X4);
			i++;
		}
	}
}
//---------------------------------------------------------------------

void Cgr4j_cal::_CreateTableCal(CSG_Table *pTable,
								GR4J_Parameters* X,
								double* NSE_SNOW, double* NSE_high, double NSE_MIN,
								int nsim,
								double t_rain,double t_melt, double dd_fac)
{
	int i = 0; // used in function Get_Record(i)
	CSG_Table_Record	*pRecord;

	// creating the column titles
	pTable->Add_Field("NSE",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("NSE_high",	TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X1",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X2",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X3",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("X4",			TABLE_FIELDTYPE_Double);
	pTable->Add_Field("T_RAIN",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("T_MELT",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("DD_FAC",		TABLE_FIELDTYPE_Double);

	for (int j = 0; j < nsim; j++)
	{
		if (NSE_SNOW[j] >= NSE_MIN)
		{
			pTable->Add_Record();
			pRecord = pTable->Get_Record(i);

			// writing the data into the rows
			pRecord->Set_Value(0,NSE_SNOW[j]);
			pRecord->Set_Value(1,NSE_high[j]);
			pRecord->Set_Value(2,X[j].X1);
			pRecord->Set_Value(3,X[j].X2);
			pRecord->Set_Value(4,X[j].X3);
			pRecord->Set_Value(5,X[j].X4);
			pRecord->Set_Value(6,t_rain);
			pRecord->Set_Value(7,t_melt);
			pRecord->Set_Value(8,dd_fac);
			i++;
		}
	}
}
//---------------------------------------------------------------------
// Create Simulation Output Table if snow module was NOT active
//---------------------------------------------------------------------
void Cgr4j_cal::_CreateTableSim(CSG_Table *pTable, int nbestsim,
								InputData Input,
								Q_sim_out *Q_sim_best, int sizeAll, double area)
{
	int i = 0; // used in function Get_Record(i)
	CSG_Table_Record	*pRecord;
	string				title1 = "sim";
	string				number = "";
	string				title="";

	// creating the column titles
	pTable->Add_Field("Date",		TABLE_FIELDTYPE_String);
	pTable->Add_Field("Obs",		TABLE_FIELDTYPE_Double);
	for (int j = 0; j < nbestsim; j++)
	{
		title = title1 + convert_sl::Int2String(j+1);
		pTable->Add_Field(title.c_str(),	TABLE_FIELDTYPE_Double);
		title = "";
	}
	for (int j = 0; j < sizeAll; j++)
	{
		pTable->Add_Record();
		pRecord = pTable->Get_Record(i);
		pRecord->Set_Value(0,Input.date[j].c_str());
		pRecord->Set_Value(1,Input.Q_obs[j] * area / 86.4);
		for (int x = 2; x < nbestsim + 2; x++)
			pRecord->Set_Value(x,Q_sim_best[x-2].Q_sim[j]);
		i++;
	}
}
//---------------------------------------------------------------------
// Create Simulation Output Table if SNOW MODULE IS active
//---------------------------------------------------------------------
void Cgr4j_cal::_CreateTableSnow(CSG_Table *pTable, int nbestsim,
								InputData Input,
								Q_sim_out *Q_sim_best, int sizeAll, double area)
{
	int i = 0; // used in function Get_Record(i)
	CSG_Table_Record	*pRecord;
	string				title1 = "sim";
	string				title2 = "sim_snow";
	string				number = "";
	string				title="";

	// creating the column titles
	pTable->Add_Field("Date",		TABLE_FIELDTYPE_String);
	pTable->Add_Field("Obs",		TABLE_FIELDTYPE_Double);

	for (int j = 0; j < nbestsim / 2; j++)
	{
		title = title1 + convert_sl::Int2String(j+1);
		pTable->Add_Field(title.c_str(),	TABLE_FIELDTYPE_Double);
		title = "";
		title = title2 + convert_sl::Int2String(j+1);
		pTable->Add_Field(title.c_str(),	TABLE_FIELDTYPE_Double);
		title = "";
	}

	for (int j = 0; j < sizeAll; j++)
	{
		pTable->Add_Record();
		pRecord = pTable->Get_Record(i);
		pRecord->Set_Value(0,Input.date[j].c_str());
		pRecord->Set_Value(1,Input.Q_obs[j] * area / 86.4);
		for (int x = 2; x < nbestsim + 2; x++)
			pRecord->Set_Value(x,Q_sim_best[x-2].Q_sim[j]);
		i++;
	}
}
//---------------------------------------------------------------------

void Cgr4j_cal::_CreateTableSnowParms(CSG_Table *pTable, int nsim, double *NSE_SNOW,
									  double *t_rain,double *t_melt, double *dd_fac)
{
	CSG_Table_Record	*pRecord;

	// creating the column titles
	pTable->Add_Field("NSE",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("T_RAIN",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("T_MELT",		TABLE_FIELDTYPE_Double);
	pTable->Add_Field("DD_FAC",		TABLE_FIELDTYPE_Double);

	for (int j = 0; j < nsim; j++)
	{
		pTable->Add_Record();
		pRecord = pTable->Get_Record(j);
		pRecord->Set_Value(0,NSE_SNOW[j]);
		pRecord->Set_Value(1,t_rain[j]);
		pRecord->Set_Value(2,t_melt[j]);
		pRecord->Set_Value(3,dd_fac[j]);
	}
}

//---------------------------------------------------------------------
// Converting a date string 'YYYYMMDD' to three separate integer values

void Cgr4j_cal::_Get_Date_Int(string date, int &year, int &month, int &day)
{
	// divide date string to year, month, and day string
	string y(date.c_str(),0,4);
	string m(date.c_str(),4,2);
	string d(date.c_str(),6,2);

	// convert to integer
	sscanf(y.c_str(),"%d",&year);
	sscanf(m.c_str(),"%d",&month);
	sscanf(d.c_str(),"%d",&day);
}
//---------------------------------------------------------------------

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

void Cgr4j_cal::_CreateDialog1()
{
	CSG_Parameter	*pNode;
	CSG_String s;

	//---------------------------------------------------------------
	// Input Table
	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 [m3/s]"),
		"Select the Column containing Discharge Values"
	);

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

	Parameters.Add_Table_Field(
		pNode	, "ETP_TMP_Field"	, _TL("ETp or Temperature Column"),
		"Select the Column containing Temperature Values"
	);

	Parameters.Add_Choice(
		pNode	, "ETP_TMP_TS"		, "Specify which time series you are using!",
		"",
		CSG_String::Format("%s|%s|",
			_TL("ETp [mm]"),			//  0
			_TL("mean air temperature [°C]")	//  1 
		)
	);
	Parameters.Add_Value(
		pNode,	"bSNOW",	_TL("Use Snow Module"),
		_TL("The snow module can only be used if temperature is used"),
		PARAMETER_TYPE_Bool
	);

	//---------------------------------------------------------------
	s.Printf("Node2", 2);
		pNode = Parameters.Add_Node(NULL,s,"Number of Simulations","");
	Parameters.Add_Value(
		pNode,	"NSIM",	_TL("Number of Simulations"),
		_TL("Number of Simulations"),
		PARAMETER_TYPE_Int,
		10000, 1, true, 10000000, true
	);
	Parameters.Add_Value(
		pNode,	"NbestSIM",	_TL("Number of best Simulations for Output"),
		_TL("Number of best Simulations that will be written in an output table"),
		PARAMETER_TYPE_Int,
		10, 1, true, 100000, true
	);
	s.Printf("Node2-1", 2-1);
		pNode = Parameters.Add_Node(NULL,s,"Minimum Nash-Sutcliffe","");
	Parameters.Add_Value(
		pNode,	"MIN_NSE",	_TL("Nash-Sutcliffe Efficiency"),
		_TL("Minimum Nash-Sutcliffe Efficiency for output"),
		PARAMETER_TYPE_Double,
		0.6, 0.0, true, 1.0, true
	);
	//---------------------------------------------------------------
	// Input / Calibration Parameters
	s.Printf("Node2-2", 2-2);
		pNode = Parameters.Add_Node(NULL,s,"Free Parameters","");

	Parameters.Add_Value(
		pNode,	"X1_lb",	_TL("x1: Capacity of the production store [mm] (lower bound)"),
		_TL("(x1 lower bound) Capacity of the production store [mm]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);
	Parameters.Add_Value(
		pNode,	"X1_ub",	_TL("x1: Capacity of the production store [mm] (upper bound)"),
		_TL("(x1 upper bound) Capacity of the production store [mm]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);

	Parameters.Add_Value(
		pNode,	"X2_lb",	_TL("x2: Water exchange coefficient [mm] (lower bound)"),
		_TL("(x2 lower bound) Water exchange coefficient [mm]"),
		PARAMETER_TYPE_Double,
		0.0, -100.0, true, 100.0, true
	);
	Parameters.Add_Value(
		pNode,	"X2_ub",	_TL("x2: Water exchange coefficient [mm] (upper bound)"),
		_TL("(x2 upper bound) Water exchange coefficient [mm]"),
		PARAMETER_TYPE_Double,
		0.0, -100.0, true, 100.0, true
	);

	Parameters.Add_Value(
		pNode,	"X3_lb",	_TL("x3: Capacity of the routing store [mm] (lower bound)"),
		_TL("(x3 lower bound) Capacity of the routing store [mm]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);
	Parameters.Add_Value(
		pNode,	"X3_ub",	_TL("x3: Capacity of the routing store [mm] (upper bound)"),
		_TL("(x3 upper bound) Capacity of the routing store [mm]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);

	Parameters.Add_Value(
		pNode,	"X4_lb",	_TL("x4: Time base of the unit hydrograph [days] (lower bound)"),
		_TL("(x4 lower bound) Time base of the unit hydrograph [days]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);
	Parameters.Add_Value(
		pNode,	"X4_ub",	_TL("x4: Time base of the unit hydrograph [days] (upper bound)"),
		_TL("(x4 upper bound) Time base of the unit hydrograph [days]"),
		PARAMETER_TYPE_Double,
		0.0, 0.0, true, 50000.0, true
	);
	//---------------------------------------------------------------

	// output table for calibration parameter settings
	Parameters.Add_Table_Output(
		NULL	, "TABLEout"	, _TL("Table_out"),
		""
	);
	Parameters.Add_Table_Output(
		NULL	, "TABLEsim"	, _TL("Table_sim"),
		""
	);
	Parameters.Add_Table_Output(
		NULL	, "TABLEsnow"	, _TL("Table_snow"),
		""
	);
	Parameters.Add_Table_Output(
		NULL	, "TABLEsnowparms"	, _TL("Table_snow_parms"),
		""
	);
	//---------------------------------------------------------------
}

//-------------------------------------------------------------------
//						DIALOG 2
//-------------------------------------------------------------------

bool Cgr4j_cal::_CreateDialog2(CSG_Table* pTable, int dateField,
							  CSG_String& date1, CSG_String& date2,
							  int Choice_ETp_TMP, bool bSnowModule,
							  double& Latitude, double& area)
{
	CSG_String		s;
	CSG_Parameters	P;  // used to add Parameters in the second dialog
	CSG_Parameter	*pNode, *pNode1;

	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(""),
				 pTable->Get_Record(0)->asString(dateField));

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

	s.Printf("Node2", 2);
	pNode = P.Add_Node(NULL,s,"Catchment Area","");

	P.Add_Value(
		pNode,	"AREA",	_TL("Catchment Area in [km2]"),
		_TL("Catchment area in square kilometers, used to convert m3/s to mm"),
		PARAMETER_TYPE_Double,
		1.0, -0.0, true, 10000.0, true
	);

	if (Choice_ETp_TMP ==1)
	{
		s.Printf("Node2-1", 2-1);
		pNode = P.Add_Node(NULL,s,"Latitude","");

		P.Add_Value(
			pNode,	"LATITUDE",	_TL("Latitude of temperature station in [degrees]"),
			_TL("Latitude of temperature station in [degrees]"),
			PARAMETER_TYPE_Double,
			50.0, -90.0, true, 90.0, true
		);
	}

	if (bSnowModule)
	{
		s.Printf("Node4", 4);
		pNode = P.Add_Node(NULL,s,"Snow Module","");
		s.Printf("Node4-1", 4-1);
		pNode1 = P.Add_Node(pNode,s,"Snow Parameters","");

		P.Add_Value(
			pNode1,	"T_RAIN_LB",	_TL("Snowfall temperature (lower bound)"),
			_TL("Mean Air Temperature at which precipitation is likely to be snow"),
			PARAMETER_TYPE_Double,
			0.0, -5.0, true, 5.0, true
		);
		P.Add_Value(
			pNode1,	"T_RAIN_UB",	_TL("Snowfall temperature (upper bound)"),
			_TL("Mean Air Temperature at which precipitation is likely to be snow"),
			PARAMETER_TYPE_Double,
			0.0, -5.0, true, 5.0, true
		);

		P.Add_Value(
			pNode1,	"T_MELT_LB",	_TL("Snowmelt temperature (lower bound)"),
			_TL("Mean Air Temperature at which snow starts to melt"),
			PARAMETER_TYPE_Double,
			0.0, -5.0, true, 10.0, true
		);
		P.Add_Value(
			pNode1,	"T_MELT_UB",	_TL("Snowmelt temperature (upper bound)"),
			_TL("Mean Air Temperature at which snow starts to melt"),
			PARAMETER_TYPE_Double,
			0.0, -5.0, true, 10.0, true
		);

		P.Add_Value(
			pNode1,	"DD_FAC_LB",	_TL("Degree-Day Factor (lower bound)"),
			_TL("The degree-day factor is used to convert the degree-days to the depth of snowmelt."),
			PARAMETER_TYPE_Double,
			0.7, 0.7, true, 9.2, true
		);
		P.Add_Value(
			pNode1,	"DD_FAC_UB",	_TL("Degree-Day Factor (upper bound)"),
			_TL("The degree-day factor is used to convert the degree-days to the depth of snowmelt."),
			PARAMETER_TYPE_Double,
			9.2, 0.7, true, 9.2, true
		);
	}

	if( SG_UI_Dlg_Parameters(&P, _TL("Choose Time Range")) )
	{
		///////////////////////////////////////////////////////////////
		//
		//                ASSIGN DATA FROM SECOND DIALOG
		//
		///////////////////////////////////////////////////////////////
		// date1 is the first day of the selected period
		date1		= P(CSG_String::Format("FDAY",dateField).c_str())
									->asString();
		// date2 is the last day of the selected period
		date2		= P(CSG_String::Format("LDAY",dateField).c_str())
									->asString();

		// the catchment area is used to convert m3/s to mm
		area		= P("AREA")			->asDouble();

		// If temperature is used instead of ETp, the latitude is needed
		// to calculate ETp from temperature time series.
		if (Choice_ETp_TMP ==1)
			Latitude = P("LATITUDE")	->asDouble();

		if (bSnowModule)
		{
			mT_Rain_lb	= P("T_RAIN_LB")		->asDouble();
			mT_Rain_ub	= P("T_RAIN_UB")		->asDouble();
			mT_Melt_lb	= P("T_MELT_LB")		->asDouble();
			mT_Melt_ub	= P("T_MELT_UB")		->asDouble();
			mDD_FAC_lb	= P("DD_FAC_LB")		->asDouble();
			mDD_FAC_ub	= P("DD_FAC_UB")		->asDouble();
		}
		return(true);
	}
	return(false);
	

}