/***************************************************************************
*                                                                         *
*   This program 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.                                   *
*                                                                         *
***************************************************************************/

#pragma once

#include <QApplication>
#include <QWidget>
#include <QMainWindow>
#include <QList>
#include <QMenuBar>
#include <QMenu>
#include <QCloseEvent>
#include <QShowEvent>
#include <QTabBar>
#include <QToolBar>
#include <QHash>
#include <QSessionManager>

#include "dcpp/stdinc.h"
#include "dcpp/ConnectionManager.h"
#include "dcpp/DownloadManager.h"
#include "dcpp/LogManager.h"
#include "dcpp/QueueManager.h"
#include "dcpp/TimerManager.h"
#include "dcpp/UploadManager.h"
#include "dcpp/FavoriteManager.h"
#include "dcpp/ShareManager.h"
#include "dcpp/SettingsManager.h"
#include "dcpp/Download.h"
#include "dcpp/Util.h"
#include "dcpp/version.h"

#include "ArenaWidget.h"
#include "HistoryInterface.h"
#include "LineEdit.h"
#include "ShortcutManager.h"

#include "ui_UIAbout.h"

class FavoriteHubs;
class DownloadQueue;
class ToolBar;
class MainWindow;
class MultiLineToolBar;
#ifdef USE_JS
class ScriptConsole;
#endif

class QProgressBar;

class About:
        public QDialog,
        public Ui::UIAbout
{
Q_OBJECT

public:
    About(QWidget *parent = nullptr): QDialog(parent){ setupUi(this); }

    void printHelp() const {
        QString msg =   tr("Usage:\n"
                        "  eiskaltdcpp-qt <magnet link> <dchub://link> <adc(s)://link>\n"
                        "  eiskaltdcpp-qt <Key>\n"
                        "EiskaltDC++ is a cross-platform program that uses the Direct Connect and ADC protocols.\n"
                        "\n"
                        "Keys:\n"
                        "  -h, --help\t Show this message\n"
                        "  -V, --version\t Show version string"
                        );

        printf("%s\n", msg.toUtf8().constData());
    }

    void printVersion() const {
        printf("%s\n", eiskaltdcppVersionString.c_str());
    }
};

class HashProgress;
class MainWindowPrivate;

