#include "datasources.h"

using namespace bdm;

MemDS::MemDS ( mat &Dat ) : Data( Dat ) {
}

void MemDS::step( ) {
	if ( time < max_length() ) {
		time++;
	}
}

void MemDS::getdata ( vec &dt ) const {
	bdm_assert_debug ( dt.length() == Data.rows(), "MemDS:getdata incompatible dt" );
	dt = Data.get_col ( time );
}

void MemDS::getdata ( vec &dt, const ivec &indices ) {
	bdm_assert_debug ( dt.length() == indices.length(), "MemDS:getdata incompatible dt" );
	vec tmp = Data.get_col ( time );
	dt = tmp ( indices );
}

void MemDS::set_drv ( const RV &drv ) {
	bdm_assert_debug ( drv._dsize() == Data.rows(), "MemDS::set_rvs incompatible drv" );
	DS::set_drv ( drv, RV() );
}

void MemDS::from_setting ( const Setting &set ) {
	DS::from_setting ( set );

	UI::get ( Data, set, "Data", UI::compulsory );
	
	if ( !UI::get ( time, set, "time", UI::optional ) ) {
		time = 0;
	}
	
	shared_ptr<RV> r = UI::build<RV> ( set, "drv", UI::optional );
	if ( !r ) {
		r = new RV();
		for ( int i = 0; i < Data.rows(); i++ ) {
			r->add ( RV ( "ch" + num2str ( i ), 1, 0 ) );
		}
	}
	
	set_drv ( *r );
	dtsize = r->_dsize();
	utsize = 0;
}

void FileDS::from_setting ( const Setting & set ) {
	// here we do not call MemDS::from_setting intentionally as we can not load any Data matrix directly
	DS::from_setting ( set );

	string filename;
	UI::get ( filename, set, "filename", UI::compulsory );

	time = 0;

	shared_ptr<RV> r = UI::build<RV> ( set, "drv", UI::optional );
	if ( !r ) {
		r = new RV();
		for ( int i = 0; i < Data.rows(); i++ ) {
			r->add ( RV ( "ch" + num2str ( i ), 1, 0 ) );
		}
	}
	
	set_drv ( *r );
	dtsize = r->_dsize();
	utsize = 0;
}

void CsvFileDS::from_setting ( const Setting & set ) {
	FileDS::from_setting ( set );

	vec data_line;
	string line;

	ifstream fs;
	fs.open ( filename.c_str() );
	if ( fs.is_open() ) {
		while ( getline ( fs, line ) ) {
			data_line.set ( line );
			Data.append_row ( data_line );
		}
	}

	string orientation;
	if( UI::get ( orientation, set, "orientation", UI::optional ) & orientation == "BY_ROW" ) 
		transpose ( Data, Data );
}

void ITppFileDS::from_setting ( const Setting & set ) {
	FileDS::from_setting ( set );

	string varname;
	UI::get ( varname, set, "varname", UI::compulsory );

	it_file it ( filename );
	it << Name ( varname );
	it >> Data;
}

void PdfDS::step() {
	yt2rgr.store_data ( yt ); // y is now history
	ut2rgr.filldown ( ut, rgr );
	yt2rgr.filldown ( yt, rgr );
	yt = ipdf->samplecond ( rgr );
	ut2rgr.store_data ( ut ); //u is now history
}

void PdfDS::getdata ( vec & dt_out ) const {
	bdm_assert_debug ( dt_out.length() >= dtsize, "Short output vector" );
	dt_out.set_subvector ( 0, yt );
	dt_out.set_subvector ( yt.length(), ut );
}

void StateDS::step() {
	vec imc ( IM->dimensionc() );
	imc.set_subvector ( 0, xt );
	u2imc.filldown ( ut, imc );
	xt = IM->samplecond ( imc );

	vec omc ( OM->dimensionc() );
	omc.set_subvector ( 0, xt );
	u2omc.filldown ( ut, omc );
	vec yt;
	yt = OM->samplecond ( omc );
	//fill all data
	dt.set_subvector ( 0, yt );
	dt.set_subvector ( yt.length(), xt );
	dt.set_subvector ( yt.length()+xt.length(), ut );
}

void StateDS::from_setting ( const Setting & set ) {
	IM = UI::build<pdf> ( set, "IM", UI::compulsory );
	OM = UI::build<pdf> ( set, "OM", UI::compulsory );

	//todo test if IM->rvc contains IM->rv
	//todo test if OM->rvc contains IM->rv

	UI::get ( xt, set, "x0", UI::optional );

}

void StateDS::validate() {
	DS::validate();

	RV Yrv = concat ( OM->_rv() , IM->_rv() ); // export also true state
	int ytsize = Yrv._dsize();

	RV tmp = concat ( OM->_rvc(), IM->_rvc() ); // what i not in rvc
	Urv = tmp.subt ( Yrv ); // remove dt,xt and
	Urv = Urv.subt ( Yrv.copy_t ( -1 ) ); // remove dt,xt and
	utsize = Urv._dsize();

	set_drv ( Yrv, Urv );
	dtsize = utsize + ytsize;

	dt.set_length ( dtsize );
	if ( xt.length() != IM->dimension() ) {
		xt = zeros ( IM->dimension() );
	}
	ut.set_length ( Urv._dsize() );

	//create data links
	u2imc.set_connection ( IM->_rvc(), Urv );
	u2omc.set_connection ( OM->_rvc(), Urv );
}
