///////////////////////////////////////////////////////////
//                                                       //
//                         SAGA                          //
//                                                       //
//      System for Automated Geoscientific Analyses      //
//                                                       //
//                    Module Library:                    //
//                        IHACRES                        //
//                                                       //
//-------------------------------------------------------//
//                                                       //
//                  ihacres_auto_cal.h                   //
//                                                       //
//                 Copyright (C) 2006 by                 //
//                     Stefan Liersch                    //
//-------------------------------------------------------//
//                                                       //
//    e-mail:     stefan.liersch@ufz.de                  //
//                stliersch@freenet.de                   //
//                                                       //
//                     2007-01-03                        //
//                                                       //
///////////////////////////////////////////////////////////


//*******************************************************//
//                        ToDo                           //
//-------------------------------------------------------//
// - Parameter l und p in PreCalibration berücksichtigen
//	 - Parm c dafür raus und automatisch Bereich festlegen
//	 - T_CP um l und p erweitern
//	 - functions: PreCalibration1, CalcNonLinear, CalcNonLinearMC
//		_Select_Valid_Sims, _Init_Tocc

// - Snow Module
// - wenn nbset bzw. nsteps zu klein -> Absturz
// - Absturz nach Cancel Modul
//*******************************************************//


#ifndef _HEADER_INCLUDED__ihacres_auto_cal_H
#define _HEADER_INCLUDED__ihacres_auto_cal_H

#include <iostream>
#include <string>
#include <vector>   // used for storing date string values in array

using std::string;
using std::vector;
using std::cout;
using std::cin;
using std::endl;

typedef vector<string>	vector_str; // vector array to storing date values as strings

#include "MLB_Interface.h"		// SAGA Module Interface
#include "ihacres_eq.h"			// IHACRES Functions

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

struct T_InputTable
{
	// Parameters of the input table (date, precip, obs. streamflow, temperature)
	int			dateField;		// Table number (date field)
	int			dischargeField; // Table number (discharge field)
	int			pcpField;		// Table number (precipitation field)
	int			tmpField;		// Table number (temperature field)
	bool		bTMP;			// true if temperature data available
	int			first;			// number of the record of first date
	int			last;			// number of the record of last date
	CSG_String	date1;			// first day of calibration period
	CSG_String	date2;			// last day of calibration period

	// vectors and arrays
	int			size;			// size of the vectors and arrays
	vector_str	date;			// vector storing date values
	double*		p_discharge;	// array storing discharge values
	double*		p_dischargeMM;	// observed discharge in [mm]
	double*		p_pcp;			// array storing precipitation values
	double*		p_tmp;			// array storing temperature values
};
//---------------------------------------------------------

struct T_Cal
{
	// Parameters used in Pre-Calibration
	int			nsteps1, nsteps2, nsteps3; // number of steps in first calibration
	int			ncombi;			// number of parameter combinations
	double		lb1, lb2, lb3;	// lower bounds of non-linear module parameters
	double		ub1, ub2, ub3;	// upper bounds of non-linear module parameters
};
//---------------------------------------------------------

struct T_nOccurence
{
	int			nsteps;			// number of steps
	double		lb, ub;			// lower and upper bound of each parameter
	double*		val;			// current parameter value
	int*		n_occ;			// number of occurences of each parameter value
								// in valid simulations
	int			n_classes;		// number of classes (STURGES [1926]
	int			n_best;			// number of best values, that are taken into account
	double		new_lb, new_ub; // new lower and upper bound
};
//---------------------------------------------------------

struct T_NonLinear_Parms
{
	double		Tw;
	double		f;
	double		c;
	double		l;				// soil moisture index threshold
	double		p;				// power on soil moisture
	double		sum_eRainGTpcp;	// sum of excess rainfall that is greater
								// than precipitation in one simulation
	double		Dif_eRainDis;	// difference between streamflow and excess rainfall
	double		Sum_eRainMM;	// sum of estimated effective rainfall [mm]
};
//---------------------------------------------------------

struct T_Linear_Parms
{
	int			nStorages;		// number of storages (one or more than one are possible)
	double*		a;				// alpa, array with nStorages elements
	double*		b;				// beta, array with nStorages elements
};
//---------------------------------------------------------
struct T_Linear_Bounds
{
	// single storage
	double		a_lb;
	double		a_ub;
	double		b_lb;
	double		b_ub;
	// two storages
	double		aq_lb;
	double		aq_ub;
	double		bq_lb;
	double		bq_ub;
	double		as_lb;
	double		as_ub;
	double		bs_lb;
	double		bs_ub;
};
//---------------------------------------------------------

struct T_Top_NLM_Sims
{
	int			nTop;			// number of top simulations
	double*		Tw;				// = double[nTop]
	double*		f;				// = double[nTop]
	double*		c;				// = double[nTop]
	double*		l;				// soil moisture index threshold
	double*		p;				// power on soil moisture
	double*		sum_eRainGTpcp;	// sum of excess rainfall that is greater (=double[nTop])
								// than precipitation in one simulation
	double*		Dif_eRainDis;	// difference between streamflow and excess rainfall (=double[nTop])
	double*		Sum_eRainMM;	// sum of excess rainfall (=double[nTop])
};
//---------------------------------------------------------

struct T_SnowModule
{
	// Snow Module Parameters
	double*		p_SnowStorage;	// Snow storage at each time step
	double*		p_MeltRate;		// Melt rate at each time step
	double		T_Rain;			// Temperature threshold
								// below this value precipitation will fall as snow
	double		T_Melt;			// Temperature threshold
								// above this value snow will start to melt
	double		DD_FAC;			// day-degree factor, depending on catchment characteristics
};
//---------------------------------------------------------

