#ifndef MXDS_H
#define MXDS_H


#include "../bdm/bdmerror.h"
#include "../bdm/base/datasources.h"
#include "mex_parser.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 mxArrayDS : public MemDS {
	public:
	//!Default constructor
	mxArrayDS ():MemDS() {};

	/*! \brief Create memory data source from mxArray

	\code
	system={
		type="mexDS";
		varname="";                // name of workspace variable
		row_rv = {class='RV',...}  // definition of 
		};
	\endcode

	MemDS with the above fields will be created;

	*/
	void from_setting ( const Setting &set ) {
		Data = mxArray2mat ( mexGetVariable ( "base", set["varname"] ) );
/*		UI::get ( rowid, set, "rids" , UI::compulsory );
		bdm_assert_debug ( max ( rowid ) <= Data.rows(), "MemDS rowid is too high for given Dat." );

		UI::get ( delays, set, "tds", UI::compulsory );
		time = max ( delays );
		bdm_assert_debug ( time < Data.cols(), "MemDS delays are too high." );
*/
		//set MemDS
		rowid = linspace(0,Data.rows()-1);
		delays = zeros_i(Data.rows());
		dtsize=rowid.length();
		utsize=0;
		
		shared_ptr<RV> r = UI::build<RV> ( set, "rv", UI::optional );
		RV ru = RV();
		if (r){
			set_rvs ( *r, ru );
		} else {
			RV def((const char*)set["varname"],Data.rows());
			set_rvs(def, ru);
		}
	}


	// TODO dodelat void to_setting( Setting &set ) const;
};

UIREGISTER ( mxArrayDS );
SHAREDPTR ( mxArrayDS );

/*!
* \brief Matlab wrapper for DS mapping functions step() to a matlab function

The identifier of matlab function is stored in attribute \c name.
This identifier defines: 
\li function to call to do a step(): name_step.m
\li workspace variable to write input to: name_input
*/
class mexDS : public DS {
	protected:
		//! identifier of matlab function 
		string step_name;
		//! identifier of matlab input variabel
		string input_name;
		//! cache of results from name_step
		vec dt;
		//! cache of inputs 
		vec ut;
	public:
	//!Default constructor
	mexDS ():DS() {};

	/*! \brief Create memory data source from mxArray

	\code
	system={
		type="mexDS";
		step_name="";              // name of function to call
		input_name="";             // name of workspace variable where inputs are written
		rv_out = {class='RV',...}  // identification of outputs
		rv_in = {class='RV',...}   // identification of inputs
		};
	\endcode

	MemDS with the above fields will be created;

	*/
	void from_setting ( const Setting &set ) {
		UI::get(step_name, set, "step_name", UI::compulsory);
		UI::get(input_name, set, "input_name", UI::compulsory);
		
		shared_ptr<RV> ry = UI::build<RV> ( set, "rv_out", UI::compulsory );
		shared_ptr<RV> ru = UI::build<RV> ( set, "rv_in", UI::compulsory);

		dtsize=ry->_dsize();
		utsize=ru->_dsize();

		set_drv(*ry, *ru);
	}
	
	void step() {
		mxArray* tmp;
		mxArray* tmp2;
		// write inputs to variable input_name
		mxArray* mxinp= mexGetVariable ( "global", input_name.c_str()) ;
		vec2mxArray(ut, mxinp);
		// call function step_name
		mexCallMATLAB(1, &tmp, 0, (mxArray **) &tmp2, step_name.c_str());
		// save its results
		dt=mxArray2vec(tmp);
	}
	void write(vec &ut0){ ut=ut0;}
	void getdata(vec &dt_out){dt_out = dt;	}


	// TODO dodelat void to_setting( Setting &set ) const;
};

UIREGISTER ( mexDS );
SHAREDPTR ( mexDS );

}
#endif //MXDS_H
