/*
 * Copyright 2009- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation
 * nor does it submit to any jurisdiction.
 */

#include "RepeatEditor.hpp"

#include <QIntValidator>
#include <QItemSelectionModel>
#include <QSettings>
#include <QStringListModel>
#include <QtGlobal>

#include "AttributeEditorFactory.hpp"
#include "CommandHandler.hpp"
#include "SessionHandler.hpp"
#include "UiLog.hpp"
#include "VAttribute.hpp"
#include "VAttributeType.hpp"
#include "VInfo.hpp"
#include "VNode.hpp"
#include "VRepeatAttr.hpp"
#include "ecflow/node/Node.hpp"

RepeatEditorWidget::RepeatEditorWidget(QWidget* parent) : QWidget(parent) {
    setupUi(this);
}

void RepeatEditorWidget::hideRow(QWidget* w) {
    w->hide();
    QWidget* item = formLayout_->labelForField(w);
    Q_ASSERT(item);
    item->hide();
}

//================================================================
//
// RepeatEditor
//
//================================================================

RepeatEditor::RepeatEditor(VInfo_ptr info, QWidget* parent) : AttributeEditor(info, "repeat", parent), model_(nullptr) {
    w_ = new RepeatEditorWidget(this);
    addForm(w_);

    VAttribute* a = info_->attribute();

    Q_ASSERT(a);
    Q_ASSERT(a->type());
    Q_ASSERT(a->type()->name() == "repeat");

    auto* rep = static_cast<VRepeatAttr*>(a);

#if 0
    if(a->data().count() < 7)
        return;

    VNode *vnode=info_->node();
    Q_ASSERT(vnode);
    node_ptr node=vnode->node();
    Q_ASSERT(node);
    const Repeat& r=node->repeat();
    repeat_=VRepeat::make(r);
#endif

    oriVal_ = a->data().at(3);

    w_->nameLabel_->setText(a->data().at(2));
    // w_->valueLe_->setText(a->data().at(3));
    w_->startLabel_->setText(a->data().at(4));
    w_->endLabel_->setText(a->data().at(5));
    w_->stepLabel_->setText(a->data().at(6));

    // Value will be initailised in the subclasses
    oriVal_ = a->data().at(3);

    buildList(rep);

#if 0
    QIntValidator *validator=new QIntValidator(this);
    if(!a->data().at(3).isEmpty() && !a->data().at(4).isEmpty())
    {
        validator->setRange(a->data().at(3).toInt(),
                            a->data().at(4).toInt());
    }
    valueLe_->setValidator(validator);
#endif

    header_->setInfo(QString::fromStdString(info_->nodePath()), "Repeat " + QString::fromStdString(rep->subType()));

    readSettings();
}

RepeatEditor::~RepeatEditor() {
    writeSettings();
}

void RepeatEditor::buildList(VRepeatAttr* rep) {
    int start   = rep->startIndex();
    int end     = rep->endIndex();
    int step    = rep->step();
    int current = rep->currentIndex();

    if (step <= 0 || end <= start) {
        return;
    }

    modelData_.clear();
    int cnt = end - start;
    if (cnt > 1) {
        for (int i = start; i <= end; i++) {
            modelData_ << QString::fromStdString(rep->value(i));
        }

        model_ = new QStringListModel(this);
        model_->setStringList(modelData_);
        w_->valueView_->setModel(model_);
        w_->valueView_->setCurrentIndex(model_->index(current, 0));

        connect(w_->valueView_->selectionModel(),
                SIGNAL(currentChanged(QModelIndex, QModelIndex)),
                this,
                SLOT(slotSelectedInView(QModelIndex, QModelIndex)));

        w_->valueView_->setFocus(Qt::MouseFocusReason);
    }
    else {
        w_->valueView_->hide();
    }
}

void RepeatEditor::slotSelectedInView(const QModelIndex& current, const QModelIndex& /*previous*/) {
    setValue(current.data().toString());
    checkButtonStatus();
}

bool RepeatEditor::isListMode() const {
    return (model_) ? true : false;
}

void RepeatEditor::writeSettings() {
    SessionItem* cs = SessionHandler::instance()->current();
    Q_ASSERT(cs);
    QSettings settings(QString::fromStdString(cs->qtSettingsFile("RepeatEditor")), QSettings::NativeFormat);

    // We have to clear it so that should not remember all the previous values
    settings.clear();

    settings.beginGroup("main");
    settings.setValue("size", size());
    settings.endGroup();
}

