/*
    SuperCollider Qt IDE
    Copyright (c) 2012 Jakob Leben & Tim Blechmann
    http://www.audiosynth.com

    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 2 of the License, or
    (at your option) any later version.

    This program 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, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

#pragma once

#include "util/docklet.hpp"
#include "QtCollider/widgets/web_page.hpp"
#include "QtCollider/widgets/QcWebView.h"

#include <QWebEngineView>
#include <QLabel>
#include <QLineEdit>
#include <QBasicTimer>
#include <QTimerEvent>
#include <QList>
#include <QKeySequence>

namespace ScIDE {

namespace Settings {
class Manager;
}

class HelpBrowserDocklet;
class HelpBrowserFindBox;
class HelpBrowser;

class LoadProgressIndicator : public QLabel {
    Q_OBJECT
public slots:
    void start(const QString& msg = tr("Loading")) {
        mMsg = msg;
        mDotCount = 0;
        mUpdateTimer.start(200, this);
    }
    void stop() {
        mUpdateTimer.stop();
        clear();
    }

protected:
    virtual void timerEvent(QTimerEvent* event) {
        if (event->timerId() != mUpdateTimer.timerId())
            return;

        ++mDotCount;
        if (mDotCount > 6)
            mDotCount = 1;

        QString string(mDotCount, '.');
        string.prepend(mMsg);

        setText(string);
    }

private:
    QBasicTimer mUpdateTimer;
    QString mMsg;
    int mDotCount;
};


class HelpBrowser : public QWidget {
    Q_OBJECT

public:
    enum ActionRole {
        GoHome,
        DocClose,
        ZoomIn,
        ZoomOut,
        ResetZoom,
        Evaluate,
        EvaluateRegion,

        ActionCount
    };

    HelpBrowser(QWidget* parent = 0);

    QSize sizeHint() const { return mSizeHint; }
    QSize minimumSizeHint() const { return QSize(50, 50); }

    void gotoHelpFor(const QString&);
    void gotoHelpForMethod(const QString& className, const QString& methodName);
    QWidget* loadProgressIndicator() { return mLoadProgressIndicator; }

    QUrl url() const { return mWebView->url(); }

    bool helpBrowserHasFocus() const;

    void setServerPort(int serverPort) { mServerPort = serverPort; };

public slots:
    void applySettings(Settings::Manager*);
    void goHome();
    void closeDocument();
    void zoomIn();
    void zoomOut();
    void resetZoom();
    void evaluateSelection(bool region = false);
    void findText(const QString& text, bool backwards = false);
    bool openDocumentation();
    void openDefinition();
    void openCommandLine();
    void findReferences();
    void onLinkClicked(const QUrl&, QWebEnginePage::NavigationType type, bool isMainFrame);
    void onPageLoad();

signals:
    void urlChanged();

private slots:
    void onContextMenuRequest(const QPoint& pos);
    void onReload();
    void onScResponse(const QString& command, const QString& data);
    void onJsConsoleMsg(const QString&, int, const QString&);

private:
    friend class HelpBrowserDocklet;

    void createActions();
    bool eventFilter(QObject* object, QEvent* event);
    void sendRequest(const QString& code);
    QString symbolUnderCursor();

    QtCollider::WebView* mWebView;
    LoadProgressIndicator* mLoadProgressIndicator;

    QSize mSizeHint;

    QAction* mActions[ActionCount];

    int mServerPort = 0; // if 0, server is not running
};

class HelpBrowserFindBox : public QLineEdit {
    Q_OBJECT

public:
    HelpBrowserFindBox(QWidget* parent = 0);

signals:
    void query(const QString& text, bool backwards = false);

protected:
    virtual bool event(QEvent* event);
};

class HelpBrowserDocklet : public Docklet {
    Q_OBJECT

public:
    explicit HelpBrowserDocklet(QWidget* parent = 0);
    HelpBrowser* browser() { return mHelpBrowser; }

private slots:
    void onInterpreterStart() {
        if (isVisible() && mHelpBrowser->url().isEmpty())
            mHelpBrowser->goHome();
    }

private:
    HelpBrowser* mHelpBrowser;
    HelpBrowserFindBox* mFindBox;
};

} // namespace ScIDE
