/*@@@**************************************************************************
* \file  operator
* \author Hernan Badino
* \date  Thu Feb 19 12:58:34 Local time zone must be set--see zic manual page 2009
* \notes 
*******************************************************************************
******************************************************************************/

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

#include "operator.h"
#include "drawingList.h"
#include "displayStateParam.h"

using namespace VIC;

CDrawingListHandler COperator::m_drawingListHandler;
CGLViewer *         COperator::m_3dViewer_p = NULL;

COperator::COperator (  COperator * const f_parent_p /* = NULL */, 
                        const std::string f_name_str /* = "Unnamed Operator" */ )
        : m_parent_p (             f_parent_p ),
          m_name_str (             f_name_str ),
          m_paramSet_p (                 NULL )
{
    if ( m_parent_p )
        m_paramSet_p = new CParameterSet ( m_parent_p -> getParameterSet () );
    else
        m_paramSet_p = new CParameterSet ( NULL );

    m_paramSet_p -> setName ( f_name_str );
}

COperator::~COperator ()
{
    /// Delete parameter set only if this is the root node.
    if ( m_parent_p == NULL )
        delete m_paramSet_p;

    deleteChildren ( );
}

void
COperator::deleteChildren ( )
{
    for (int i = m_children_v.size()-1; i >=0 ; --i)
    {
        printf("COperator:: Deleting operator %i name: %s\n", i, m_children_v[i].ptr_p->getName().c_str());
        delete m_children_v[i].ptr_p;
        m_children_v.pop_back();
        printf("COperator:: Ready deleting operator %i\n", i);
    }
}

bool 
COperator::cycle()
{
    bool result_b = true;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        bool res_b = m_children_v[i].ptr_p -> cycle();
        result_b &= res_b;
    }

    return result_b;
}

bool 
COperator::show()
{
    bool result_b = true;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        bool res_b = m_children_v[i].ptr_p ->  show();
        result_b &= res_b;
    }

    return result_b;
}

bool 
COperator::initialize()
{    
    bool result_b = true;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        //printf("Initializing %s\n", m_children_v[i].ptr_p -> getName().c_str());
        
        bool res_b = m_children_v[i].ptr_p ->  initialize();
        result_b &= res_b;
    }

    return result_b;
}

bool 
COperator::reset()
{
    bool result_b = true;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        bool res_b = m_children_v[i].ptr_p ->  reset();
        result_b &= res_b;
    }

    return result_b;
}

bool 
COperator::exit()
{
    bool result_b = true;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        bool res_b = m_children_v[i].ptr_p ->  exit();
        result_b &= res_b;
    }

    return result_b;
}

void 
COperator::mousePressed ( CMouseEvent * const f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  mousePressed ( f_event_p );
}

void 
COperator::mouseReleased ( CMouseEvent * const f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  mouseReleased ( f_event_p );
}

void 
COperator::mouseMoved ( CMouseEvent * const f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  mouseMoved ( f_event_p );
}

void 
COperator::wheelTurned ( CWheelEvent * const f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  wheelTurned ( f_event_p );
}

void 
COperator::regionSelected ( CRegionSelectedEvent * const 
                                f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  regionSelected ( f_event_p );
}

void 
COperator::keyPressed ( CKeyEvent * const f_event_p )
{
    for (uint32_t i = 0; i < m_children_v.size(); ++i)
        m_children_v[i].ptr_p ->  keyPressed ( f_event_p );
}

std::vector<QWidget*> 
COperator::getWidgets( ) const
{
    // Return empty vector.
    std::vector<QWidget *> v;

    for (uint32_t i = 0; i < m_children_v.size(); ++i)
    {
        std::vector<QWidget *> childWidgets = m_children_v[i].ptr_p ->  getWidgets ( );        
        v.insert ( v.end(), childWidgets.begin(), childWidgets.end() );        
    }

    return v;
}

std::string 
COperator::getName() const
{
    return m_name_str;
}

void 
COperator::registerOutput ( const std::string &f_id_str, 
                            CIOObj * const f_ioObj,
                            const unsigned int /*f_cycleDelay_ui*/ )
{
    m_ios[f_id_str] = f_ioObj;

    if (m_parent_p)
        m_parent_p -> m_ios[f_id_str] = f_ioObj;
}

