/*!
  \file
  \brief Common DataSources.
  \author Vaclav Smidl.

  -----------------------------------
  BDM++ - C++ library for Bayesian Decision Making under Uncertainty

  Using IT++ for numerical operations
  -----------------------------------
*/

#ifndef DS_H
#define DS_H


#include "libBM.h"
#include "libEF.h"


namespace bdm {
	/*!
	* \brief Memory storage of off-line data column-wise

	The data are stored in an internal matrix \c Data . Each column of Data corresponds to one discrete time observation \f$t\f$. Access to this matrix is via indices \c rowid and \c delays.

	The data can be loaded from a file.
	*/
	class MemDS : public DS {
		//! internal matrix of data
		mat Data;
		//! active column in the Data matrix
		int time;
		//!  vector of rows that are presented in Dt
		ivec rowid;
		//! vector of delays that are presented in Dt
		ivec delays;

	public:
		void getdata ( vec &dt );
		void getdata ( vec &dt, const ivec &indeces );
		void set_rvs ( RV &drv, RV &urv );
		void write ( vec &ut ) {it_error ( "MemDS::write is not supported" );}
		void write ( vec &ut,ivec &indices ) {it_error ( "MemDS::write is not supported" );}
		void step();
		//!Default constructor
		MemDS ( mat &Dat, ivec &rowid, ivec &delays );
	};

	/*!
	\brief Generator of ARX data

	*/
	class ArxDS : public DS {
	protected:
		//! Rv of the regressor
		RV Rrv;
		//! Rv of the history (full regressor)
		RV Hrv;
		//! History, ordered as \f$[y_t, u_t, y_{t-1 }, u_{t-1}, \ldots]\f$
		vec H;
		//! (future) input
		vec U;
		//! temporary variable for regressor
		vec rgr;
		//! data link: H -> rgr
		datalink *rgrlnk;
		//! model of Y - linear Gaussian
		mlnorm<chmat> model;
		//! options
		bool opt_L_theta;
		//! loggers
		int L_theta;
		int L_R;
	public:
		void getdata ( vec &dt ) {
			//it_assert_debug ( dt.length() ==Drv.count(),"ArxDS" );
			dt=H.left ( Urv._dsize() +Drv._dsize() );
		};
		void getdata ( vec &dt, const ivec &indices ) {
			it_assert_debug ( dt.length() ==indices.length(),"ArxDS" );
			dt=H ( indices );
		};
		void write ( vec &ut ) {
			//it_assert_debug ( ut.length() ==Urv.count(),"ArxDS" );
			U=ut;
		};
		void write ( vec &ut, const ivec &indices ) {
			it_assert_debug ( ut.length() ==indices.length(),"ArxDS" );
			set_subvector ( U, indices,ut );
		};
		void step();
		//!Default constructor
		ArxDS ( ){};
		//! Set parameters of the internal model
		void set_parameters ( const mat &Th0, const vec mu0, const chmat &sqR0 )
		{ model.set_parameters ( Th0, mu0, sqR0 ); };
		//! set options from a string
		void set_options ( const string &s ) {
			opt_L_theta= ( s.find ( "L_theta" ) !=string::npos );
		};
		virtual void log_add ( logger &L ) {
			DS::log_add ( L );
			mat &A =model._A();
			mat R =model._R();
			if ( opt_L_theta ) {L_theta=L.add ( RV ( "{theta }", vec_1 ( A.rows() *A.cols() ) ),"t" );}
			if ( opt_L_theta ) {L_R=L.add ( RV ( "{R }", vec_1 ( R.rows() *R.cols() ) ),"r" );}
		}
		virtual void logit ( logger &L ) {
			DS::logit ( L );
			mat &A =model._A();
			mat R =model._R();
			if ( opt_L_theta ) {L.logit ( L_theta,vec ( A._data(), A.rows() *A.cols() ) );};
			if ( opt_L_theta ) {L.logit ( L_R, vec ( R._data(), R.rows() *R.rows() ) );};
		}

	};

	class ARXDS : public ArxDS {
	public:
		ARXDS ( ) : ArxDS ( ) {}

		void getdata ( vec &dt ) {dt=H;}
		void getdata ( vec &dt, const ivec &indeces ) {dt=H ( indeces );}
		virtual RV _drv() const {return Hrv;}

	};

	class stateDS : public DS {
	protected:
		//!conditional pdf of the state evolution \f$ f(x_t|x_{t-1}) \f$
		mpdf* IM;
		//!conditional pdf of the observations \f$ f(d_t|x_t) \f$
		mpdf* OM;
		//! result storage
		vec dt;
		//! state storage
		vec xt;
		//! input storage
		vec ut;
		//! Logger
		int L_xt;
	public:
		void getdata ( vec &dt0 ) {dt0=dt;}
		void getdata ( vec &dt0, const ivec &indeces ) {dt0=dt ( indeces );}

		stateDS ( mpdf* IM0, mpdf* OM0, int usize ) :DS ( ),IM ( IM0 ),OM ( OM0 ),
				dt ( OM0->dimension() ), xt ( IM0->dimension() ), ut ( usize) {}
		~stateDS() {delete IM; delete OM;}
		virtual void step() {
			xt=IM->samplecond(concat ( xt,ut ));
			dt=OM->samplecond(concat ( xt,ut ));
		};
		
		virtual void log_add ( logger &L ) {
			DS::log_add ( L );
			L_xt=L.add(IM->_rv(),"true");
		}
		virtual void logit ( logger &L ) {
			DS::logit ( L );
			L.logit ( L_xt,xt);
		}

	};

}; //namespace

#endif // DS_H
