/*****************************************************************************
 *
 * Testmanager - Graphical Automation and Visualisation Tool
 *
 * Copyright (C) 2018-2023  Florian Pose <fp@igh.de>
 *
 * This file is part of Testmanager.
 *
 * Testmanager 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 3 of the License, or (at your option)
 * any later version.
 *
 * Testmanager 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 Testmanager. If not, see <http://www.gnu.org/licenses/>.
 *
 ****************************************************************************/

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "Plugin.h"
#include "DataModel.h"

#include <string>
#include <QMainWindow>

#include <QClipboard>
#include <QLabel>
#include <QSocketNotifier>
#include <QJsonObject>

#include "ui_MainWindow.h"

/****************************************************************************/

class SourceDelegate;
class PropertyModel;
class PropertyNode;
class PropertyDelegate;
class ScriptVariable;
class ParameterModel;
class ParameterSetModel;

struct _object;
typedef struct _object PyObject;

namespace QtPdCom {
    class Message;
}

/****************************************************************************/

class MainWindow:
    public QMainWindow,
    public Ui::MainWindow
{
    Q_OBJECT

    public:
        MainWindow(const QString &, bool, bool, QWidget *parent = 0);
        ~MainWindow();

        static PyObject *pythonMethodTabCount(PyObject *, PyObject *);
        static PyObject *pythonMethodMaximize(PyObject *, PyObject *);

        DataModel *getDataModel() const {
            return dataModel;
        }
        PropertyModel *getPropertyModel() const {
            return propertyModel;
        }
        ParameterModel *getParameterModel() const {
            return parameterModel;
        }
        ParameterSetModel *getParameterSetModel() const {
            return parameterSetModel;
        }
        const PluginMap &getPluginMap() const { return pluginMap; }
        bool getEditMode() const { return editMode; }

        int getGridStep() const { return gridStep; }

        bool getAutoConnect() const { return autoConnect; }

        enum Filter { All, Selected };
        QSet<WidgetContainer *> containers(Filter) const;
        QSet<WidgetContainer *> containers(const QUrl &) const;
        QSet<WidgetContainer *> containers(const QSet<QUrl> &) const;
        void deselectAll() const;

        void selectionChanged();
        void ensureLoginDialog(DataSource *dataSource);

        QJsonArray checkPaste();

    public slots:
        void signalRaised(int);

    private:
        DataModel *dataModel;
        SourceDelegate *sourceDelegate;
        PropertyModel *propertyModel;
        PropertyDelegate *propertyDelegate;
        PluginMap pluginMap;
        bool editMode;
        int gridStep;
        bool restore;
        QStringList recentFiles;
        QString filePath;
        PropertyNode *propertyNode; // selected node
        ScriptVariable *scriptVariable; // selected variable
        int pythonStdOut[2];
        int pythonStdErr[2];
        QSocketNotifier *pythonStdOutNotifier;
        QSocketNotifier *pythonStdErrNotifier;
        bool autoConnect;
        ParameterModel *parameterModel;
        ParameterSetModel *parameterSetModel;

        QList<QString> pythonHistory;
        int pythonHistoryIndex;

        enum { MaxRecentFiles = 10 };
        QAction *recentFileActions[MaxRecentFiles];

        QLabel *labelIn;
        QLabel *labelOut;
        QLabel *statusMessageIcon;
        QLabel *statusMessageText;

        static MainWindow *singleton;

        QPersistentModelIndex dataIndex;

#ifdef _WIN32
        std::wstring applicationDirPrefix;
#endif

        void clearTabs();
        void initPython();
        void loadLayout(const QString &);
        void saveLayout();
        void updateWindowTitle();
        void pythonBenchmark();
        void showEvent(QShowEvent *);
        void closeEvent(QCloseEvent *);
        void addRecentFile(const QString &);
        void updateRecentFileActions();
        void expandChildren(const QModelIndex &, QTreeView *, int);
        void updateEditMode();
        void updatePaste();
        void replaceUrl(const QUrl &, const QUrl &);
        void appendTab(const QString &, const QJsonObject & = QJsonObject());
        QSet<WidgetContainer *> usingSelected() const;

    private slots:
        void on_actionNew_triggered();
        void on_actionLoad_triggered();
        void on_actionLoadParameterFile_triggered();
        void openRecentFile();
        void on_actionSave_triggered();
        void on_actionSaveAs_triggered();
        void on_actionClose_triggered();
        void on_actionCopy_triggered();
        void clipboardChanged(QClipboard::Mode);
        void on_actionPaste_triggered();
        void on_actionConnectAll_triggered();
        void on_actionConnect_triggered();
        void on_actionEditMode_toggled(bool);
        void on_actionGlobalStyleSheet_triggered();
        void on_actionAddTab_triggered();
        void on_actionAboutTestManager_triggered();
        void on_tabWidget_tabBarDoubleClicked(int);
        void on_lineEditFilter_textChanged(const QString &);
        void on_toolButtonClearFilter_clicked();
        void sourceTreeCustomContextMenu(const QPoint &);
        void connectDataSource();
        void disconnectDataSource();
        void loginDataSource();
        void logoutDataSource();
        void removeDataSource();
        void replaceDataSource();
        void onLoginFailed();
        void dataSourceShowMessages();
        void dataSourceConfigMessages();
        void copyVariableUrl();
        void selectSubscribers();
        void expandData();
        void expandProperties();
        void propertyTreeCustomContextMenu(const QPoint &);
        void resetProperty();
        void scriptVariablesCustomContextMenu(const QPoint &);
        void removeScriptVariables();
        void clearScriptVariables();
        void tableViewParametersCustomContextMenu(const QPoint &);
        void removeParameter();
        void clearParameters();
        void newParameterSet();
        void removeParameterSet();
        void changeParameterSet(const QModelIndex &);
        void saveParameters();
        void tabCloseRequested(int);
        void pythonStdOutDataAvailable(int);
        void pythonStdErrDataAvailable(int);
        void connectionStateChanged(DataModel::ConnectionState);
        void connectDataSlots();
        void statsChanged();
        void currentMessage(const QtPdCom::Message *);
};

/****************************************************************************/

#endif
