#include <estim/arx.h>
#include <itpp/itmex.h>
#include <mex/config2mxstruct.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)  {
			name = (const char *) S["name"];
			UImxConfig conf(S);
			data = mxDuplicateArray(conf.mxconfig);
			//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);
		} 
};
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);
			name = (const char *) S["name"];
			UImxConfig conf(S);
			data = mxDuplicateArray(conf.mxconfig);
			//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);

}
