/*!
\file
\brief Scenario Simulator

The task of simulation is defined here as follows:
\dot
digraph estimation{
	node [shape=box];
	{rank="same"; "Data Source"; "Result Logger"}
	"Data Source" -> "Result Logger" [label="Simulated\n data"];
}
\enddot

Here,
\li Data Source is an object (class DS) providing sequential data, \f$ [d_1, d_2, \ldots d_t] \f$.
\li Result Logger is an object (class logger) dedicated to storing important data from the experiment.

Naming of the data provided by the datasource is done via mechanism of random variables (class RV).

\section  cmd Command-line usage
Execute command:
\code
$> simulator config_file.cfg
\endcode

Full description of the experiment is in the file config_file.cfg which is expected to have the following structure:
\code
system = {type = "DS_offspring", ...};      // definition of a data source
logger = {type = "logger_type",...};        // definition of a logger
experiment = {ndat = 11000; };              // definition of number of data records
\endcode

\section ex Matlab usage
Execute command:
\code
>> simulator(system,experiment,logger);
\endcode
Here, the only accepted field of experiment is \c experiment.ndat. If loger is not specified, the mexlogger is used, i.e. the data are stored as matlab structure with field names given by RV.names.
 */

#include <estim/arx.h>
#include <stat/emix.h>
#include <base/datasources.h>
#include <base/loggers.h>

//#include "mex_datasource.h"

using namespace bdm;

#ifdef MEX
#include <itpp/itmex.h>
#include "mex/mex_BM.h"
#include "mex/mex_logger.h"
#include "mex/mex_datasource.h"
#include "mex/mex_function.h"

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 ( "Usage:\n"
		                                "result=simulator(system,  experiment, logger)\n"
		                                "  system     = struct('class','datasource',...);  % Estimated system\n"
		                                "  === optional ==="
		                                "  experiment = struct('ndat',10);                 % number of data in experiment, full length of finite datasources, 10 otherwise \n"
		                                "  logger     = struct('class','mexlogger');       % How to store results, default=mexlog, i.e. matlab structure\n\n"
		                                "see documentation of classes datasource and mexlogger and their offsprings in BDM." );

	RV::clear_all();
	//CONFIG
	UImxArray Cfg;
	try {
		Cfg.addGroup ( input[0],"system" );
		if ( n_input>1 ) {
			Cfg.addGroup ( input[1],"experiment" );
		}
		if ( n_input>2 ) {
			Cfg.addGroup ( input[2],"logger" );
		}/*else{
		// define logger as mexlog
		Setting &S=Cfg.getRoot();
		S.add("logger",Setting::TypeGroup);
		S["logger"].add("class",Setting::TypeString);
		S["logger"]["class"]="mexlog";
		S["logger"].add("maxlen",Setting::TypeInt);
		int maxlen;
		S["experiment"].lookupValue("ndat",maxlen);
		S["logger"]["maxlen"]=maxlen;
	}*/
	} catch ( SettingException e ) {
		it_error ( "error: "+string ( e.getPath() ) );
	}

	//DBG
	Cfg.writeFile ( "simulator.cfg" );

#else
int main ( int argc, char* argv[] ) {
	const char *fname;
	if ( argc>1 ) {
		fname = argv[1];
	} else {
		fname="simulator.cfg";
	}
	UIFile Cfg ( fname );
#endif

	shared_ptr<DS> Ds = UI::build<DS> ( Cfg, "system" );
	int Ndat=10;
	if ( Cfg.exists ( "experiment" ) ) {
		if ( Cfg.lookupValue ( "experiment.ndat",Ndat ) ) {
			bdm_assert ( Ndat<=Ds->max_length(), "Data source has less data then required" );
		};
	} else {
		if ( Ds->max_length() < std::numeric_limits< int >::max() ) {
			Ndat=Ds->max_length();
		}
		;// else Ndat=10;
	}
	shared_ptr<logger> L = UI::build<logger> ( Cfg, "logger",UI::optional );
	if ( !L ) {
#ifdef MEX
		//mex logger has only from_setting constructor - we  have to fill it...
		L=new mexlog ( Ndat );
#else
		L=new stdlog();
#endif
	}

	Ds->log_register ( *L, "DS" );
	L->init();

	vec dt=zeros ( Ds->_drv()._dsize() );   //data variable

	for ( int tK=0;tK<Ndat;tK++ ) {
		Ds->getdata ( dt );					// read data
		Ds->log_write (  );

		L->step();
		Ds->step();							// simulator step
	}

	L->finalize();
	// ------------------ End of routine -----------------------------

#ifdef MEX
	mexlog* mL=dynamic_cast<mexlog*> ( L.get() );

	if ( mL ) { // user wants output!!
		if ( n_output<1 ) mexErrMsgTxt ( "Wrong number of output variables!" );
		output[0] = mL->toCell();
	}
#endif
}
