#ifndef __PARAMBASECONNECTOR_H
#define __PARAMBASECONNECTOR_H

/**
 *******************************************************************************
 * @file paramBaseConnector.h
 *
 * \class CParameterBaseConnector
 * \date  Tue Oct 13, 2009
 * \author Hernan Badino (hernan.badino@gmail.com)
 *
 * \brief Abstract base class for connecting parameters with variables.
 *
 * Abstract base class for connecting parameters with variables. The children
 * concrete classes must implement the methods updateContainer and 
 * updateParameterObj.
 *
 *******************************************************************************/

/* INCLUDES */
#include "parameter.h"
#include "standardTypes.h"
#include "int2DParam.h"

/* CONSTANTS */
namespace VIC
{
    class CParameterBaseConnector
    {
    /// Constructors / Destructor
    public:
        
        CParameterBaseConnector () {}
        virtual ~CParameterBaseConnector () {}

    /// Virtual public functions
    public:
        virtual bool updateContainer() = 0;
        
        /// Update the parameter object calling the setValue method
        /// of the parameter.
        virtual bool updateParameterObj() = 0;

        virtual bool setParameterObject ( CParameter * f_param_p )
        {
            m_parameter_p = f_param_p; return true;
        }
   /// Protected members
    protected:
        /// Pointer to the parameter type class.
        CParameter *          m_parameter_p;
    };
    
/**
 *******************************************************************************
 *
 * \class CParameterConnector
 * \date  Tue Oct 13, 2009
 * \author Hernan Badino (hernan.badino@gmail.com)
 *
 * \brief Template concrete class for connecting a parameter with a variable in a 
 * container class.
 *
 * The template types to specified are the container class of the parameter, the 
 * parameter type and its corresponding parameter class type (derived from 
 * CParameter). When instantiating an object a pointer to the container object
 * and pointers to the set and get methods of the class must be specified.
 *
 *******************************************************************************/

    template < class _ParamContainerClass, 
               class _ParamType,
               class _ParamTypeClass >
    class CParameterConnector: public CParameterBaseConnector
    {
    /// Public data types
    public:
        typedef bool       (_ParamContainerClass::*SetMethod_t) ( _ParamType );
        typedef _ParamType (_ParamContainerClass::*GetMethod_t) ( ) const;

        CParameterConnector (_ParamContainerClass *  f_container_p,
                             GetMethod_t             f_getMethod_p,
                             SetMethod_t             f_setMethod_p ) 
                : CParameterBaseConnector (             ),
                  m_paramContainerObj_p(  f_container_p ),
                  m_getMethod_p (         f_getMethod_p ),
                  m_setMethod_p (         f_setMethod_p )
        { 
        }

        virtual ~CParameterConnector () {}
        
        
    /// Virtual public functions
    public:
        /// Update calling the set method of the container.
        virtual bool updateContainer();

        /// Update the parameter object calling the setValue method
        /// of the parameter.
        virtual bool updateParameterObj();

    /// Protected members
    protected:

        /// Pointer to container object.
        _ParamContainerClass *     m_paramContainerObj_p;
 
        /// Get method in param container class.
        GetMethod_t                m_getMethod_p;

        /// Set method in param container class.
        SetMethod_t                m_setMethod_p;        
    };
    
    template < class _ParamContainerClass, 
               class _ParamType,
               class _ParamTypeClass >
    inline
    bool CParameterConnector< _ParamContainerClass, 
                              _ParamType,
                              _ParamTypeClass >::updateContainer() 
    {
        _ParamTypeClass * ptr = static_cast<_ParamTypeClass *>(m_parameter_p);

        if (!ptr) return false;
        
        const _ParamType param1 = ptr -> getValue();
        const _ParamType param2 = (m_paramContainerObj_p->*m_getMethod_p)( );

        if ( !(param1 == param2) )
        {
            if ( not (m_paramContainerObj_p->*m_setMethod_p)( param1 ) )
                return false;
        }
        return true;
    }

    template < class _ParamContainerClass, 
               class _ParamType,
               class _ParamTypeClass >
    inline
    bool CParameterConnector< _ParamContainerClass,
                              _ParamType,
                              _ParamTypeClass >::updateParameterObj()
    {
        _ParamTypeClass * ptr = static_cast<_ParamTypeClass *>(m_parameter_p);

        if (!ptr)
            return false;

        const _ParamType param1 = ptr -> getValue();
        const _ParamType param2 = (m_paramContainerObj_p->*m_getMethod_p)( );

        if ( !(param1 == param2) )
        {
            if ( not (ptr -> setValue ( param2, false ) ) )
                return false;
        }
        return true;
    }    

}


#endif // __PARAMBASECONNECTOR_H

/* ////////////  Version History ///////////////
 *  $Log: paramBaseConnector.h,v $
 *  Revision 1.2  2009/11/18 15:51:01  badino
 *  badino: documentation added. Some other global changes.
 *
 *//////////////////////////////////////////////