void 
COperator::registerOutputs ( const std::map< std::string, CIOObj* > &f_elements,
                             const unsigned int /*f_cycleDelay_ui*/ )
{
    m_ios.insert( f_elements.begin(), f_elements.end() ) ;   
    
    if (m_parent_p)
        m_parent_p -> m_ios.insert( f_elements.begin(), f_elements.end() ) ;
}

/// Get output of this operator.
CIOObj*
COperator::getOutput ( const std::string &f_id_str, 
                       const unsigned int /* f_cycleDelay_ui */ )
{
    // Find object.
    const std::map<std::string, CIOObj*>::const_iterator 
        it = m_ios.find( f_id_str );
    
    if ( it == m_ios.end() )    
    {
        // Return empty element.
        std::string warn_str =  (std::string) "Object with Id \"" + f_id_str + "\" not found.";
        logger::warn(warn_str);
        WARN(warn_str);
        
        return NULL;
    }
    
    return it->second;
}

CIOObj* 
COperator::getInput ( const std::string &f_id_str,
                      const unsigned int /* f_cycleDelay_ui */ ) const
{
    // Find object.
    const std::map<std::string, CIOObj*>::const_iterator 
        it = m_ios.find( f_id_str );
    
    if ( it == m_ios.end() )
    {
        if ( m_parent_p )
        {
            // Check if the object is available at higher levels.
            return m_parent_p -> getInput ( f_id_str );
        }
        else
        {
            // Return empty element.
            std::string warn_str =  (std::string) "Object with Id \"" + f_id_str + "\" not found.";
            logger::warn(warn_str);
            WARN(warn_str);
            
            return NULL;
        }
    }
    else
    {
        // Return corresponding element.
        return it->second;
    }
}

bool 
COperator::addChild ( COperator * const f_child_p, 
                      const int f_priority_i /* = 1 */ )
{
    SChildren newChild;
    newChild.ptr_p      = f_child_p;
    newChild.priority_i = f_priority_i;

    // Add child.
    m_children_v.push_back( newChild );

    // If priority must be considered...
    if ( f_priority_i >= 0 )
    {
        uint32_t i;

        // Move child one position until corresponding position for new child is
        // found....

        for (i = m_children_v.size() - 1; 
             i > 0 && 
             m_children_v[i].priority_i < f_priority_i ; --i)
        {
            m_children_v[i] = m_children_v[i - 1];
        }

        m_children_v[i] = newChild;
    }

    return true;
}

void 
COperator::registerDrawingList ( std::string f_id_str,
                                 S2D<int>    f_position, 
                                 bool        f_visibile_b )
{
     CDrawingList *  list_p = m_drawingListHandler.getDrawingList ( f_id_str, this );
     list_p -> setPosition ( f_position );
     list_p -> setVisibility ( f_visibile_b );
}

CDrawingList * 
COperator::getDrawingList ( std::string f_id_str )
{
    return m_drawingListHandler.getDrawingList ( f_id_str, this );
}

/// Add a child to this operator.
COperator * 
COperator::getChild ( unsigned int f_id_ui )
{
    if (f_id_ui >= m_children_v.size())
        return NULL;

    return m_children_v[f_id_ui].ptr_p;
}

/// Inform the drawing list handler to update the display.
void 
COperator::updateDisplay ( )
{
    m_drawingListHandler.setDisplayUpdateFlag ( true );
}

CParameterSet *
COperator::getParameterSet() const
{
    return m_paramSet_p;
}

void 
COperator::addDrawingListParameter ( std::string f_id_str,
                                     std::string f_comment_str )
{
    CDrawingList *list_p;
    list_p = getDrawingList(f_id_str);

    if (f_comment_str.empty())
        f_comment_str = list_p -> getName();

    m_paramSet_p -> addParameter (
            new CDisplayStateParameter ( list_p -> getName(), 
                                         f_comment_str, 
                                         list_p -> getDisplayState(),
                                         new CParameterConnector< CDrawingList, SDisplayState, CDisplayStateParameter >
                                         ( list_p, 
                                           &CDrawingList::getDisplayState, 
                                           &CDrawingList::setDisplayState ) ) );
}

void
COperator::set3DViewer ( CGLViewer * viewer_p )
{
#if defined HAVE_QGLVIEWER
    m_3dViewer_p = viewer_p;
#else
    m_3dViewer_p = NULL;
#endif

}

/* ////////////  Version History ///////////////
 *  $Log: operator.cpp,v $
 *  Revision 1.2  2009/11/18 15:50:15  badino
 *  badino: global changes.
 *
 *//////////////////////////////////////////////
