// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0

#pragma once

#include <coreplugin/coreconstants.h>
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/ioutputpane.h>

#include <utils/outputformat.h>
#include <utils/theme/theme.h>

#include <QPointer>

QT_BEGIN_NAMESPACE
class QToolButton;
class QAction;
class QPoint;
QT_END_NAMESPACE

namespace Core { class OutputWindow; }

namespace ProjectExplorer {

class RunControl;

namespace Internal {

class ShowOutputTaskHandler;
class TabWidget;

enum class AppOutputPaneMode { FlashOnOutput, PopupOnOutput, PopupOnFirstOutput };

class OutputColorAspect : public Utils::ColorAspect
{
public:
    using Utils::ColorAspect::ColorAspect;

    QVariant fromSettingsValue(const QVariant &savedValue) const override;
};

class OutputMaxCharCountAspect : public Utils::IntegerAspect
{
public:
    using Utils::IntegerAspect::IntegerAspect;

    QVariant fromSettingsValue(const QVariant &savedValue) const override;
    QVariant toSettingsValue(const QVariant &valueToSave) const override;
};

class AppOutputSettings : public Utils::AspectContainer
{
public:
    AppOutputSettings();

    QColor effectiveBackgroundColor() const;

    Utils::SelectionAspect runOutputMode{this};
    Utils::SelectionAspect debugOutputMode{this};
    Utils::BoolAspect cleanOldOutput{this};
    Utils::BoolAspect mergeChannels{this};
    Utils::BoolAspect wrapOutput{this};
    Utils::BoolAspect discardExcessiveOutput{this};
    OutputMaxCharCountAspect maxCharCount{this};
    Utils::BoolAspect overwriteBackground{this};
    OutputColorAspect backgroundColor{this};
};

class AppOutputPane final : public Core::IOutputPane
{
public:
    AppOutputPane();
    ~AppOutputPane() final;

    bool aboutToClose() const;

    QList<RunControl *> allRunControls() const;

    static AppOutputSettings &settings();

    void prepareRunControlStart(RunControl *runControl);
    void showOutputPaneForRunControl(RunControl *runControl);

    void closeTabsWithoutPrompt();

private:
    enum CloseTabMode {
        CloseTabNoPrompt,
        CloseTabWithPrompt
    };

    void closeTabs(CloseTabMode mode);
    void showTabFor(RunControl *rc);

    void setBehaviorOnOutput(RunControl *rc, AppOutputPaneMode mode);
    void projectRemoved();

    void createNewOutputWindow(RunControl *rc);
    void appendMessage(ProjectExplorer::RunControl *rc, const QString &out,
                       Utils::OutputFormat format);
    void reRunRunControl();
    void stopRunControl();
    void attachToRunControl();
    void tabChanged(int);
    void contextMenuRequested(const QPoint &pos);
    void runControlFinished(RunControl *runControl);

    void aboutToUnloadSession();
    void updateFromSettings();
    void enableDefaultButtons();

    void zoomIn(int range);
    void zoomOut(int range);
    void resetZoom();

    void enableButtons(const RunControl *rc);

    class RunControlTab {
    public:
        explicit RunControlTab(RunControl *runControl = nullptr,
                               Core::OutputWindow *window = nullptr);
        QPointer<RunControl> runControl;
        QPointer<Core::OutputWindow> window;
        AppOutputPaneMode behaviorOnOutput = AppOutputPaneMode::FlashOnOutput;
    };

    void closeTab(int index, CloseTabMode cm = CloseTabWithPrompt);
    bool optionallyPromptToStop(RunControl *runControl);

    RunControlTab *tabFor(const RunControl *rc);
    RunControlTab *tabFor(const QWidget *outputWindow);
    const RunControlTab *tabFor(const QWidget *outputWindow) const;
    RunControlTab *currentTab();
    const RunControlTab *currentTab() const;
    RunControl *currentRunControl() const;
    void handleOldOutput(Core::OutputWindow *window) const;
    void updateCloseActions();

    QWidget *outputWidget(QWidget *) final;
    QList<QWidget *> toolBarWidgets() const final;
    void clearContents() final;
    bool canFocus() const final;
    bool hasFocus() const final;
    void setFocus() final;

    bool canNext() const final;
    bool canPrevious() const final;
    void goToNext() final;
    void goToPrev() final;
    bool canNavigate() const final;

    bool hasFilterContext() const final;

    void updateFilter() final;
    const QList<Core::OutputWindow *> outputWindows() const final;
    void ensureWindowVisible(Core::OutputWindow *ow) final;

    TabWidget *m_tabWidget;
    QList<RunControlTab> m_runControlTabs;
    QAction *m_stopAction;
    QAction *m_closeCurrentTabAction;
    QAction *m_closeAllTabsAction;
    QAction *m_closeOtherTabsAction;
    QToolButton *m_reRunButton;
    QToolButton *m_stopButton;
    QToolButton *m_attachButton;
    QToolButton * const m_settingsButton;
    QWidget *m_formatterWidget;
    ShowOutputTaskHandler * const m_handler;
};

AppOutputPane &appOutputPane();

void setupAppOutputPane();
void destroyAppOutputPane();

} // namespace Internal
} // namespace ProjectExplorer