class MainWindow:
        public QMainWindow,
        public  dcpp::Singleton<MainWindow>,
        private dcpp::LogManagerListener,
        private dcpp::TimerManagerListener,
        private dcpp::QueueManagerListener
{
    Q_OBJECT

friend class dcpp::Singleton<MainWindow>;

    public:

        typedef QList<QAction*> ActionList;

        Q_PROPERTY (QObject* ToolBar READ getToolBar);
        Q_PROPERTY (QMenuBar* MenuBar READ menuBar);

        void beginExit();

        /** */
        void newHubFrame(QString, QString);

        /** */
        void browseOwnFiles();

        /** */
        void startSocket(bool changed);
        /** */
        void showPortsError(const std::string& port);
        /** */
        void autoconnect();
        /** */
        void retranslateUi();

        /** */
        void reloadSomeSettings();

        /** */
        void setUnload(bool b);

        ArenaWidget *widgetForRole(ArenaWidget::Role) const;

    Q_SIGNALS:
        void redrawWidgetPanels();

    public Q_SLOTS:
         QObject *getToolBar();

        /** */
        void addActionOnToolBar(QAction*);
        /** */
        void remActionFromToolBar(QAction*);

        /** */
        void toggleMainMenu(bool);

        void slotChatClear();

        /** */
        void redrawToolPanel();

        /** */
        void setStatusMessage(QString);

        /** */
        void show();

        /** */
        void parseCmdLine(const QStringList &);
        /** */
        void parseInstanceLine(QString);

    protected:
        virtual void closeEvent(QCloseEvent*);
        virtual void showEvent(QShowEvent *);
        virtual void hideEvent(QHideEvent *);
        virtual bool eventFilter(QObject *, QEvent *);

    private Q_SLOTS:
        /** Show widget on arena */
        void mapWidgetOnArena(ArenaWidget*);
        void removeWidget(ArenaWidget *awgt);
        void insertWidget(ArenaWidget *awgt);
        void updated(ArenaWidget *awgt);

        void slotOpenMagnet();
        void slotFileOpenLogFile();
        void slotFileOpenDownloadDirectory();
        void slotFileBrowseFilelist();
        void slotFileHasher();
        void slotFileBrowseOwnFilelist();
        void slotFileMatchAllList();
        void slotFileHashProgress();
        void slotFileRefreshShareHashProgress();
        void slotHubsReconnect();
        void slotHubsFavoriteHubs();
        void slotHubsPublicHubs();
        void slotHubsFavoriteUsers();
        void slotToolsDownloadQueue();
        void slotToolsQueuedUsers();
        void slotToolsHubManager();
        void slotToolsFinishedDownloads();
        void slotToolsFinishedUploads();
        void slotToolsSpy();
        void slotToolsAntiSpam();
        void slotToolsIPFilter();
        void slotToolsSwitchAway();
        void slotToolsAutoAway();
        void slotToolsSearch();
        void slotToolsADLS();
        void slotToolsCmdDebug();
        void slotToolsSecretary();
        void slotToolsCopyWindowTitle();
        void slotToolsSettings();
        void slotToolsJS();
        void slotToolsJSConsole();
        void slotJSFileChanged(const QString&);
        void slotToolsTransfer(bool);
        void slotToolsSwitchSpeedLimit();
        void slotPanelMenuActionClicked();
        void slotWidgetsToggle();
        void slotQC();
        void slotHideMainMenu();
        void slotShowMainMenu();
        void slotHideWindow();
        void slotHideProgressSpace();
        void slotHideLastStatus();
        void slotHideUsersStatistics();
        void slotSideBarDockMenu();
        void slotExit();
        void slotToolbarCustomization();
        void slotToolbarCustomizerDone(const QList<QAction*> &enabled);

        void slotCloseCurrentWidget();

        void slotUnixSignal(int);

        void nextMsg();
        void prevMsg();

        void slotFind();
        void slotChatDisable();

        void slotAboutOpenUrl();
        void slotAboutClient();
        void slotAboutQt();

        void showShareBrowser(dcpp::UserPtr, const QString &, const QString&);
        void updateStatus(const QMap<QString,QString> &);

        void slotUpdateFavHubMenu();
        void slotConnectFavHub(QAction*);

        // These slots are used only in Mac OS X.
        // But due to bug in moc they cannot be placed in #ifdef block.
        void slotShowSpeedLimits();
        void slotSuppressTxt();
        void slotSuppressSnd();
        //

    Q_SIGNALS:
        void coreLogMessage(const QString&);
        void coreOpenShare(dcpp::UserPtr, const QString &, const QString&);
        void coreUpdateStats(const QMap<QString, QString> &);
        void notifyMessage(int, const QString&, const QString&);

    private:
        MainWindow (QWidget *parent=nullptr);
        virtual ~MainWindow();

        /** LogManagerListener */
        virtual void on(dcpp::LogManagerListener::Message, time_t t, const std::string&) noexcept;
        /** TimerManagerListener */
        virtual void on(dcpp::TimerManagerListener::Second, uint64_t) noexcept;
        /** QueueManagerListener */
        virtual void on(dcpp::QueueManagerListener::Finished, dcpp::QueueItem*, const std::string&, int64_t) noexcept;

        // Interface setup functions
        void init();
        void loadSettings();
        void saveSettings();
        void getWindowGeometry();

        void initActions();
        void initMenuBar();
        void initStatusBar();
        void initSearchBar();
        void initToolbar();
        void initSideBar();
        void initFavHubMenu();
#if defined(Q_OS_MAC)
        void initDockMenuBar();
#endif

        void toggleSingletonWidget(ArenaWidget *a);

        void updateHashProgressStatus();

        Q_DECLARE_PRIVATE(MainWindow)

        HashProgress *progress_dialog(); // Lazy initialization for _progress_dialog;

        MainWindowPrivate *d_ptr;
};

Q_DECLARE_METATYPE(MainWindow*)
