
/*!
  \file
  \brief Bayesian Models (bm) that use Bayes rule to learn from observations
  \author Vaclav Smidl.

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

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

#ifndef root_H
#define root_H

#include <string>
#include <bitset>

#include "itpp_ext.h"
#include "bdmerror.h"

#ifdef MEX
	#include "base/libconfig/lib/libconfig.h++"	
	// TODO DODELAT A NAHRADIT #include "base/libconfig_mex.h"
#else
	#include "base/libconfig/lib/libconfig.h++"
#endif


using namespace libconfig;
using namespace itpp;
using namespace std;

namespace bdm {
	
//! auxiliary function for debugging
void UI_DBG (const Setting &S, const string &spc, ostream &out );
	
//! This class stores a details that will be logged to a logger
template<class T> class log_level_template {
private:
	// UserInfo class have to be able to read all the internal 
	// attributes to be able to write/read log_level to/from a Setting structure
	friend class UI;

	//! boolean flags related indicating which details will be logged to a logger
	bitset<32> values;

	//! string equivalents of the used enumerations which are filled with a help of #LOG_LEVEL macro within class T
	const Array<string> &names() const
	{
		return T::log_level_names();
	}

public:
	
	//! a general utility transforming a comma-separated sequence of strings into an instance of Array<strings>
	static Array<string> string2Array( const string &input )
	{
		string result = input;
		string::size_type loc;
		while( loc = result.find( ',' ), loc != string::npos )
			result[loc] = ' ';
		return Array<string>("{ " + result + " }" );
	}

	//! is any field of log_level active?
	bool any() const
	{
		return values.any();
	}

	//! read only operator for testing  individual fields of log_level
	//!
	//! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe
	bool operator [] (const enum T::log_level_enums &log_level ) const
	{
		return values[log_level];
	}

	//! operator for setting an individual field of log_level 
	//!
	//! it is necessary to acces it with a proper enumeration type, thus this approach is type-safe
	bitset<32>::reference operator [] (const enum T::log_level_enums &log_level )
	{
		return values[log_level];
	}
};

/*!
  \def LOG_LEVEL(classname,...)
  \brief Macro for defining a log_level attribute with a specific set of enumerations related to a specific class 

  This macro has to be called within a class declaration. Its argument \a classname has to correspond to that wrapping class.
  This macro defines a log_level instance which can be modified either directly or by the means of #UI class.

  One of the main purposes of this macro is to allow variability in using enumerations. By relating them to their names through
  an array of strings, we are no more dependant on their precise ordering. What is more, we can add or remove any without harming 
  any applications which are using this library.

  \todo Write a more detailed explanation including also examples

  \ref ui
*/
#define LOG_LEVEL(classname,...) public: enum log_level_enums { __VA_ARGS__ }; log_level_template<classname> log_level; private: friend class log_level_template<classname>; static const Array<string> &log_level_names() { static const Array<string> log_level_names = log_level_template<classname>::string2Array( #__VA_ARGS__ ); return log_level_names; }

//forward declaration
class logger;

//! information about connection to a logger
class log_record {
public:
	//!remember which logger is registered
	logger &L;
	//! vector of log IDs - one element for each entry
	ivec ids;

	//!default constructor
	log_record ( logger &L0 ) : L ( L0 ), ids ( 0 ) {}
};

//! Root class of BDM objects
class root {
private:
	//! It is necessary to allow calling of from_setting and to_setting within the UI class ++ i log_options
	friend class UI;

	//! This method is a dummy method closely related to to the #LOG_LEVEL macro, do not remove it
	static const string &log_level_names() 
	{ 
		static const string log_level_names; 
		return log_level_names; 
	}; 

protected:
	//! record of connections to the logger
	log_record* logrec;

	/*!	
	\brief Read instance properties according the data stored in the Setting structure.
	It has to be called only through UI class, therefore it is protected 

	At the begining of this method, it is obligatory to call
	the corresponding base::from_setting method. Sometimes, there can be 
	an exception from this rule. If so, the programmer is encouraged 
	to describe the reasons for this exception in the documentation in detail.
	
	Then, all the configuration	components should be read through the UI mechanism. 
	Those with UI::SettingPresence set to optional shoud have their defaults fulfilled 
	within the body of this method.

	For instance, declaring a class \c trunk derived from our #root class, 
	the implementation of the from_setting method should look like this

	\code

	public trunk : public root {

		anytype xxx, yyy;

		virtual void from_setting ( const Setting &set ) {
			root::from_setting( set );
			
			UI::get ( xxx, set, "xxx", UI::compulsory );

			if ( !UI::get ( yyy, set, "yyy", UI::optional ) ) {
				... // here, it is necessary to set the default of attribute yyy						
			}

			... // another stuff related to trunk class
		}

		... // other members of this class
	};

	\endcode
	*/
	virtual void from_setting ( const Setting &set ) {
	}

	/*!	
	\brief 	Save all the instance properties into the Setting structure.
	It has to be called only through UI class, therefore it is protected 

	The only obligatory rule concerning the body of this method is to call
	the corresponding base::to_setting method first. 	Sometimes, there can 
	be an exception from this rule. If so, the programmer is encouraged 
	to describe the reasons for this exception in the documentation in detail.
	
	For instance, declaring
	a class \c trunk derived from our #root class, the implementation of 
	the to_setting method should look like this

	\code
	public trunk : public root {

		anytype xxx;

		virtual void to_setting ( const Setting &set ) {
			root::to_setting( set );

			UI::save ( xxx, set, "xxx" );
			
			... // another stuff related directly to trunk class

		}

		... // other members of this class

	};

	\endcode
	*/
	virtual void to_setting ( Setting &set ) const {
	}

public:
	//! This enumeration defines all possible options specifing the level of details logged by a logger about this specific class 
	//! 
	//! It has to be reimplemented in descendant classes using the #LOG_LEVEL macro
	enum log_level_enums { };

	//!default constructor
	root() : logrec ( NULL ) {};

	//! make sure this is a virtual object
	virtual ~root() {
		if ( logrec ) delete logrec;
	}

	//! Returns basic textual info about the current instance
	virtual string to_string() const {
		Config C;
		Setting &set=C.getRoot();
		this->to_setting(set);
		ostringstream os;
		UI_DBG(set, "", os);
		return os.str();
	}
	//! Register itself in a logger, i.e. allocate space for data from this class
	//! The level of details (parameter \c level ) is individual for each class.
	virtual void log_register ( logger &L, const string &prefix ) {
		logrec = new log_record ( L );
	}

	//! Write current information into the given logger
	virtual void log_write() const {
	}

	/*!	
	\brief 	This method checks that all internal structures has been set up correctly.

	It is called automatically after the call of the #from_setting method by the mechanism of the UI class. 
	However, it can be called in any other situation to assure the correctness of an instance.
	
	The only obligatory rule concerning the body of this method is to call
	the corresponding base::validate method first. Sometimes, there can be 
	an exception from this rule. If so, the programmer is encouraged 
	to describe the reasons for this exception in the documentation in detail.	
	
	Then, only those checks which are not implemented in the base method 
	are implemented here. For instance, declaring a class \c trunk derived from our 
	#root class, the implementation of the method validate should 
	look like this

	\code
	public trunk : public root {

		virtual void validate ( ) {
			root::validate( );

			... // checks related directly to trunk class
		}

		... // other members of this class

	};

	\endcode

	*/
	virtual void validate() {
	}

	//! Virtual method providing deep copy of instances
	virtual root* _copy() const NOT_IMPLEMENTED(NULL);
	
};

}; //namespace
#endif // root_H
