
/*!
  \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 );


//! Forward class declaration
class logger;

//! 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;

protected:

    /*!
    \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:

    //!default constructor
    root() {};

    //! make sure this is a virtual object
    virtual ~root() {
    }

    //! 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 log levels of each inheritance layer to a logger, i.e. allocate space for data from this class
    virtual void log_register ( logger &L, const string &prefix ) {
    }

    //! 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);

};

//! base class for all log_levels
//!
//! the existence of this class is forced by the necessity of passing log_levels to user_info methods, however, the main functionality
//! is located in \c log_level_template class
class log_level_base : public root {
private:
    //! this is necessary to allow logger to set ids vector appropriately and also to set registered_logger
    friend class logger;

protected:
    //! internal pointer to the logger to which this log_level is registered
    //!
    //! it is set to NULL at the beginning
    logger * registered_logger;

    //! vector of vectors of log IDs - one element for each entry and multiple entries can be stored on the position of one enum
    Vec<ivec> ids;


    //! default constructor�which is intentionaly declared as protected
    log_level_base( ) {
        registered_logger = NULL;
    }
};
//UIREGISTER IS FORBIDDEN FOR THIS CLASS,  AS IT SHOULD BE LOADED ONLY THROUGH THE SPECIALIZED UI::GET(...) METHOD

}; //namespace
#endif // root_H
