/*@@@**************************************************************************
* \file  mainWindow
* \author Hernan Badino
* \date  Mon Mar  2 17:04:12 Local time zone must be set--see zic manual page 2009
* \notes 
*******************************************************************************
******************************************************************************/

/* INCLUDES */
#include <QSettings>
#include <QMessageBox>
#include <QToolBar>
#include <QMenuBar>


#include "events.h"
#include "mainWindow.h"
#include "seqControlDlg.h"

#include "seqDevTester.h"
#include "seqDevHDImg.h"
#include "seqControler.h"
#include "displayWidget.h"
#include "operator.h"
#include "windowListView.h"
#include "paramEditorDlg.h"

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

using namespace VIC;

CMainWindow::CMainWindow ( COperator * f_rootOp_p )
        : m_listView_p (           NULL ),
          m_device_p (             NULL ),
          m_controler_p (          NULL ),
          m_display_p (            NULL ),
          m_paramEditorDlg_p (     NULL ),
          m_rootOp_p (       f_rootOp_p ),
          m_3dViewer_p (           NULL )
{
    setWindowTitle( tr("CVFramework Window Control") );
    setObjectName ( windowTitle() );

    /// Read saved geometry.
    QSettings qSettings;
    restoreGeometry ( 
            qSettings.value(objectName() + QString("/geometry")).toByteArray() );

    /// Create menues.
    createMenues();

    m_listView_p = new CWindowListView ( this );

    setCentralWidget( m_listView_p );

    createBaseWidgets();

    m_controler_p -> start();
    
    //m_listView_p -> showWindows( );
}

CMainWindow::~CMainWindow( )
{
    /// Write geometry.
    QSettings qSettings;
    qSettings.setValue(objectName() + QString("/geometry"), 
                       saveGeometry());
    m_listView_p -> saveWindowsGeometry( );

    /// Delete all operators.
    if ( m_rootOp_p )
        delete m_rootOp_p;

    /// Delete device.
    if (m_device_p)
        delete m_device_p;

    m_device_p = NULL;
    
    /// Delete controler.
    if (m_controler_p)
        delete m_controler_p;
    m_controler_p = NULL;

    /// Delete display.
    if (m_display_p)
        delete m_display_p;
    m_display_p = NULL;    

    /// Delete parameter editor,
    if (m_paramEditorDlg_p)
        delete m_paramEditorDlg_p;
    m_paramEditorDlg_p = NULL;    

#if defined HAVE_QGLVIEWER
    if (m_3dViewer_p)
        delete m_3dViewer_p;
#endif
}

void CMainWindow::createMenues()
{
    // Create first menu and toolbar entries.
    QToolBar *qtbWindow_p = this -> addToolBar ( tr("Windows") );
    QMenu    *qmWindows_p = this -> menuBar() -> addMenu( tr("&Windows") );
    QMenu    *qmHelp_p    = this -> menuBar() -> addMenu( tr("&Help") );

    /// First set toolbar not moveable.
    qtbWindow_p -> setMovable ( false );
    qtbWindow_p -> setIconSize ( QSize(32,32) );

    /// Create Show All Windows Action.
    QAction *qaShowAllWindows_p = new QAction ( QIcon(":/symbols/showAllWindows.png"),
                                                tr("&Show all windows"),
                                                this );
    qaShowAllWindows_p -> setStatusTip( tr("Make all windows visible") );
    qtbWindow_p -> addAction ( qaShowAllWindows_p );
    qmWindows_p -> addAction ( qaShowAllWindows_p );
    // Connect action to corresponding slot.
    connect( qaShowAllWindows_p, SIGNAL(triggered(bool)), this, SLOT(showAllWindows()) );

    /// Create Hide All Windows Action.
    //QAction *qaHideAllWindows_p = new QAction ( QIcon(":/symbols/hideAllWindows.png"),
    QAction *qaHideAllWindows_p = new QAction ( QIcon("mime:player_play"),
                                                tr("&Hide all windows"),
                                                this );
    qaHideAllWindows_p -> setStatusTip( tr("Make all windows invisible") );
    qtbWindow_p -> addAction ( qaHideAllWindows_p );
    qmWindows_p -> addAction ( qaHideAllWindows_p );
    // Connect action to corresponding slot.
    connect( qaHideAllWindows_p, SIGNAL(triggered(bool)), this, SLOT(hideAllWindows()) );


    /// Create Exit Action.
    QAction *qaExit_p = new QAction ( QIcon(":/symbols/exit.png"),
                                      tr("&Exit."),
                                      this );

    qaExit_p -> setStatusTip( tr("Exit application saving preferences.") );
    qtbWindow_p -> addAction ( qaExit_p );
    qmWindows_p -> addAction ( qaExit_p );
    // Connect action to quit slot.
    connect( qaExit_p, SIGNAL(triggered(bool)), qApp, SLOT(quit()) );

    /// Create About Action
    QAction *qaAbout_p = new QAction ( QIcon(":/symbols/about.png"),
                                       tr("&About CVFramework..."),
                                       this );
    qaAbout_p -> setStatusTip( tr("Show CVFramework information.") );
    qmHelp_p -> addAction ( qaAbout_p );
    // Connect action to quit slot.
    connect( qaAbout_p, SIGNAL(triggered(bool)), this, SLOT(about()) );

}

