/**
 * 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 "AppSettingsDialogController.h"

#include <QHBoxLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QTreeWidget>

#include <U2Core/AppContext.h>
#include <U2Core/Settings.h>

#include <U2Gui/AppSettingsGUI.h>
#include <U2Gui/HelpButton.h>

#include "AppSettingsDialogTree.h"

namespace U2 {

AppSettingsDialogController::AppSettingsDialogController(const QString& pageId, QWidget* p)
    : QDialog(p) {
    setupUi(this);

    currentPage = nullptr;
    helpButton = new HelpButton(this, buttonBox, QString());
    buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
    buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));

    QHBoxLayout* pageLayout = new QHBoxLayout();
    settingsBox->setLayout(pageLayout);

    connect(tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(sl_currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));

    QList<AppSettingsGUIPageController*> pages = AppContext::getAppSettingsGUI()->getRegisteredPages();
    foreach (AppSettingsGUIPageController* page, pages) {
        registerPage(page);
    }

    if (tree->topLevelItemCount() > 0) {
        if (!pageId.isEmpty()) {
            AppSettingsTreeItem* item = findPageItem(pageId);
            if (item != nullptr) {
                tree->setCurrentItem(item);
            }
        }
        if (tree->currentItem() == nullptr) {
            tree->setCurrentItem(tree->topLevelItem(0));
        }
    }
}

bool AppSettingsDialogController::checkCurrentState(bool saveStateInItem, bool showError) {
    if (currentPage == nullptr) {
        return true;
    }
    QString err;
    currentPage->pageState = currentPage->pageWidget->getState(err);
    if (currentPage->pageState == nullptr) {
        if (showError) {
            if (err.isEmpty()) {
                err = tr("Error");
            }
            QMessageBox::critical(this, tr("Error"), err);
        }
        return false;
    }
    if (!saveStateInItem) {
        delete currentPage->pageState;
        currentPage->pageState = nullptr;
    } else {
        currentPage->pageState->setParent(this);
    }
    return true;
}

bool AppSettingsDialogController::turnPage(AppSettingsTreeItem* page) {
    assert(page == nullptr || page->pageWidget == nullptr);

    if (currentPage != nullptr) {
        assert(currentPage->pageWidget != nullptr);
        assert(currentPage->pageState == nullptr);
        if (!checkCurrentState(true, false)) {
            return false;
        }
        assert(currentPage->pageState != nullptr);
        settingsBox->setTitle("");
        delete currentPage->pageWidget;
        currentPage->pageWidget = nullptr;
        currentPage = nullptr;
    }
    if (page != nullptr) {
        assert(currentPage == nullptr);
        settingsBox->setTitle(page->pageController->getPageName());
        page->pageState = page->pageState == nullptr ? page->pageController->getSavedState() : page->pageState;
        page->pageState->setParent(this);
        page->pageWidget = page->pageController->createWidget(page->pageState);
        settingsBox->layout()->addWidget(page->pageWidget);
        delete page->pageState;
        page->pageState = nullptr;

        currentPage = page;
        helpButton->updatePageId(currentPage->pageController->getHelpPageId());
        connect(currentPage->pageWidget, SIGNAL(si_setLockState(bool)), SLOT(sl_setLockState(bool)));
    }
    return true;
}

void AppSettingsDialogController::registerPage(AppSettingsGUIPageController* page) {
    assert(findPageItem(page->getPageId()) == nullptr);
    tree->addTopLevelItem(new AppSettingsTreeItem(page));
}

AppSettingsTreeItem* AppSettingsDialogController::findPageItem(const QString& id) const {
    for (int i = 0, n = tree->topLevelItemCount(); i < n; i++) {
        auto item = static_cast<AppSettingsTreeItem*>(tree->topLevelItem(i));
        if (item->pageController->getPageId() == id) {
            return item;
        }
    }
    return nullptr;
}

void AppSettingsDialogController::accept() {
    if (!checkCurrentState(false, true)) {
        return;
    }

    turnPage(nullptr);  // make current state saved in item
    for (int i = 0, n = tree->topLevelItemCount(); i < n; i++) {
        auto item = static_cast<AppSettingsTreeItem*>(tree->topLevelItem(i));
        if (item->pageState != nullptr) {
            item->pageController->saveState(item->pageState);
        }
    }

    QDialog::accept();
}

void AppSettingsDialogController::reject() {
    QDialog::reject();
}

void AppSettingsDialogController::timerEvent(QTimerEvent* te) {
    killTimer(te->timerId());
    tree->setCurrentItem(currentPage);
}

void AppSettingsDialogController::sl_setLockState(bool lockState) {
    buttonBox->button(QDialogButtonBox::Ok)->setDisabled(lockState);
    tree->setDisabled(lockState);
}

void AppSettingsDialogController::sl_currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) {
    Q_UNUSED(previous);
    auto page = static_cast<AppSettingsTreeItem*>(current);
    if (page == currentPage) {
        return;
    }
    if (page == nullptr || !checkCurrentState(false, true)) {
        startTimer(0);
        return;
    }
    turnPage(page);
}

AppSettingsTreeItem::AppSettingsTreeItem(AppSettingsGUIPageController* p)
    : pageController(p), pageState(nullptr), pageWidget(nullptr) {
    setText(0, "  " + p->getPageName());
}

}  // namespace U2