void RepeatEditor::readSettings() {
    SessionItem* cs = SessionHandler::instance()->current();
    Q_ASSERT(cs);
    QSettings settings(QString::fromStdString(cs->qtSettingsFile("RepeatEditor")), QSettings::NativeFormat);

    settings.beginGroup("main");
    if (settings.contains("size")) {
        resize(settings.value("size").toSize());
    }
    else {
        resize(QSize(310, 340));
    }

    settings.endGroup();
}

//================================================================
//
// RepeatIntEditor
//
//================================================================

RepeatIntEditor::RepeatIntEditor(VInfo_ptr info, QWidget* parent) : RepeatEditor(info, parent) {
    // if(!repeat_)
    //     return;

    w_->hideRow(w_->valueLe_);

    initSpinner();

    connect(w_->valueSpin_, SIGNAL(valueChanged(int)), this, SLOT(slotValueChanged(int)));

    checkButtonStatus();
}

void RepeatIntEditor::initSpinner() {
    w_->valueSpin_->setValue(oriVal_.toInt());

    VAttribute* a = info_->attribute();

    Q_ASSERT(a);
    Q_ASSERT(a->type());
    Q_ASSERT(a->type()->name() == "repeat");

    auto* rep = static_cast<VRepeatAttr*>(a);

    int startIndex = rep->startIndex();
    int endIndex   = rep->endIndex();
    int step       = rep->step();

    if (step <= 0 || endIndex <= startIndex) {
        return;
    }

    int minVal = QString::fromStdString(rep->value(startIndex)).toInt();
    int maxVal = QString::fromStdString(rep->value(endIndex)).toInt();

#if 0
    UiLog().dbg() << "min=" << minVal << " max=" << maxVal << " step=" << step;
#endif
    w_->valueSpin_->setMinimum(minVal);
    w_->valueSpin_->setMaximum(maxVal);
    w_->valueSpin_->setSingleStep(step);
}

void RepeatIntEditor::setValue(QString val) {
    w_->valueSpin_->setValue(val.toInt());
}

void RepeatIntEditor::slotValueChanged(int val) {
    if (isListMode()) {
        QString txt = QString::number(val);
        int row     = modelData_.indexOf(txt);
        if (row != -1) {
            w_->valueView_->setCurrentIndex(model_->index(row, 0));
        }
        else {
            w_->valueView_->clearSelection();
            w_->valueView_->setCurrentIndex(QModelIndex());
        }
    }
    checkButtonStatus();
}

void RepeatIntEditor::resetValue() {
    w_->valueSpin_->setValue(oriVal_.toInt());
    slotValueChanged(oriVal_.toInt());
    checkButtonStatus();
}

bool RepeatIntEditor::isValueChanged() {
    return (oriVal_.toInt() != w_->valueSpin_->value());
}

void RepeatIntEditor::apply() {
    std::string val = QString::number(w_->valueSpin_->value()).toStdString();
    // std::string name=w_->nameLabel_->text().toStdString();

    std::vector<std::string> cmd;
    VAttribute::buildAlterCommand(cmd, "change", "repeat", val);
    CommandHandler::run(info_, cmd);
}

//================================================================
//
// RepeatStringEditor
//
//================================================================

RepeatStringEditor::RepeatStringEditor(VInfo_ptr info, QWidget* parent) : RepeatEditor(info, parent) {
    // if(!repeat_)
    //     return;

    w_->hideRow(w_->valueSpin_);
    w_->hideRow(w_->stepLabel_);
    w_->valueLe_->setText(oriVal_);

    connect(w_->valueLe_, SIGNAL(textEdited(QString)), this, SLOT(slotValueEdited(QString)));

    checkButtonStatus();
}

void RepeatStringEditor::setValue(QString val) {
    w_->valueLe_->setText(val);
}

void RepeatStringEditor::slotValueEdited(QString txt) {
    if (isListMode()) {
        int row = modelData_.indexOf(txt);
        if (row != -1) {
            w_->valueView_->setCurrentIndex(model_->index(row, 0));
        }
        else {
            w_->valueView_->clearSelection();
            w_->valueView_->setCurrentIndex(QModelIndex());
        }
    }
    checkButtonStatus();
}

