/////////////////////////////////////////////////////////////////////////////
// Name:        gr4j.h
// Author:      Stefan Liersch
// Contact:		stefan.liersch@ufz.de stliersch@freenet.de
// Created:     2007-02-28
//
// --------------------------------------------------------------
// Note:		The functions of the program GR4J were adopted from
//				FORTRAN Code by Charles Perrin (CEMAGREF) and the
//				SciLab Code by Julien Lerat (CEMAGREF).
//				The functions have been converted to C++.
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// ToDo
// -------------------------------------------------------------------------
// - delete variable nX
//
//
/////////////////////////////////////////////////////////////////////////////
#ifndef __gr4j_H
#define __gr4j_H

#include <SAGA_API/saga_api.h> // CSG_Table
#include <vector>

#include "snow_module.h"

using std::vector;						
using std::string;						
typedef vector<string> vector_str; 		

//---------------------------------------------------------------------
// a structure to handle input time series data from input file
struct InputData
{
	int			size; // number of values in arrays
	vector_str	date;
	double*		precipitation;	// in [mm]
	double*		pET;			// in [mm]
	double*		Q_obs;			// in [mm] !!!
};

//---------------------------------------------------------------------
// this struct contains the four free (calibration) variables 
struct GR4J_Parameters
{
	double		X1;
	double		X2;
	double		X3;
	double		X4;
};
//---------------------------------------------------------------------

class Cgr4j
{
public:
	// constructors
	Cgr4j();
	Cgr4j(InputData Input);
	
	// use this constructor if you want to use the SNOW MODULE from
	// Monte Carlo Simulation
	Cgr4j(InputData Input, double *temperature, CSnowModule *SnowModule);

	// use this constructor if you want to use the SNOW MODULE
	Cgr4j(InputData Input,
		  double* temperature,
		  double T_Rain, double T_Melt, double DD_FAC);

	// destructor
	~Cgr4j();

	// Input parameters --------
	InputData		Input;
	GR4J_Parameters		X;
	// -------------------------

	/////////////////////////////////////////////////////////////////
	void			Simulation(InputData& Input, GR4J_Parameters& Settings);
	void			free_memory();
	/////////////////////////////////////////////////////////////////
	
	void			AssignFirstLastRec(CSG_Table &pTable, int &first, int &last,
										CSG_String date1, CSG_String date2, int dateField);

	// PRIVATE VARIABLES / PARAMETERS
	int				nUH;		// number of UH ordinates = 10
	double*			UH1;		// Unit hydrograph1 ordinates
	double*			UH2;		// Unit hydrograph2 ordinates
	double*			UH1_Contrib;// V(>3)
	double*			UH2_Contrib;// 
	double*			GWExchange; // groundwater exchange (ECH)

	double*			ES;			// quantity of water that will evaporate from production store
	double*			WS;			// netto pet / X.X1 (capacity of production store)
	double*			PS;			// part of netto precipitation that fills the production store
	double*			PR;			// netto precipitation - PS + percolation

	double*			percolation;// percolation from production store
	
	double*			Q_r;		// reservoir outflow
	double*			Q_d;		// outflow from UH2 and groundwater exchange
	double*			Q_sim;		// simulated streamflow

	double			mean_pcp;
	double			mean_Q;
	double			mean_pet;

	double*			LevelProdStore;
	double*			LevelRouteStore;
private:

	bool			bSnowModule;	// true if snow module is active
	double*			temperature;	// only used if snow module is active

	// -------------- UH subroutines --------------------------------
	// SS1, SS2: Gives the discrete values of the UH S-curve for
	// UH1 and UH2 respectively
	double			_SS1(double count, double UH_timeconstant);
	double			_SS2(double count, double UH_timeconstant);
	double*			_UH1(double* UH1, int nuh, double UH_timeconstant);
	double*			_UH2(double* UH2, int nuh, double UH_timeconstant);
	// Calculate the discrete ordinates of unit hydrographs
	// UH1 and UH2 respectively
	void			_CalcUH(double* UH1, double* UH2, int nUH, double X4);
	// --------------------------------------------------------------


	// --------------------------------------------------------------
	// initialize pointers (arrays)
	// calculate time series averages (mean pcp, Q_obs, pET)
	void			_InitParms(GR4J_Parameters Settings);

	// initialize model for first time step
	// intitialize storages
	void			_InitStorages(GR4J_Parameters X,
								  double& LevelProdStore,
								  double& LevelRouteStore);
	// --------------------------------------------------------------


	/////////////////////////////////////////////////////////////////
	//
	//			SIMULATE STREAMFLOW
	//
	/////////////////////////////////////////////////////////////////

	// simulate production store
	double			_SimProductionStore(GR4J_Parameters X, double pcp, double pet,
										double LevelProdStore,
										double& ES, double& WS,
										double& PS, double& PR);

	// simulate production store
	double			_SimProductionStore_Snow(GR4J_Parameters X, 
											 CSnowModule* SnowModule, int current_day,
											 double pcp, double pet, double temperature,
											 double LevelProdStore,
											 double& ES, double& WS,
											 double& PS, double& PR);

	// simulate percolation from production store
	double			_SimPercolation(double& LevelProdStore, double& PR);

	// simulate contribution of unit hydrographs
	double*			_Sim_UH_Contrib(double* UHx_Contrib, double PR, double* UH, int nUH);

	// simulate groundwater exchange
	double			_SimWaterExchange(GR4J_Parameters X, double LevelProdStore);

	// simulate reservoir outflow
	double			_SimReservoirOutflow(double& LevelRouteStore, double LRS_before, double uh1_1, double gw_exchange);

	// simulate UH2 contribution, that is subject to groundwater exchange
	double			_Sim_UH2_ComponentOutflow(double uh2_1, double GWExchange);

	/////////////////////////////////////////////////////////////////


	
	// HELPER -----------------------------------
	// calculate the sum of an array
	double			_SumArray(double* val, int size);


	CSnowModule*	SnowModule;


	// RENAMED PARAMETERS -----------------------

	// original | this version
	//-------------------------------------------
	// NPX		= nX
	// NH		= nUH
	// C		= UH_timeconstant
	// X(1)		= X.X1 Capacity of the production store [mm]
	// X(2)		= X.X2 Water exchange coefficient [mm]
	// X(3)		= X.X3 Capacity of the routing store [mm]
	// X(4)		= X.X4 Time base of the unit hydrograph [days]
	// V(1)		= LevelProdStore
	// V(2)		= LevelRouteStore
	// V(3)		= UH1_Contrib / UH2_Contrib
	// PSQ		= mean_Q
	// PSP		= mean_pcp
	// PSE		= mean_pet
};


#endif /* __gr4j_H */