void CMainWindow::createBaseWidgets()
{
    /// Create device.
    //m_device_p    = new CSeqDevTester;
    /// Create device.

    m_device_p         = new CSeqDevHDImg ();

    /// Create controler.
    m_controler_p      = new CSeqControler ( m_device_p );

    /// Create display.
    m_display_p        = new CDisplayWidget ( 0,
                                         m_rootOp_p -> getDrawingListHandler() );

    /// Create parameter editor.
    m_paramEditorDlg_p = new CParameterEditorDlg ( m_rootOp_p -> getParameterSet(),
                                                   NULL );

#if defined HAVE_QGLVIEWER
    m_3dViewer_p       = new CGLViewer;
    m_3dViewer_p -> setWindowTitle(tr("3D GL Viewer"));
    m_3dViewer_p -> setObjectName ( m_3dViewer_p -> windowTitle() );
    m_rootOp_p -> set3DViewer ( m_3dViewer_p );
#endif

    /// Show display.
    //m_display_p -> show();

    /// Add windows to list.
    //m_window_v.push_back( m_device_p );
    //m_window_v.push_back( m_controler_p -> getDialog() );
    //m_window_v.push_back( m_display_p );
    //m_window_v.push_back( m_display_p -> getDialog() );

    //std::vector<QWidget *> opWidgets = m_rootOp_p -> getWidgets();
    //printf("TOTAL NUMBER OF OPERATOR WIDGETS IS %i\n", opWidgets.size());
    //m_window_v.insert( m_window_v.end(), opWidgets.begin(), opWidgets.end());

    m_listView_p->insertWindow ( m_controler_p -> getDialog() );
    m_listView_p->insertWindow ( m_display_p );
    m_listView_p->insertWindow ( m_display_p -> getDialog() );
    m_listView_p->insertWindow ( m_paramEditorDlg_p );

#if defined HAVE_QGLVIEWER
    m_listView_p->insertWindow ( m_3dViewer_p );
#endif

    std::vector<QWidget *> opWidgets = m_rootOp_p -> getWidgets();
    for (unsigned int i = 0; i < opWidgets.size(); ++i)
        m_listView_p->insertWindow (opWidgets[i]);

    // Connections with Controler.
    connect( m_controler_p, SIGNAL(cycle()), this, SLOT(cycle()) );
    connect( m_controler_p, SIGNAL(stop()),  this, SLOT(stop()) );    
    connect( m_controler_p, SIGNAL(initialize()), this, SLOT(initialize()) );

    /// Get display object pointer.
    CDisplay *disp_p = m_display_p -> getDisplay();    

    // Connections Display <-> This
    QObject::connect( disp_p, SIGNAL(mousePressed ( CMouseEvent *  )), 
                      this,  SLOT(   mousePressed ( CMouseEvent * )));
    
    QObject::connect( disp_p, SIGNAL(mouseReleased ( CMouseEvent * )), 
                      this,  SLOT(   mouseReleased ( CMouseEvent * )));

    QObject::connect( disp_p, SIGNAL(mouseMoved ( CMouseEvent * )), 
                      this,  SLOT(   mouseMoved ( CMouseEvent * )));

    QObject::connect( disp_p, SIGNAL(wheelTurned ( CWheelEvent * )), 
                      this,  SLOT(   wheelTurned ( CWheelEvent * )));

    QObject::connect( disp_p, SIGNAL(keyPressed ( CKeyEvent * )), 
                      this,  SLOT(   keyPressed ( CKeyEvent * )));

    QObject::connect( disp_p, SIGNAL(regionSelected ( CRegionSelectedEvent * )), 
                      this,  SLOT(   regionSelected ( CRegionSelectedEvent * )));

    ///////////////////

    //bool load_b = ((CSeqDevHDImg *) m_device_p) -> loadNewSequence("sequence.xml");
    //printf("result of reading file sequence.xml is %i\n", load_b);

    ((CSeqDevHDImg *) m_device_p) -> loadNewSequence("sequence.xml");
}