void RepeatStringEditor::resetValue() {
    w_->valueLe_->setText(oriVal_);
    slotValueEdited(oriVal_);
    checkButtonStatus();
}

bool RepeatStringEditor::isValueChanged() {
    return (oriVal_ != w_->valueLe_->text());
}

void RepeatStringEditor::apply() {
    std::string val = w_->valueLe_->text().toStdString();
    // std::string name=w_->nameLabel_->text().toStdString();

    std::vector<std::string> cmd;
    VAttribute::buildAlterCommand(cmd, "change", "repeat", val);
    CommandHandler::run(info_, cmd);
}

//================================================================
//
// RepeatDateEditor
//
//================================================================

RepeatDateEditor::RepeatDateEditor(VInfo_ptr info, QWidget* parent) : RepeatEditor(info, parent) {
    // if(!repeat_)
    //     return;

    w_->hideRow(w_->valueSpin_);
    w_->valueLe_->setText(oriVal_);

    connect(w_->valueLe_, SIGNAL(textEdited(QString)), this, SLOT(slotValueEdited(QString)));

    checkButtonStatus();
}

void RepeatDateEditor::setValue(QString val) {
    w_->valueLe_->setText(val);
}

void RepeatDateEditor::slotValueEdited(QString txt) {
    if (isListMode()) {
        int row = modelData_.indexOf(txt);
        if (row != -1) {
            w_->valueView_->setCurrentIndex(model_->index(row, 0));
        }
        else {
            w_->valueView_->clearSelection();
            w_->valueView_->setCurrentIndex(QModelIndex());
        }
    }
    checkButtonStatus();
}

void RepeatDateEditor::resetValue() {
    w_->valueLe_->setText(oriVal_);
    slotValueEdited(oriVal_);
    checkButtonStatus();
}

bool RepeatDateEditor::isValueChanged() {
    return (oriVal_ != w_->valueLe_->text());
}

void RepeatDateEditor::apply() {
    std::string val = w_->valueLe_->text().toStdString();
    // std::string name=w_->nameLabel_->text().toStdString();

    std::vector<std::string> cmd;
    VAttribute::buildAlterCommand(cmd, "change", "repeat", val);
    CommandHandler::run(info_, cmd);
}

//================================================================
//
// RepeatDateTimeEditor
//
//================================================================

RepeatDateTimeEditor::RepeatDateTimeEditor(VInfo_ptr info, QWidget* parent) : RepeatEditor(info, parent) {
    // if(!repeat_)
    //     return;

    w_->hideRow(w_->valueSpin_);
    w_->valueLe_->setText(oriVal_);

    connect(w_->valueLe_, SIGNAL(textEdited(QString)), this, SLOT(slotValueEdited(QString)));

    checkButtonStatus();
}

void RepeatDateTimeEditor::setValue(QString val) {
    w_->valueLe_->setText(val);
}

void RepeatDateTimeEditor::slotValueEdited(QString txt) {
    if (isListMode()) {
        int row = modelData_.indexOf(txt);
        if (row != -1) {
            w_->valueView_->setCurrentIndex(model_->index(row, 0));
        }
        else {
            w_->valueView_->clearSelection();
            w_->valueView_->setCurrentIndex(QModelIndex());
        }
    }
    checkButtonStatus();
}

void RepeatDateTimeEditor::resetValue() {
    w_->valueLe_->setText(oriVal_);
    slotValueEdited(oriVal_);
    checkButtonStatus();
}

bool RepeatDateTimeEditor::isValueChanged() {
    return (oriVal_ != w_->valueLe_->text());
}

void RepeatDateTimeEditor::apply() {
    std::string val = w_->valueLe_->text().toStdString();
    // std::string name=w_->nameLabel_->text().toStdString();

    std::vector<std::string> cmd;
    VAttribute::buildAlterCommand(cmd, "change", "repeat", val);
    CommandHandler::run(info_, cmd);
}

static AttributeEditorMaker<RepeatIntEditor> makerStr1("repeat_integer");
static AttributeEditorMaker<RepeatStringEditor> makerStr2("repeat_string");
static AttributeEditorMaker<RepeatStringEditor> makerStr3("repeat_enumerated");
static AttributeEditorMaker<RepeatDateEditor> makerStr4("repeat_date");
static AttributeEditorMaker<RepeatStringEditor> makerStr5("repeat_datelist");
static AttributeEditorMaker<RepeatDateTimeEditor> makerStr6("repeat_datetime");
