/**
 * UGENE - Integrated Bioinformatics Tools.
 * Copyright (C) 2008-2024 UniPro <ugene@unipro.ru>
 * http://ugene.net
 *
 * 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.
 */

#include "QueryEditor.h"

#include <QRegExpValidator>

#include <U2Lang/Attribute.h>
#include <U2Lang/WorkflowUtils.h>

#include "QDDocument.h"
#include "QueryProcCfgDelegate.h"
#include "QueryProcCfgModel.h"
#include "QueryViewController.h"
#include "QueryViewItems.h"

namespace U2 {

QueryEditor::QueryEditor(QWidget* parent /* =0 */)
    : QWidget(parent), current(nullptr) {
    setupUi(this);
    caption->setMinimumHeight(nameEdit->sizeHint().height());

    // QueryViewController* controller = qobject_cast<QueryViewController*>(parent);
    nameEdit->setValidator(new QRegExpValidator(QRegExp(QDDocument::ID_PATTERN), nameEdit));
    directionCombo->insertItem(0, tr("Forward"));
    directionCombo->insertItem(1, tr("Backward"));
    directionCombo->insertItem(2, tr("Any"));

    cfgModel = new QueryProcCfgModel(this);
    table->setModel(cfgModel);
    table->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
    table->horizontalHeader()->setStretchLastSection(true);
    table->verticalHeader()->hide();
    table->verticalHeader()->setDefaultSectionSize(QFontMetrics(QFont()).height() + 6);
    table->setItemDelegate(new QueryProcCfgDelegate(this));
    table->setMinimumHeight(height() / 2);

    reset();

    connect(table->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), SLOT(sl_showPropDoc()));
    connect(nameEdit, SIGNAL(editingFinished()), SLOT(sl_setLabel()));
    connect(keyEdit, SIGNAL(editingFinished()), SLOT(sl_setKey()));
    connect(directionCombo, SIGNAL(currentIndexChanged(int)), SLOT(sl_setDirection(int)));
    connect(cfgModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SIGNAL(modified()));
}

void QueryEditor::setCurrentAttribute(const QString& id) {
    QModelIndex modelIndex = cfgModel->modelIndexById(id);

    QModelIndex prev = table->selectionModel()->currentIndex();

    if (modelIndex == prev) {
        table->selectionModel()->reset();
    }
    table->setCurrentIndex(modelIndex);
    // table->selectionModel()->setCurrentIndex(modelIndex, QItemSelectionModel::ClearAndSelect);
}

void QueryEditor::sl_setLabel() {
    if (current->getParameters()->getLabel() != nameEdit->text()) {
        current->getParameters()->setLabel(nameEdit->text());
        emit modified();
    }
}

void QueryEditor::sl_setKey() {
    if (current->getParameters()->getAnnotationKey() != keyEdit->text()) {
        current->getParameters()->setAnnotationKey(keyEdit->text());
        emit modified();
    }
}

void QueryEditor::sl_setDirection(int index) {
    QDStrandOption dir = QDStrandOption(index);
    if (current->getStrand() != dir) {
        current->setStrand(dir);
        emit modified();
    }
}

void QueryEditor::sl_showPropDoc() {
    QModelIndex current = table->selectionModel()->currentIndex();
    if (current.isValid()) {
        propDoc->setText(WorkflowUtils::getRichDoc(current.data(DescriptorRole).value<Descriptor>()));
    } else {
        propDoc->setText("");
    }
}

void QueryEditor::setDescriptor(const Descriptor* d, const QString& hint) {
    QString text = d ? WorkflowUtils::getRichDoc(*d) + "<br><br>" + hint : hint;
    if (text.isEmpty()) {
        text = tr("Select an element to inspect.");
    }
    doc->setText(text);
}

void QueryEditor::showProto(QDActorPrototype* proto) {
    if (proto) {
        caption->setText(tr("Element Name"));
        caption->show();
        annotationLbl->setText(tr("Annotate As"));
        annotationLbl->show();
        directionLbl->setText(tr("Direction"));
        directionLbl->show();
        // nameEdit->setText(a->getParameters()->getLabel());
        nameEdit->show();
        nameEdit->setDisabled(true);
        // keyEdit->setText(a->getParameters()->getAnnotationKey());
        keyEdit->show();
        keyEdit->setDisabled(true);
        directionCombo->show();
        directionCombo->setDisabled(true);

        setDescriptor(&proto->getDescriptor(),
                      tr("To configure the algorithm element parameters go to the \"Parameters\" area below."));
        cfgModel->setConfiguration(proto->getEditor(), proto->getParameters());
        tableSplitter->show();
        tableSplitter->setDisabled(true);
    } else {
        reset();
    }
}

void QueryEditor::edit(QDConstraint* constraint) {
    if (constraint) {
        caption->setText("");
        caption->hide();
        annotationLbl->setText("");
        annotationLbl->hide();
        directionLbl->setText(tr(""));
        directionLbl->hide();
        nameEdit->setText("");
        nameEdit->hide();
        keyEdit->setText("");
        keyEdit->hide();
        directionCombo->hide();
        doc->setText(tr("To configure the constraint element parameters go to the \"Parameters\" area below."));
        cfgModel->setConfiguration(constraint->getParameters());
        tableSplitter->show();
        tableSplitter->setDisabled(false);
    } else {
        reset();
    }
}

void QueryEditor::edit(QDActor* a) {
    current = a;
    if (a) {
        caption->setText(tr("Element Name"));
        caption->show();
        annotationLbl->setText(tr("Annotate As"));
        annotationLbl->show();
        directionLbl->setText(tr("Direction"));
        directionLbl->show();
        nameEdit->setText(a->getParameters()->getLabel());
        nameEdit->show();
        nameEdit->setDisabled(false);
        keyEdit->setText(a->getParameters()->getAnnotationKey());
        keyEdit->show();
        keyEdit->setDisabled(false);
        directionCombo->setCurrentIndex(a->getStrand());
        directionCombo->show();
        if (a->hasStrand()) {
            directionCombo->setDisabled(false);
        } else {
            directionCombo->setDisabled(true);
        }

        setDescriptor(&a->getProto()->getDescriptor(),
                      tr("To configure the algorithm element parameters go to the \"Parameters\" area below."));
        cfgModel->setConfiguration(a->getParameters());
        a->updateEditor();
        tableSplitter->show();
        tableSplitter->setDisabled(false);
    } else {
        reset();
    }
}

void QueryEditor::reset() {
    caption->setText("");
    caption->hide();
    annotationLbl->setText("");
    annotationLbl->hide();
    directionLbl->setText(tr(""));
    directionLbl->hide();
    nameEdit->setText("");
    nameEdit->hide();
    keyEdit->setText("");
    keyEdit->hide();
    directionCombo->hide();
    setDescriptor(nullptr);
    cfgModel->setConfiguration(nullptr);
    tableSplitter->hide();
    propDoc->setText("");
}

}  // namespace U2
