/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

// -- Core stuff
#include "CamiTKAPI.h"
#include "ConsoleStream.h"

// -- QT stuff
#include <QMainWindow>
#include <QApplication>
#include <QDir>
#include <QTextEdit>
#include <QLineEdit>
#include <QProgressBar>
#include <QStatusBar>
#include <QStackedLayout>

namespace camitk {

// -- Core stuff classes
class Component;
class Viewer;
class LogSyntaxHighlighter;

/**
  * @ingroup group_sdk_libraries_core_application
  *
  * @brief
  * This class is the base class for your application. It sets up the main
  * window and creates a menubar and statusbar (all hidden by default).
  *
  * It is the default main window for a application.
  *
  * Create a class that inherits from MainWindow to
  * get all the goodies of CamiTK and add your own customization/UI.
  *
  * See tutorials applications for examples.
  *
  * The central widget's layout is a QStackedLayout: when new central viewers are added, the previous central
  * viewer is hidden, not destroyed.
  */
class CAMITK_API MainWindow : public QMainWindow {
    Q_OBJECT

public:

    /// @name general
    ///@{
    /** Constructor, the window title can be changed here, it is inconsistent to use setWindowTitle().
     * If you like to dynamically add some information to the window title, please use setWindowSubtitle() instead.
     *
     * @see setWindowSubtitle
     * @param title main window title
     */
    MainWindow(QString title);

    /// destructor
    ~MainWindow() override;

    /** this method is automatically called by Application before the first time show() is called.
     * This method calls initSettings().
     */
    virtual void aboutToShow();

    ///@}

    /// @name title, subtitle, status bar message, progress bar state and console
    ///@{

    /// Get the main window title
    QString getName() const;

    /** The subtitle is situated at the end of the title, on the title bar, is helps for example showing which file is currently
     *  selected.
     *  It appears between brackets "[ ... ]"
     *
     *  \note the main title is set to Core::version(), you can change the title part (i.e. the part
     *  of the title bar before the subtitle), by calling setWindowTitle(...)
     */
    void setWindowSubtitle(QString);

    /// similar as statusBar() from QMainWindow but for the progress bar
    QProgressBar* getProgressBar();

    /// show the status bar (by default it is hidden)
    void showStatusBar(bool);

    /// use or not the application console (redirect or not standard out/err streams)
    virtual void redirectToConsole(bool);

    /// get the console window
    void showConsole(bool);

    /// get the visibility state of the console (@return true if and only if the console is currently visible)
    bool getConsoleVisibility();
    ///@}

    /** @name Initialize and save settings */
    ///@{
    /// init MainWindow specific settings (e.g. size, position)
    virtual void initSettings();

    /// Save MainWindow's settings into Application::settings
    void saveSettings();
    ///@}

    /// @name Viewers
    ///@{

    /// set the visibility for the given docked viewer
    virtual void showDockViewer(Viewer*, bool);

    /** add a Viewer to the application as a docking widget and specify where it has to be docked
    * Note that MainWindow takes ownership of the Viewer pointer and deletes it at the appropriate time.
    *
    * This method calls addViewer(...).
    * This method calls showDockViewer(..,true)
    *
    * \note MainWindow takes ownership of the viewer pointer and deletes it when it is itself destroyed.
    */
    virtual void addDockViewer(Qt::DockWidgetArea, Viewer*);

    /** Method uses to refresh all the viewer of the Main Window */
    void refreshViewers();

    /** set the central Viewer of the application.
    * The central viewer has a specific behaviour in a MainWindow. It uses a QStackWidget to keep
    * all the central viewer that are used. When a new central viewers is set, the previous central
    * viewer (i.e., its widget) is hidden but not destroyed.
    *
    * This method calls addViewer(..).
    *
    * \note MainWindow takes ownership of the viewer pointer and deletes it when it is itself destroyed.
    */
    virtual void setCentralViewer(Viewer*);

    /**
     * @return the current central viewer.
     */
    virtual Viewer* getCentralViewer() const;
    ///@}

public slots:

    /** @name Refresh and show */
    ///@{
    /// this slot is connected to all the viewers selectionChanged() signal, this will call the refresh method of all viewers
    virtual void refresh();

    /// inherited from QWidget, just to refresh all viewers
    void show();
    ///@}

protected:

    /// overriden from QMainWindow, just connect to slotFileQuit
    void closeEvent(QCloseEvent*) override;

    /** @name Viewer and other things */
    ///@{
    /// the set of viewers
    QList<Viewer*> viewers;

    /// the map that gives the corresponding QDockWidget for a given Viewer
    QMap<Viewer*, QDockWidget*> dockWidgetMap;

    ///@}

    /// called when a drag event started on the main window, accept drag only if file is MIME type text/uri-list
    void dragEnterEvent(QDragEnterEvent* event) override;

    /// called when the mouse moves inside the widgets area during a drag/drop operation
    void dragMoveEvent(QDragMoveEvent* event) override;

    /// called when the mouse leaves the widgets area during a drag/drop operation
    void dragLeaveEvent(QDragLeaveEvent* event) override;

    /// just call open with the dragged uri
    void dropEvent(QDropEvent* event) override;

    /**
     * @brief The actual central Viewer.
     * @note MainWindow, like QMainWindow with its central widget contains an unique central viewer.
     */
    Viewer* centralViewer;


private:

    /**
     * Add a viewer (called by addDockViewer and setCentralViewer), returns true if not already added.
     * Note that MainWindow takes ownership of the Viewer pointer and deletes it when it is itself destroyed.
     *
     * This method connects the selectionChanged signal of the viewer to the refresh method of MainWindow.
     */
    virtual bool addViewer(Viewer*);

    /// the output stream for the application console
    ConsoleStream cout;

    /// the error stream for the application console
    ConsoleStream cerr;

    /// the progress bar (access through setProgress() method)
    QProgressBar* myProgressBar;

    /// console to display all messages
    QDockWidget* consoleWindow;

    /// the QTextEdit part of the console dialog
    QTextEdit* consoleWindowTextEdit;

    /// the log syntax highlighter used in the console
    LogSyntaxHighlighter* logSyntaxHighlighter;

    /// the main part of the title
    QString mainTitle;

    /// the central widget is a frame, its layout is a QStackedLayout so that
    /// it is possible to easily switch between viewers
    QStackedLayout* centralLayout;

};
}


#endif // MAINWINDOW_H
