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

using namespace bdm;

class mexEpdf: public epdf{
	protected:
		string name;
		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);

class mexBM: public BM{
	protected :
		string name;
		mexEpdf est;
		mxArray *data;
	public:
		mexBM() {}

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

		void from_setting(const 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 &dt)  {
		//void bayes()  {
			mxArray *tmp, *old;
			mxArray *in[2];
			in[0] = data;
			in[1] = mxCreateDoubleMatrix(dt.size(), 1, mxREAL);
			vec2mxArray(dt, 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!!
		const mexEpdf* _e() const  {
			return &est;
		} //tohle by melo zustat!!
};
UIREGISTER(mexBM);

void mexFunction(int n_output, mxArray *output[], int n_input, const mxArray *input[])
{
    // Check the number of inputs and output arguments
	if(n_input!=1) mexErrMsgTxt("Wrong number of input variables - expected parameter 'filename'!");

 	// ------------------ Start of routine ---------------------------

	//mexBM mB(mxArray2string(input[0])); // naplni
	//mB.bayes(vec_1(1.3));
	string filename = mxArray2string(input[0]);
	Config config;
	config.readFile(filename.c_str());
	mexBM mb;
	Setting &root = config.getRoot();
	mb.from_setting(root);
	vec dt = "18.0";
	mb.bayes(dt);
	if(n_output>0) output[0] = mb.get_data();
	

	// ------------------ End of routine -----------------------------

    // Create output vectors
	//output[0] = mxCreateDoubleMatrix(1,1, mxREAL);

    // Convert the IT++ format to Matlab format for output
	//vec2mxArray(mB.posterior().mean(), output[0]);
}