void CMainWindow::initialize() 
{
    bool success_b;

    std::map< std::string, CIOObj * > devOutput;
    success_b = m_device_p -> registerOutputs ( devOutput );

    if ( success_b )
    {
        m_rootOp_p -> registerOutputs ( devOutput );

        success_b = m_rootOp_p -> initialize();
        success_b = m_rootOp_p -> cycle();
        success_b = m_rootOp_p -> show();

#if defined HAVE_QGLVIEWER
        m_3dViewer_p -> update();
#endif
    }

    m_display_p -> update();

    if (0) //autoPlay
    {
        m_controler_p -> playClicked();
    }

    /*
    m_window_v.clear();
    m_window_v.push_back( m_controler_p ->getDialog() );
    m_window_v.push_back( m_display_p );
    m_window_v.push_back( m_display_p ->getDialog() );

    std::vector<QWidget *> opWidgets = m_rootOp_p -> getWidgets();
    printf("TOTAL NUMBER OF OPERATOR WIDGETS IS %i\n", opWidgets.size());
    m_window_v.insert( m_window_v.end(), opWidgets.begin(), opWidgets.end());
    */

    //m_listView_p->clear();
    //m_listView_p->insertWindow ( m_controler_p -> getDialog() );
    //m_listView_p->insertWindow ( m_display_p );
    //m_listView_p->insertWindow ( m_display_p -> getDialog() );

    std::vector<QWidget *> opWidgets = m_rootOp_p -> getWidgets();

    for (unsigned int i = 0; i < opWidgets.size(); ++i)
    {
        m_listView_p->insertWindow ( opWidgets[i] );
    }
    
}

void CMainWindow::cycle() 
{
    bool success_b;
    
    std::map< std::string, CIOObj * > devOutput;
    success_b = m_device_p -> registerOutputs ( devOutput );
    
    if ( success_b )
    {
        m_rootOp_p -> registerOutputs ( devOutput );

        //printf("In CMainWindow::cycle calling cycle for root operator\n");
        success_b = m_rootOp_p -> cycle();
        //printf("In CMainWindow::cycle calling show for root operator\n");
        success_b = m_rootOp_p -> show();
#if defined HAVE_QGLVIEWER
        m_3dViewer_p -> update();
#endif
    }

    //printf("In CMainWindow::cycle updating display\n");
    m_display_p -> update();
}

void CMainWindow::stop() 
{
    bool success_b;

    std::map< std::string, CIOObj * > devOutput;
    success_b = m_device_p -> registerOutputs ( devOutput );

    if ( success_b )
    {
        m_rootOp_p -> registerOutputs ( devOutput );

        success_b = m_rootOp_p -> reset();
        success_b = m_rootOp_p -> initialize();
        success_b = m_rootOp_p -> cycle();
        success_b = m_rootOp_p -> show();
#if defined HAVE_QGLVIEWER
        m_3dViewer_p -> update();
#endif
    }

    m_display_p -> update();
}

void CMainWindow::about() 
{
    QMessageBox::about( this,
                        "About CVFramework ",
                        tr("This app was coded for educational purposes") );
}

void CMainWindow::hideAllWindows() 
{
    QMessageBox::about( this,"Hiding all windows.", "Bye" );
}

void CMainWindow::showAllWindows() 
{
    QMessageBox::about( this,
                        "Showing all windows.",
                        "Bye" );
}

void CMainWindow::keyPressed ( CKeyEvent * const f_event_p )
{
    QKeyEvent* keyEvent_p = f_event_p -> qtKeyEvent_p;
    
    if ( keyEvent_p -> key() == Qt::Key_P || 
         keyEvent_p -> key() == Qt::Key_Space )
    {
        if ( m_device_p -> getState() == CSeqDeviceControl::S_PLAYING )
        {
            m_controler_p -> pauseClicked();
        }
        else
        {
            m_controler_p -> playClicked();
        }       
    }
    else if ( keyEvent_p -> key() == Qt::Key_S )
    {
        m_controler_p -> stopClicked();
    }

    if ( m_device_p -> getState() != CSeqDeviceControl::S_PLAYING )
    {
        if (keyEvent_p -> key() == Qt::Key_Right )
        {
            m_controler_p -> nextClicked();
        }
        else if ( keyEvent_p -> key() == Qt::Key_Left )
        {
            m_controler_p -> previousClicked();
        }
    }

    m_rootOp_p -> keyPressed ( f_event_p );    

    m_display_p -> update ( false );
}

void
CMainWindow::mousePressed   ( CMouseEvent *  f_event_p )
{
    m_rootOp_p -> mousePressed ( f_event_p );

    m_display_p -> update ( false );
}

void 
CMainWindow::mouseReleased  ( CMouseEvent *  f_event_p )
{
    m_rootOp_p -> mouseReleased ( f_event_p );

    m_display_p -> update ( false );
}

void CMainWindow::mouseMoved     ( CMouseEvent *  f_event_p )
{
    m_rootOp_p -> mouseMoved ( f_event_p );

    m_display_p -> update ( false );
}

void CMainWindow::wheelTurned    ( CWheelEvent *  f_event_p )
{
    m_rootOp_p ->wheelTurned  ( f_event_p );

    m_display_p -> update ( false );
}

void CMainWindow::regionSelected ( CRegionSelectedEvent *  f_event_p )
{
    m_rootOp_p -> regionSelected ( f_event_p );

    m_display_p -> update ( false );
}

void CMainWindow::closeEvent ( QCloseEvent *  f_event_p)
{
    //printf("Close event was called\n");
    m_rootOp_p -> exit();
    //f_event_p->ignore();
    f_event_p->accept();

#if 0
    if (maybeSave()) 
    {
        writeSettings();
        event->accept();
    } else 
    {
        event->ignore();
     }
#endif
}


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