#ifndef MainWindow_h
#define MainWindow_h

/******************************************************************************
*
* Copyright (C) 2002 Hugo PEREIRA <mailto: hugo.pereira@free.fr>
*
* This is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT
* Any WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program.  If not, see <http://www.gnu.org/licenses/>.
*
*******************************************************************************/

#include "BaseMainWindow.h"
#include "Counter.h"
#include "CustomToolBar.h"
#include "Debug.h"
#include "JobCommand.h"
#include "Job.h"
#include "JobRecord.h"
#include "Key.h"
#include "UserSet.h"

#include <QCloseEvent>

class TabWidget;
class JobManagerFrame;
class BaseStatusBar;
class SummaryFrame;
class SignalMenu;
class UserSelectionFrame;

class MainWindow: public BaseMainWindow, public Base::Key
{

    //* Qt meta object declaration
    Q_OBJECT

    public:

    //* constructor
    MainWindow( QWidget* = nullptr );

    //* user
    UserSelectionFrame& userSelectionFrame( void ) const
    { return *userFrame_; }

    //* toolbar
    CustomToolBar& userToolBar( void )
    { return *userToolBar_; }

    //* toolbar
    CustomToolBar& toolBar( void )
    { return *toolbar_; }

    //* active frame
    bool hasActiveFrame( void ) const
    { return (bool) activeFrame_; }

    //* active frame
    JobManagerFrame& activeFrame( void ) const
    { return *activeFrame_; }

    //* status bar
    BaseStatusBar& statusBar( void ) const
    { return *statusBar_; }

    //* pause state
    bool isPaused( void ) const
    { return isPaused_; }

    //* install frames
    void installFrames( void );

    //*@name actions
    //@{

    //* toggle summary
    QAction& toggleSummaryAction( void ) const
    { return *toggleSummaryAction_; }

    //* resume paused job
    QAction& resumeAction( void ) const
    { return *resumeAction_; }

    //* pause job
    QAction& pauseAction( void ) const
    { return *pauseAction_; }

    //* kill job
    QAction& killAction( void ) const
    { return *killAction_; }

    //* update
    QAction& updateAction( void ) const
    { return *updateAction_; }

    //* tree view action
    QAction& treeViewAction( void ) const
    { return *treeViewAction_; }

    //* lock
    QAction& lockAction( void ) const
    { return *lockAction_; }

    //* add frame
    QAction& addFrameAction( void ) const
    { return *addFrameAction_; }

    //* remove current frame
    QAction& removeFrameAction( void ) const
    { return *removeFrameAction_; }

    //* record
    QAction& recordAction( void ) const
    { return *recordAction_; }

    //* record
    QAction& toggleRecordAction( void ) const
    { return *toggleRecordAction_; }

    //@}

    Q_SIGNALS:

    //* request command
    void commandRequested( JobCommand );

    //* new jobs available
    void newJobs( Job::Set );

    public Q_SLOTS:

    //* update actions visibility
    void updateActions( void );

    //* update users
    void updateUsers(UserSet);

    //* add frame
    void addFrame( const QString& );

    //* run top to look for job updates
    void requestJobList( void );

    //* process job list
    void processJobList( Job::Set );

    //* close record dialogs
    void closeJobInformationDialogs( void );

    protected Q_SLOTS:

    //* update configuration
    void _updateConfiguration( void );

    //* save configuration
    void _saveConfiguration( void );

    //* update uesr
    void _updateUser( QString );

    //* active frame changed
    void _activeFrameChanged( int );

    //* toggle summary
    void _toggleSummary( bool );

    //* resume selected jobs
    void _resume( void );

    //* pause selected jobs
    void _pause( void );

    //* kill selected jobs
    void _kill( void );

    //* send signal to selected jobs
    void _sendSignal( int );

    //* opens recorder for selected jobs
    void _record( void );

    //* toggle record all jobs
    void _toggleRecordAllJobs( bool );

    //* tree view
    void _toggleTreeView( bool );

    //* pause/restart timer
    void _toggleUpdate( bool );

    //* add frame
    void _addFrame( void );

    //* remove frame
    void _removeFrame( void );

    //* remove frame at index
    void _removeFrame( int );

    //* record dialog closed
    void _recordDialogClosed( JobRecord );

    protected:

    //* timer event
    void timerEvent( QTimerEvent* );

    //* close window event handler
    void closeEvent( QCloseEvent* );

    //* active frame
    void _setActiveFrame( JobManagerFrame& frame );

    //* create a new frame
    JobManagerFrame& _newFrame( void );

    //* update frames
    void _updateFrames( const Job::Set& );

    //* update job records
    void _updateRecords( Job::Set );

    private:

    //* summary
    void _installActions( void );

    //* used to find records which have no matching job
    /**
    stores a set of jobs. For each jobRecord, loop for a matching
    job in the set. If one is found, the record gets updated and the
    job is erased from the set. False is returned. If none is found
    true is returned. Since the set of jobs is passed as a reference,
    the set of jobs is automatically updated. Remaining jobs are to be added to the list
    */
    class NoJobFTor
    {

        public:

        //* constructor
        NoJobFTor( Job::Set& jobs ):
            jobs_( jobs )
        {}

        //* predicate
        /**
        stores a set of jobs. For each jobRecord, loop for a matching
        job in the set. If one is found, the record gets updated and the
        job is erased from the set. False is returned. If none is found
        true is returned.
        */
        bool operator () ( JobRecord& );

        private:

        // reference set of jobs
        Job::Set& jobs_;

    };

    //* toolbar
    CustomToolBar* userToolBar_ = nullptr;

    //* toolbar
    CustomToolBar* toolbar_ = nullptr;

    //* user
    UserSelectionFrame* userFrame_ = nullptr;

    //* status bar
    BaseStatusBar* statusBar_ = nullptr;

    //* tab widget
    TabWidget* tabWidget_ = nullptr;

    //* active frame
    JobManagerFrame* activeFrame_ = nullptr;

    //* signal menu
    SignalMenu* signalMenu_ = nullptr;

    //* true if paused
    bool isPaused_ = false;

    //* refresh rate
    int refreshRate_ = 0;

    //* timer object for scheduled update
    QBasicTimer timer_;

    //* local copy of jobs
    Job::Set jobs_;

    //* list of JobRecord associated to found jobs.
    /** it is used to create histograms of a given job resources */
    JobRecord::List records_;

    //*@name actions
    //@{

    //* resume paused job
    QAction* resumeAction_ = nullptr;

    //* pause job
    QAction* pauseAction_ = nullptr;

    //* kill job
    QAction* killAction_ = nullptr;

    //* record
    QAction* recordAction_ = nullptr;

    //* record all jobs flag
    QAction* toggleRecordAction_ = nullptr;

    //* update
    QAction* updateAction_ = nullptr;

    //* tree view
    QAction* treeViewAction_ = nullptr;

    //* lock
    QAction* lockAction_ = nullptr;

    //* toggle summary frame
    QAction* toggleSummaryAction_ = nullptr;

    //* add frame
    QAction* addFrameAction_ = nullptr;

    //* remove frame
    QAction* removeFrameAction_ = nullptr;

    //@}

};

#endif
