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

#include <QMainWindow>
#include <QMenu>
#include <QMessageBox>
#include <QToolBar>

#include <U2Core/GUrlUtils.h>
#include <U2Core/QObjectScopedPointer.h>
#include <U2Core/Settings.h>
#include <U2Core/U2OpStatusUtils.h>

#include <U2Gui/GUIUtils.h>
#include <U2Gui/MainWindow.h>

#include "ExportProjectDialogController.h"
#include "ProjectImpl.h"
#include "ProjectLoaderImpl.h"
#include "ProjectServiceImpl.h"
#include "ProjectTasksGui.h"

namespace U2 {

#define SETTINGS_DIR QString("project_loader/")

ProjectServiceImpl::ProjectServiceImpl(Project* _pr)
    : ProjectService(tr("Project"), tr("Project service is available when opened a project file. Other services that depends on Project service will be automatically started after this service is enabled.")) {
    saveAction = nullptr;
    saveAsAction = nullptr;
    closeProjectAction = nullptr;
    projectActionsSeparator = nullptr;
    exportProjectAction = nullptr;

    pr = _pr;
    assert(pr != nullptr);
}

ProjectServiceImpl::~ProjectServiceImpl() {
    delete pr;
}

Task* ProjectServiceImpl::saveProjectTask(SaveProjectTaskKind k) {
    return new SaveProjectTask(k);
}

Task* ProjectServiceImpl::closeProjectTask() {
    return new CloseProjectTask();
}

void ProjectServiceImpl::enableSaveAction(bool e) {
    if (saveAction) {
        saveAction->setEnabled(e);
    }
}

Task* ProjectServiceImpl::createServiceEnablingTask() {
    return new ProjectServiceEnableTask(this);
}

Task* ProjectServiceImpl::createServiceDisablingTask() {
    return new ProjectServiceDisableTask(this);
}

void ProjectServiceImpl::sl_closeProject() {
    AppContext::getTaskScheduler()->registerTopLevelTask(closeProjectTask());
}

void ProjectServiceImpl::sl_save() {
    AppContext::getTaskScheduler()->registerTopLevelTask(saveProjectTask(SaveProjectTaskKind_SaveProjectAndDocuments));
}

void ProjectServiceImpl::sl_saveAs() {
    auto p = qobject_cast<QWidget*>(AppContext::getMainWindow()->getQMainWindow());
    QObjectScopedPointer<ProjectDialogController> d = new ProjectDialogController(ProjectDialogController::Save_Project, p);
    const int rc = d->exec();
    CHECK(!d.isNull(), );

    if (rc == QDialog::Rejected) {
        return;
    }

    U2OpStatus2Log os;

    AppContext::getProject()->setProjectName(d->projectNameEdit->text());

    QString fileName = d->projectFilePathEdit->text();
    if (!fileName.endsWith(PROJECTFILE_EXT)) {
        fileName.append(PROJECTFILE_EXT);
    }
    AppContext::getProject()->setProjectURL(fileName);

    AppContext::getTaskScheduler()->registerTopLevelTask(saveProjectTask(SaveProjectTaskKind_SaveProjectAndDocuments));
}

void ProjectServiceImpl::sl_exportProject() {
    Project* p = getProject();
    QString pUrl = p->getProjectURL();
    QString projectFilePath = pUrl.isEmpty() ? GUrlUtils::getDefaultDataPath() + "/project" + PROJECTFILE_EXT : pUrl;
    QObjectScopedPointer<ExportProjectDialogController> dialog = new ExportProjectDialogController(AppContext::getMainWindow()->getQMainWindow(), projectFilePath);
    dialog->exec();
    CHECK(!dialog.isNull(), );

    if (dialog->result() == QDialog::Accepted) {
        Task* t = new ExportProjectTask(dialog->getDirToSave(), dialog->getProjectFile(), dialog->useCompression());
        AppContext::getTaskScheduler()->registerTopLevelTask(t);
    }
}

//////////////////////////////////////////////////////////////////////////
/// Service tasks

ProjectServiceEnableTask::ProjectServiceEnableTask(ProjectServiceImpl* _psi)
    : Task(tr("Enable Project"), TaskFlag_NoRun), psi(_psi) {
}

Task::ReportResult ProjectServiceEnableTask::report() {
    AppContextImpl::getApplicationContext()->setProjectService(psi);
    AppContextImpl::getApplicationContext()->setProject(psi->getProject());

    assert(psi->saveAction == nullptr && psi->closeProjectAction == nullptr);

    psi->saveAction = new QAction(QIcon(":ugene/images/project_save.png"), tr("&Save all"), psi);
    psi->saveAction->setObjectName("saveProjectAction");
    psi->saveAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
    psi->saveAction->setShortcutContext(Qt::WindowShortcut);
    connect(psi->saveAction, &QAction::triggered, psi, &ProjectServiceImpl::sl_save);

    psi->saveAsAction = new QAction(tr("Save project &as..."), psi);
    psi->saveAsAction->setObjectName("saveProjectAsAction");
    connect(psi->saveAsAction, &QAction::triggered, psi, &ProjectServiceImpl::sl_saveAs);

    psi->closeProjectAction = new QAction(tr("&Close project"), psi);
    psi->closeProjectAction->setObjectName("closeProjectAction");

    if (qgetenv("UGENE_GUI_TEST") == "1") {
        // Add an extra shortcut in GUI tests mode to speed up UGENE closing after the test.
        // It saves ~30 minutes for Linux tests. See 'post_action_0002'.
        psi->closeProjectAction->setShortcut(QKeySequence(Qt::CTRL | (isOsMac() ? Qt::Key_E : Qt::Key_Q)));
    }
    connect(psi->closeProjectAction, &QAction::triggered, psi, &ProjectServiceImpl::sl_closeProject);

    psi->exportProjectAction = new QAction(tr("Export project..."), psi);
    psi->exportProjectAction->setObjectName("exportProjectAction");
    connect(psi->exportProjectAction, &QAction::triggered, psi, &ProjectServiceImpl::sl_exportProject);

    psi->projectActionsSeparator = new QAction("", psi);
    psi->projectActionsSeparator->setSeparator(true);

    MainWindow* mw = AppContext::getMainWindow();
    QMenu* fileMenu = mw->getTopLevelMenu(MWMENU_FILE);
    QAction* beforeAction = GUIUtils::findActionAfter(fileMenu->actions(), ACTION_PROJECTSUPPORT__RECENT_PROJECTS_MENU);
    fileMenu->insertAction(beforeAction, psi->projectActionsSeparator);
    fileMenu->insertAction(beforeAction, psi->saveAction);
    fileMenu->insertAction(beforeAction, psi->saveAsAction);
    fileMenu->insertAction(beforeAction, psi->exportProjectAction);
    fileMenu->insertAction(beforeAction, psi->closeProjectAction);

    QToolBar* tb = mw->getToolbar(MWTOOLBAR_MAIN);
    beforeAction = GUIUtils::findActionAfter(tb->actions(), ACTION_PROJECTSUPPORT__OPEN_PROJECT);
    tb->insertAction(beforeAction, psi->saveAction);

    return ReportResult_Finished;
}

ProjectServiceDisableTask::ProjectServiceDisableTask(ProjectServiceImpl* _psi)
    : Task(tr("Disable Project"), TaskFlag_NoRun), psi(_psi) {
}

Task::ReportResult ProjectServiceDisableTask::report() {
    AppContextImpl::getApplicationContext()->setProject(nullptr);
    AppContextImpl::getApplicationContext()->setProjectService(nullptr);

    delete psi->saveAction;
    psi->saveAction = nullptr;

    delete psi->closeProjectAction;
    psi->closeProjectAction = nullptr;

    delete psi->projectActionsSeparator;
    psi->projectActionsSeparator = nullptr;

    return ReportResult_Finished;
}

}  // namespace U2