struct T_Output_Arrays
{
	// effective rainfall time series
	// for each nTop non-linear module simulatíon
	double*		eR;
	// simulated streamflow time series
	// for each nTop non-linear module simulation
	double*		simStreamflow;
	double*		vq;
	double*		vs;
	double*		tq;
	double*		ts;
};
//---------------------------------------------------------

class Cihacres_auto_cal : public CSG_Module
{
public:
	Cihacres_auto_cal();
	virtual ~Cihacres_auto_cal();

	T_Cal				T_CP;		// Calibration Parameters
	T_NonLinear_Parms*	T_NLP;		// Non-linear module parameter set
	T_NonLinear_Parms*	T_NLP_valid; // valid simulations
	T_Top_NLM_Sims		Top_NLM;	// best n non-linear parameter settings
									// from Monte Carlo simulation
	T_Linear_Parms*		T_LM;		// Linear module parameters
	T_Linear_Bounds		T_LB;		// lower and upper bounds of storage parameters
	T_InputTable		T_in;
	T_nOccurence*		T_occ;
	T_SnowModule		T_SM;		// snow module parameters
	T_Output_Arrays*	T_out;		// simulated time series

protected:
	// execute module
	virtual bool		On_Execute(void);

private:
	//--------------------------------------------------------
	// Private Member Variables
	//--------------------------------------------------------
	double				area;			// area of the watershed in [km2]
	int					IHAC_version;	// Different versions of IHACRES exist, corresponding
										// to the version...
	bool				bSnowModule;	//

	double*				p_SimDischarge;

	double*				p_Tw;
	double*				p_WI;
	double*				p_ExcessRain;

	bool*				p_bValidSim;
	int					nValidSims;

	double				sum_obsDisMM;	// sum of observed discharge in [mm]
	double				sum_simDisMM;	// sum of simulated discharge in [mm]
	double				sum_pcpMM;		// sum of observed precipitation [mm]
	double				RunoffCoeff;	// Runoff coefficient (Discharge / Precipitation)

	int					nTop;			// number of top parameter settings of
										// the non-lineare module that are used to run
										// the linear module

	int					nsimMC_NLM;		// number of Monte-Carlo-Simulations of the non-linear module
	int					nsimMC_LM;		// number of Monte-Carlo-simulations of the linear module
	bool				b_freebee;		// if true, then b-values of storages will be chosen independ from a-values

	//--------------------------------------------------------
	// Private Member Functions
	//--------------------------------------------------------
	void				_InitArrays(int IHAC_version, T_InputTable &T_in, T_SnowModule &T_SM);
	void				_ZeroVariables();	
	//void				_Init_T_Cal(int steps);

	//T_NonLinear_Parms*	_Set_PreCalibration1_Parms(T_Cal T_CP); //, T_NonLinear_Parms *T_NLP);
	void				_Set_PreCalibration1_Parms(T_Cal T_CP); 
	
	void				_CalcNonLinearModule(T_NonLinear_Parms* T_NLP, bool bTMP, int IHAC_version, int nsim,
											 double dev_eRainDis,
											 double dev_eRainPCP, bool bSnowModule);

	void				_CalcNonLinearModuleMC(T_NonLinear_Parms* T_nlp, T_nOccurence* T_occ, 
												bool bTMP, int IHAC_version, int nsim,
												double dev_eRainDis,
												double dev_eRainPCP);

	// Count number of true values in a bool array
	int					_CountNumberTrue(bool *array, int size);
	//T_NonLinear_Parms*	_Select_Valid_Sims(int nsim,
	//									   T_NonLinear_Parms* T_NLP,
	//									   T_NonLinear_Parms* T_NLP_val);
	void				_Select_Valid_Sims(int nsim, T_NonLinear_Parms* T_NLP);

	//T_nOccurence*		_Init_Tocc(T_nOccurence* T_occ, T_Cal T_CP);
	void				_Init_Tocc(T_Cal T_CP);
	int					_Calc_num_selection(T_nOccurence T_occ);
	void				_Select_Best(T_nOccurence* T_occ);
	//int*				_FindTopIndex(int* array, int size, int *TopIndex, int top, int nsim);
	int*				_FindTopIndex(int* array, int size, int top, int nsim);
	double*				_AssignTopVal(T_nOccurence T_occ, int* topindex);
	T_Top_NLM_Sims		_Assign_TopNLM(int nTop, T_NonLinear_Parms* T_validNLM);


	//--------------------------------------------------------
	// Helper
	//--------------------------------------------------------
	int					_round_i(double d);
	double				_largest(double* array, int size);
	int					_largest_below(int* array, int size, int exception);
	double				_lowest(double* array, int size);
	int					_lowest_after(double* array, int size, double exception);
	int					_count_n_occ(int* array, int size, int val);
	int					_Get_Index(int* array, int size, int value, int start);
	double				_Random_double(double lb, double ub);
	
	//--------------------------------------------------------
	// Dialogs
	//--------------------------------------------------------
	void				_CreateDialog1();
	bool				_CreateDialog2(int storconf, CSG_Table *pTable, T_InputTable &T_in, int IHAC_version);

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

	// class Cihacres_eq, in order to use functions from this class
	Cihacres_eq			ihac;

};

#endif /* _HEADER_INCLUDED__ihacres_auto_cal_H */
