/***************************** LICENSE START ***********************************

 Copyright 2019 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "CodeHelperWidget.h"

#include <QComboBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QStackedWidget>
#include <QToolButton>
#include <QVBoxLayout>

#include "Metview.h"

#include "ConfigLoader.h"
#include "LanguageHelper.h"
#include "MvQColourWidget.h"
#include "MvQMethods.h"
#include "MvQPanel.h"
#include "ColourHelpWidget.h"
#include "VerbFunctionHelpWidget.h"
#include "FunctionHelpWidget.h"

CodeHelperWidget::CodeHelperWidget(QWidget* parent) :
    QWidget(parent),
    built_(false),
    language_(nullptr),
    functionHelper_(nullptr),
    colourHelper_(nullptr),
    editorTheme_(nullptr)
{
    auto* vb = new QVBoxLayout(this);
    vb->setContentsMargins(0, 1, 1, 1);
    vb->setSpacing(1);

    auto* controlPanel = new MvQPanel(this);
    controlPanel->setObjectName("sidebarControlPanel");

    auto* hb = new QHBoxLayout();
    hb->setContentsMargins(2, 2, 0, 2);
    hb->setSpacing(2);
    controlPanel->setLayout(hb);
    vb->addWidget(controlPanel);

    auto* sidebarLabel = new QLabel(tr(" Help mode: "), controlPanel);
    sidebarLabel->setObjectName("sidebarLabel");
    sidebarLabel->setProperty("panelStyle", "2");
    hb->addWidget(sidebarLabel);

    modeCombo_ = new QComboBox(controlPanel);
    hb->addWidget(modeCombo_);
    hb->addStretch(1);

    auto* closeTb = new QToolButton(controlPanel);
    closeTb->setProperty("panelStyle", "2");
    closeTb->setAutoRaise(false);
    closeTb->setToolTip(tr("Close sidebar"));
    closeTb->setIcon(QPixmap(":/macroEditor/panel_close.svg"));
    hb->addWidget(closeTb);

    connect(closeTb, SIGNAL(clicked()),
            this, SLOT(slotCloseSideBar()));

    // stacked widget cotaining the actual helpers
    stackedW_ = new QStackedWidget(this);
    vb->addWidget(stackedW_);
}

void CodeHelperWidget::slotCloseSideBar()
{
    emit showRequested(false);
}

bool CodeHelperWidget::canSupportLanguage() const
{
    return (language_ && language_->hasVerbFunctionHelp());
}

void CodeHelperWidget::setLanguage(LanguageHelper* language)
{
    language_ = language;

    if (!built_ && isVisible()) {
        build();
        if (functionHelper_) {
            functionHelper_->setLanguage(language_);
        }
        return;
    }

    if (functionHelper_)
        functionHelper_->setLanguage(language_);
}

void CodeHelperWidget::setVisible(bool st)
{
    if (!built_ && st) {
        build();
        if (functionHelper_) {
            functionHelper_->setLanguage(language_);
        }
    }

    QWidget::setVisible(st);
}

void CodeHelperWidget::setCodeEditorTheme(EditorTheme* theme, QFont font)
{
    editorTheme_ = theme;
    editorFont_ = font;

    if (functionHelper_)
        functionHelper_->setCodeEditorTheme(theme, font);
}

void CodeHelperWidget::build()
{
    if (built_)
        return;

    built_ = true;

    if (!language_)
        return;

    // we create the sidebar if we need it and it not has
    // been created yet (we use the existence of functionHelper_ to check it!
    // This part should only be done once!!!
    if (language_->hasVerbFunctionHelp() && !functionHelper_) {
        // load the whole metview config. All the relevant classes will
        // load their config via ConfigLoader
        ConfigLoader::init();

        // verb help. Uses VerbFunctionHelp, which will initailised later
        auto* w = new QWidget(this);
        auto* sbVb = new QVBoxLayout(w);
        sbVb->setContentsMargins(0, 0, 0, 0);
        sbVb->setSpacing(1);
        functionHelper_ = new FunctionHelpWidget(this);
        sbVb->addWidget(functionHelper_);
        stackedW_->addWidget(w);
        modeCombo_->addItem("Built-in functions", "function");
        Q_ASSERT(FunctionHelpIndex == modeCombo_->count() - 1);

        // colour editor. Uses MvQPalette - initialised via ConfigLoader
        w = new QWidget(this);
        sbVb = new QVBoxLayout(w);
        sbVb->setContentsMargins(0, 0, 0, 0);
        sbVb->setSpacing(1);
        colourHelper_ = new ColourHelpWidget(this);
        sbVb->addWidget(colourHelper_);
        sbVb->addStretch(1);

        stackedW_->addWidget(w);
        modeCombo_->addItem("Colour editor", "colour");
        Q_ASSERT(ColourHelpIndex == modeCombo_->count() - 1);

        connect(functionHelper_, SIGNAL(insertRequested(QString)),
                this, SLOT(slotInsert(QString)));

        connect(colourHelper_, SIGNAL(insertRequested(QString)),
                this, SLOT(slotInsert(QString)));

        connect(modeCombo_, SIGNAL(currentIndexChanged(int)),
                stackedW_, SLOT(setCurrentIndex(int)));

        // init
        readSettings();

        if (editorTheme_)
            functionHelper_->setCodeEditorTheme(editorTheme_, editorFont_);
    }
}

void CodeHelperWidget::showFunctionList()
{
    if (!canSupportLanguage())
        return;

    if (!built_) {
        build();
        if (functionHelper_) {
            functionHelper_->setLanguage(language_);
        }
    }

    emit showRequested(true);

    if (functionHelper_) {
        functionHelper_->showFunctionList();
        modeCombo_->setCurrentIndex(FunctionHelpIndex);
    }
}


void CodeHelperWidget::adjustContents(QStringList lines, int cursorPosInLine)
{
    if (!canSupportLanguage())
        return;

    if (!built_) {
        build();
        if (functionHelper_) {
            functionHelper_->setLanguage(language_);
        }
    }

    Q_ASSERT(language_);
    Q_ASSERT(functionHelper_);

    QString functionName, paramName;
    language_->whatFunction(lines, cursorPosInLine, functionName, paramName);

    emit showRequested(true);

    if (!functionName.isEmpty()) {
        functionHelper_->adjustContents(functionName, paramName);
    }

    modeCombo_->setCurrentIndex(FunctionHelpIndex);
}

void CodeHelperWidget::adjustColourHelper(QString line, int cursorPositionInLine)
{
    if (!canSupportLanguage())
        return;

    if (!built_) {
        build();
        if (functionHelper_) {
            functionHelper_->setLanguage(language_);
        }
    }

    Q_ASSERT(language_);

    QString colName;
    language_->whatColour(line, cursorPositionInLine, colName);

    emit showRequested(true);

    if (!colName.isEmpty()) {
        colourHelper_->setColour(colName);
    }
    else {
        colourHelper_->setColour("BLUE");
    }

    modeCombo_->setCurrentIndex(ColourHelpIndex);
}

void CodeHelperWidget::slotInsert(QString txt)
{
    emit insertRequested(txt);
}

void CodeHelperWidget::readSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "mv-CodeHelperWidget");

    if (functionHelper_ && !settings.allKeys().isEmpty())
        functionHelper_->readSettings(settings);
}

void CodeHelperWidget::writeSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "mv-CodeHelperWidget");

    if (functionHelper_)
        functionHelper_->writeSettings(settings);
}
