/*!
  \file
  \brief Loggers for storing results of experiments
  \author Vaclav Smidl.

  -----------------------------------
  BDM++ - C++ library for Bayesian Decision Making under Uncertainty

  Using IT++ for numerical operations
  -----------------------------------
*/

#ifndef LGR_H
#define LGR_H

#include "bdmbase.h"
#include "user_info.h"

namespace bdm {
using std::string;

/*!
 * Logging into matrices in data format in memory, optionally persisted into a file.
 */
class memlog : public logger {

protected:
	//! Maximum length of vectors stored in memory
	int maxlen;
	//! Currect record to be written
	int ind;
	//! Storage
	Array<mat> vectors;
	//! name of  file to save results (IT file for vectors and cfg for settings)
	string filename;

	//! this flag is only to assure reentrance of the finalize() method 
	bool file_saved;
public:
	//! convenience constructor
	memlog ( int maxlen0, string fn = "" ) : logger ( "_" ), maxlen ( maxlen0 ), ind ( 0 ), vectors ( 0 ), filename ( fn ), file_saved(false) {}

	//!Default constructor
	memlog() : logger ( "_" ), maxlen ( 0 ), ind ( 0 ), vectors ( 0 ), file_saved(false) {}

	//! Initialize storage
	void init();

	void step() {
		if ( ind < maxlen ) ind++;
		else bdm_error ( "memlog::ind is too high;" );
	}

	void log_vector ( int id, const vec &v ) {
		bdm_assert ( id < vectors.length(), "Logger was not initialized, run init()." );
		if ( id >= 0 ) {
			vectors ( id ).set_row ( ind, v );
		}
	}
	void log_double ( int id, const double &d ) {
		bdm_assert ( id < vectors.length(), "Logger was not initialized, run init()." );
		if ( id >= 0 ) {
			vectors ( id )( ind, 0 )=d;
		}
	}
	void logit ( int id, const double &d ) {
		bdm_assert_debug ( id < vectors.length(), "Logger was not initialized, run init()." );
		bdm_assert_debug ( vectors ( id ).cols() == 1, "Vector expected" );
		if ( id >= 0 ) {
			vectors ( id ) ( ind ) = d;
		}
	}
	//! Save values into an itfile named after \c fname.
	void itsave ( const char* fname );
	//!
	void finalize() {
		if ( filename.length() > 0 && !file_saved ) {
			itsave ( ( filename + ".it" ).c_str() );
			if ( settings.length() > 0 ) {
				setting_conf.writeFile ( ( filename + ".cfg" ).c_str() );
			}
			file_saved = true;
		}

	};


	/*! \brief UI for memlog

	\code
	logger = {
		class = "memlog";
		filename = "file_name"; // resulting filename with vectors in it format and setting in cfg
		maxlen = 100;           // size of memory buffer
	}
	\endcode
	 */
	void from_setting ( const Setting &set );

	// TODO dodelat void to_setting( Setting &set ) const;
};

UIREGISTER ( memlog );
SHAREDPTR ( memlog );


/*! \brief Simple logger used for debugging
All data records are written out to std from where they could be send to file
*/
class stdlog: public memlog {
public:
	//! default constructor
	stdlog() : memlog ( 1 ) {};

	void init() {
		memlog::init();
		for ( int i = 0; i < entries.length(); i++ ) {
			if ( entries ( i )._dsize() == 1 ) {
				cout << names ( i ) << separator << entries ( i ).name ( 0 ) << "\t";
			} else
				for ( int j = 0; j < vectors ( i ).cols(); j++ ) {
					cout << names ( i ) << separator << entries ( i ).scalarname ( j ) << "\t";
				}
		}
		cout << endl;


	}
	//!writes everything out
	void step() {
		for ( int i = 0; i < vectors.length(); i++ ) {
			for ( int j = 0; j < vectors ( i ).cols(); j++ ) {
				cout << vectors ( i ) ( 0, j ) << "\t";
			}
		}
		cout << endl;
	}
	/*! \brief UI for stdlog

	\code
	logger = {
		class = "stdlog"; // no parameterization needed
	}
	\endcode
	*/
	void from_setting ( const Setting &set ) {
	}
};
UIREGISTER ( stdlog );

/*!
* \brief Logging into dirfile with buffer in memory

* Dirfile is a special format used by the kst program. See documentation of kst for description.
*
* This format is used to store scalars, hence multivariate RVs must be separated.
*/
class dirfilelog : public memlog {

protected:
	//!name of the directory
	string dirname;
	//! Automatically generated
	Array<string> scalarnames;

	//! this flag is only to assure reentrance of the finalize() method 
	bool buffers_written;
public:
	/*!\brief Default constructor
	@param dirname0 name of the directory in which to store the results
	@param maxlen0 length of the memory buffers, when full the buffers will be dumped to HDD and returned to the beginning. */
	dirfilelog ( string dirname0, int maxlen0 ) : memlog ( maxlen0 ), dirname ( dirname0 ), scalarnames ( 0 ), buffers_written(false) {}

	dirfilelog() : buffers_written(false) {}

	//! Initialize storage
	void init();
	void step();
	void finalize();
	/*! \brief Write memory storage to disk.
	@param Len length of buffer to be written, if 0 the file is truncated at 0.
	*/
	void write_buffers ( int Len );

	/*! \brief UI for dirfilelog (Kst file format)
	\code
	logger = {
		class = "dirfilelog";
		dirname = "directory_for_files"; // resulting files will be stored there
		maxlen = 100;                    // size of memory buffer, when full results are written to disk
	}
	\endcode
	*/
	void from_setting ( const Setting &set );

	// TODO dodelat void to_setting( Setting &set ) const;
};

UIREGISTER ( dirfilelog );
SHAREDPTR ( dirfilelog );

};
#endif // LGR_H
