/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#include "CMakeProjectManagerPresenter.h"

#include <Log.h>

#include <QStyle>
#include <QCloseEvent>

// syntax highlighter for the output text
#include "ExtensionGeneratorLogSyntaxHighlighter.h"

// -------------------- constructor --------------------
CMakeProjectManagerPresenter::CMakeProjectManagerPresenter(const QString& camitkFileBaseName, const QList<CMakeProjectManager::CMakeProjectManagerStage>& stages, QWidget* parent) : QWidget(parent) {
    cmakeProjectManager = new CMakeProjectManager(camitkFileBaseName);

    cmakeProjectManager->setStages(stages);

    QVBoxLayout* mainLayout = new QVBoxLayout(this);

    stageListWidget = new QListWidget(this);
    for (auto& stage : cmakeProjectManager->getStages()) {
        QListWidgetItem* item = new QListWidgetItem(stage);
        item->setData(Qt::UserRole, QVariant::fromValue(QString()));
        stageListWidget->addItem(item);
    }
    connect(stageListWidget, &QListWidget::itemClicked, this, &CMakeProjectManagerPresenter::stageClicked);
    connect(cmakeProjectManager, &CMakeProjectManager::stageStarted, this, &CMakeProjectManagerPresenter::stageStarted);
    connect(cmakeProjectManager, &CMakeProjectManager::stageFinished, this, &CMakeProjectManagerPresenter::stageFinished);
    connect(cmakeProjectManager, &CMakeProjectManager::allStagesFinished, this, [ this ](bool status) {
        emit allStagesFinished(status);
    });

    outputTextEdit = new QTextEdit(this);
    outputTextEdit->setReadOnly(true);
    new ExtensionGeneratorLogSyntaxHighlighter(outputTextEdit->document());

    mainLayout->addWidget(stageListWidget);
    mainLayout->addWidget(outputTextEdit);

    QHBoxLayout* buttonLayout = new QHBoxLayout;
    statusBarLabel = new QLabel("Ready", this);
    startCloseButton = new QPushButton("Start", this);
    connect(startCloseButton, &QPushButton::clicked, this, &CMakeProjectManagerPresenter::start);

    QSpacerItem* spacer = new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Fixed);
    buttonLayout->addWidget(statusBarLabel);
    buttonLayout->addItem(spacer);
    buttonLayout->addWidget(startCloseButton);
    mainLayout->addLayout(buttonLayout);

    setLayout(mainLayout);
    setAttribute(Qt::WA_DeleteOnClose); // to avoid memory leak
    setWindowIcon(QIcon(":/camiTKIcon"));
    setWindowTitle("CMake Projet Manager [" + camitkFileBaseName + "]");
    resize(500, 400);
}

// -------------------- destructor --------------------
CMakeProjectManagerPresenter::~CMakeProjectManagerPresenter() {
    delete cmakeProjectManager;
}

// -------------------- start --------------------
void CMakeProjectManagerPresenter::start() {
    cmakeProjectManager->start();
    startCloseButton->setText("Close");
    startCloseButton->setEnabled(true);
    connect(startCloseButton, &QPushButton::clicked, this, &CMakeProjectManagerPresenter::closeClicked);
}

// -------------------- closeClicked --------------------
void CMakeProjectManagerPresenter::closeClicked() {
    emit cMakeProjectManagerPresenterClosed();
    close();
    // this instance will be deleted because of the Qt::WA_DeleteOnClose attribute
}

// -------------------- closeEvent --------------------
void CMakeProjectManagerPresenter::closeEvent(QCloseEvent* event) {
    emit cMakeProjectManagerPresenterClosed();
    event->accept();
    // this instance will be deleted because of the Qt::WA_DeleteOnClose attribute
}

// -------------------- stageClicked --------------------
void CMakeProjectManagerPresenter::stageClicked(QListWidgetItem* item) {
    QString output = item->data(Qt::UserRole).toString();
    outputTextEdit->setPlainText(output);
}

// -------------------- stageStarted --------------------
void CMakeProjectManagerPresenter::stageStarted(const QString& stage) {
    QListWidgetItem* item = getListItem(stage);
    if (item != nullptr) {
        item->setIcon(this->style()->standardIcon(QStyle::SP_BrowserReload));
        item->setData(Qt::UserRole, QVariant::fromValue(QString("Running...")));
        stageListWidget->setCurrentItem(item);
        stageClicked(item);
    }

    statusBarLabel->setText(stage + "...");
}

// -------------------- stageFinished --------------------
void CMakeProjectManagerPresenter::stageFinished(const QString& stage, bool success, const QString& output) {
    QListWidgetItem* item = getListItem(stage);
    if (item != nullptr) {
        QIcon icon = this->style()->standardIcon(success ? QStyle::SP_DialogApplyButton : QStyle::SP_DialogCancelButton);
        item->setIcon(icon);
        item->setData(Qt::UserRole, QVariant::fromValue(output));
        stageClicked(item);
    }

    statusBarLabel->setText(stage + ((success) ? " finished." : " failed."));
}

// -------------------- getListItem --------------------
QListWidgetItem* CMakeProjectManagerPresenter::getListItem(QString stage) {
    int i = 0;
    while (i < stageListWidget->count() &&  stageListWidget->item(i)->text() != stage) {
        i++;
    }
    if (i < stageListWidget->count()) {
        return stageListWidget->item(i);
    }
    else {
        return nullptr;
    }
}