#include <estim/arx.h>
#include <itpp/itmex.h>
#include "mex_parser.h"

namespace bdm {
/*!
* \brief Wrapper of BM mapping BM's methods to matlab functions

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.
*/

using namespace bdm;

//! epdf with functions implemented in matlab
class mexEpdf: public epdf {
protected:
	//! prefix of matlab functions
	string name;
	//! pointer to storage structure
	mxArray *data;
public:
	mexEpdf() {};
	void from_setting ( const Setting &S )  {
		UIFile conf( ( const char * ) S["name"] );
		data = UImxArray::create_mxArray( conf );
		//mexCallMATLAB(1, &data, 0, 0, (name+"_new").c_str());
		//TODO (future...):
		//mxArray * init_data = setting2mxarray S["init_data"];
		//mexCallMATLAB(1, &data, 1, &init_data, name+"_from_setting");
		//delete init_data;
	}
	vec mean() const {
		mxArray *tmp;
		string fname = name + "_mean";
		mexCallMATLAB ( 1, &tmp, 1, ( mxArray ** ) &data, fname.c_str() );
		return mxArray2vec ( tmp );
	}

	virtual vec sample() const NOT_IMPLEMENTED(0);

	virtual double evallog ( const vec &val ) const NOT_IMPLEMENTED(0);
	
	virtual vec variance() const NOT_IMPLEMENTED(0);
};
UIREGISTER ( mexEpdf );

//! BM with functions implemented in matlab
class mexBM: public BM {
protected :
	//! prefix of matlab functions
	string name;
	//! internal estimator
	mexEpdf est;
	//! mxArray with attributes of this object
	mxArray *data;
public:
	mexBM() {}

	//! duplicate internal data pointer?
	mxArray *get_data() {
		//mexCallMATLAB(0, NULL, 1, &data, "dump");
		return mxDuplicateArray ( data );
	}

	void from_setting ( const Setting &S )  {
		BM::from_setting ( S );

		UIFile conf( ( const char * ) S["name"] );
		data = UImxArray::create_mxArray( conf );

		//string fname = name+"_new";
		//mexCallMATLAB(1, &data, 0, 0, (name+"_new").c_str());
		//the following works as long as the posterior is the
		//only member object there could be a structure of
		//member objects in the setting and a for cycle over
		//all of them right here in the code
		Setting &posterior = S["posterior"];
		est.from_setting ( posterior );
	}
	void bayes ( const vec &yt, const vec &cond )  {
		//void bayes()  {
		mxArray *tmp, *old;
		mxArray *in[2];
		in[0] = data;
		in[1] = mxCreateDoubleMatrix ( yt.size(), 1, mxREAL );
		vec2mxArray ( yt, in[1] );
		mexCallMATLAB ( 1, &tmp, 2, in, ( name + "_bayes" ).c_str() );
		old = data;
		data = mxDuplicateArray ( tmp );
		if ( old ) mxDestroyArray ( old );
		if ( tmp ) mxDestroyArray ( tmp );
		//mexCallMATLAB(0, NULL, 1, &data, "dump");
	}
	//! return correctly typed posterior (covariant return)
	const mexEpdf& posterior() const  {
		return est;
	} //tohle by melo zustat!!

};
UIREGISTER ( mexBM );

}
