#ifndef __OPERATOR_H
#define __OPERATOR_H

/**
 *******************************************************************************
 *
 * @file operator.h
 *
 * \class COperator
 * \date  Tue Oct 13, 2009
 * \author Hernan Badino (hernan.badino@gmail.com)
 *
 * \brief Defines the base class for the operators of the framework.
 *
 * The COperator class provides a base for defining operators in the framework.
 * This class provides virtual functions for handling operations input provided by
 * the user or the device controler. The method cycle() is called every time new
 * sequence data is ready for processing. reset() is called when the device
 * controler stops operation (because of user input for example). initialize() is 
 * called when a new sequence data is loaded. exit() is called when the program 
 * exits or the current sequence is closed. Additional functions for handling 
 * mouse and keyboard actions are provided.
 *
 * An operator can have a parent and multiple children. This allows the generation
 * of tree structures. At least one root operator must exist in a functioning 
 * program.
 *
 * Operators also have a parameter set for defining the parameters of the operator.
 *
 * Data connections between operators are performed by registering outputs with 
 * (registerOutput methods) and requesting intput data (getInput methods).
 * 
 * An operator also might define visual output in the form of drawing lists 
 * (registerDrawingList and getDrawingList methods).
 *
 *******************************************************************************/

/* INCLUDES */
#include "events.h"

#include "ioObj.h"
#include "drawingListHandler.h"
#include "standardTypes.h"
#include "logger.h"
#include "parameterSet.h"
#include "paramMacros.h"
#include "paramBaseConnector.h"

//#include <iostream>
#include <string>
#include <vector>
#include <map>

#include "events.h"


#if defined HAVE_QGLVIEWER
#include "glViewer.h"
#endif

/* CONSTANTS */

/* PROTOTYPES */
class QWidget;

/* CLASS DEFINITION */

namespace VIC
{
/* PROTOTYPES */        
    class CGLViewer;

    class COperator
    {
    /// Constructor, Desctructors
    public:    

        /// Constructors.
        COperator ( COperator * const f_parent_p = NULL, 
                    const std::string f_name_str = "Unnamed Operator" );

        /// Virtual destructor.
        virtual ~COperator ();

    /// Sequence Cycle Events
    public:

        /// Cycle event.
        virtual bool cycle();

        /// Show event.
        virtual bool show();

        /// Init event.
        virtual bool initialize();

        /// Reset event.
        virtual bool reset();

        /// Exit event.
        virtual bool exit();


    /// User Operation Events
    public:

        /// Mouse clicked.
        virtual void mousePressed (   CMouseEvent * f_event_p );

        /// Mouse released.
        virtual void mouseReleased (  CMouseEvent * f_event_p );

        /// Mouse moved.
        virtual void mouseMoved (     CMouseEvent * f_event_p );

        /// Mouse wheel event.
        virtual void wheelTurned (    CWheelEvent * f_event_p );

        /// Key pressed in display.
        virtual void keyPressed (     CKeyEvent * f_event_p );

        /// Region selected in display.
        virtual void regionSelected ( CRegionSelectedEvent * 
                                     f_event_p );

    /// Get/Set methods
    public:

        /// Get list of widgets generated by this operator.
        virtual std::vector<QWidget*> getWidgets( ) const;

        /// Get name of operator.
        virtual std::string           getName() const;

        /// Get drawing handler.
        static CDrawingListHandler *  getDrawingListHandler() 
        {
            return &m_drawingListHandler;
        }

        /// Get the input of this operator.
        virtual COperator*            getParentOp ( ) const { return m_parent_p; }

        /// Get list of widgets generated by this operator.
        virtual void                  set3DViewer ( CGLViewer * viewer_p );

    /// I/O registration.
    public:

        /// Set the output of this operator.
        virtual void    registerOutput ( const std::string &f_id_str, 
                                         CIOObj * const f_ioObj,
                                         const unsigned int f_cycleDelay_ui = 0 );
        
        /// Set the output of this operator.
        virtual void    registerOutputs ( const std::map< std::string, CIOObj* > &f_elements,
                                          const unsigned int f_cycleDelay_ui = 0 );
        
        /// Get output of this operator.
        virtual CIOObj* getOutput ( const std::string &f_id_str, 
                                    const unsigned int f_cycleDelay_ui = 0 );

        /// Get the input of this operator.
        virtual CIOObj* getInput ( const std::string &f_id_str, 
                                   const unsigned int f_cycleDelay_ui = 0 ) const;
        
        /// Get the casted input object of this operator.
        template<class PtrType_, class CastType_>
        CastType_       getCastedInputObject ( const std::string &f_id_str, 
                                               const CastType_   &f_defaultValue ) const;

        /// Get the input object of this operator.
        template<class Type_>
        Type_           getInputObject ( const std::string &f_id_str, 
                                         const Type_       &f_defaultValue ) const;

        /// Get the casted input object of this operator.
        template<class Type_>
        const Type_   & getInputReference ( const std::string &f_id_str ) const;

        /// Get the casted input object of this operator.
        template<class Type_>
        Type_        & getInputReference ( const std::string &f_id_str );

    /// Parameter handling.
    public:

        /// Get parameter set.
        CParameterSet *   getParameterSet () const;

    /// Protected methods for internal use.
    protected:
        /// Register a drawing list so that is visible and available from the 
        /// beginning.
        void           registerDrawingList ( std::string f_id_str,
                                             S2D<int>    f_position = S2D<int>(0,0), 
                                             bool        f_visibile_b = false );

        void           addDrawingListParameter ( std::string f_id_str, 
                                                 std::string f_comment_str = "" );

        /// Get a drawing list to draw something.
        CDrawingList * getDrawingList ( std::string f_id_str );

        /// Inform the drawing list handler to update the display.
        void           updateDisplay();

    /// Support functions for internal use.
    protected:
        /// Add a child to this operator.
        virtual bool   addChild ( COperator * const f_child_p, 
                                  const int f_priority_i = 1 );

        /// Get a child with given id.
        virtual COperator * 
                       getChild ( unsigned int f_id_ui );

        /// Add a child to this operator.
        virtual void   deleteChildren (  );

    /// Private data types
    protected:
        struct SChildren
        {
            /// Pointer to operator.
            COperator *   ptr_p;
            
            /// Priority
            int32_t       priority_i;
            
            /// Operator < for sorting operations.
            int operator < ( SChildren &other )
            {
                return priority_i < other.priority_i;
            }            
        };
        

    /// Private static members
    private:
        /// Drawing handler
        static CDrawingListHandler         m_drawingListHandler;

    /// Protected static members
    protected:
        /// 3D Viewer.
        static CGLViewer *                 m_3dViewer_p;

    /// Private members
    protected:    

        /// Operator's parent.
        COperator *                        m_parent_p;

        /// Operator's children.
        std::vector<SChildren>             m_children_v;

        /// Operator's name.
        std::string                        m_name_str;

        /// I/O list.
        std::map< std::string, CIOObj* >   m_ios;

        /// Operator's parameter handling.
        CParameterSet *                    m_paramSet_p;

        /// Clock handling.
        /// to be implemented.

        /// Plots handling.
        /// to be implemented.

    };

    /// Get the input object of this operator.
    template<class Type_>
    Type_ COperator::getInputObject ( const std::string &f_id_str, 
                                      const Type_       &f_defaultValue ) const
    {
        return getCastedInputObject<Type_, Type_> ( f_id_str, f_defaultValue );
    }    

    /// Get an input object.
    template<class PtrType_, class CastType_>
    CastType_ COperator::getCastedInputObject ( const std::string &f_id_str, 
                                                const CastType_   &f_defaultValue ) const
    {
        PtrType_ *  obj_p = dynamic_cast<PtrType_ *>(getInput ( f_id_str ) );
        if (obj_p) 
            return (CastType_) (*obj_p);
        
        return f_defaultValue;
    }

    /// Get the casted input object of this operator.
    template<class Type_>
    Type_   & COperator::getInputReference ( const std::string &f_id_str )
    {
        Type_ *  obj_p = dynamic_cast<Type_ *>(getInput ( f_id_str ) );

        if (obj_p) 
            return (*obj_p);
        
        logger::error("Error while accessing input.");
        static Type_ def;

        return def;
    }
 
    /// Get the casted input object of this operator.
    template<class Type_>
    const Type_   & COperator::getInputReference ( const std::string &f_id_str ) const
    {
        Type_ *  obj_p = dynamic_cast<Type_ *>(getInput ( f_id_str ) );

        if (obj_p) 
            return (*obj_p);
        
        logger::error("Error while accessing input.");
        const static Type_ def;
        
        return def;
    }
    

} // Namespace VIC

#endif // __OPERATOR_H

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