//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//=========================================================================

#include "pqACE3PMenu.h"

#include "pqACE3PCloseBehavior.h"
#include "pqACE3PExportBehavior.h"
#include "pqACE3PNewProjectBehavior.h"
#include "pqACE3PNewStageBehavior.h"
#include "pqACE3POpenBehavior.h"
#include "pqACE3PProjectLoader.h"
#include "pqACE3PRecentProjectsMenu.h"
#include "pqACE3PRemoteParaViewBehavior.h"
#include "pqACE3PSaveBehavior.h"
#include "pqNerscFileBrowserBehavior.h"
#include "pqNerscLoginBehavior.h"

#include "smtk/newt/qtNewtInterface.h"
#include "smtk/simulation/ace3p/Project.h"
#include "smtk/simulation/ace3p/qt/qtProjectRuntime.h"

// ParaView includes
#include "pqApplicationCore.h"
#include "pqCoreUtilities.h"

// Qt includes
#include <QAction>
#include <QDebug>
#include <QList>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QString>

//-----------------------------------------------------------------------------
pqACE3PMenu::pqACE3PMenu(QObject* parent)
  : Superclass(parent)
{
  this->startup();
}

//-----------------------------------------------------------------------------
pqACE3PMenu::~pqACE3PMenu()
{
  this->shutdown();
}

//-----------------------------------------------------------------------------
bool pqACE3PMenu::startup()
{
  auto pqCore = pqApplicationCore::instance();
  if (!pqCore)
  {
    qWarning() << "cannot initialize ACE3P menu because pqCore is not found";
    return false;
  }

  // Access/create the singleton instances of our behaviors.
  auto openProjectBehavior = pqACE3POpenBehavior::instance(this);
  auto newProjectBehavior = pqACE3PNewProjectBehavior::instance(this);
  auto newStageBehavior = pqACE3PNewProjectBehavior::instance(this);
  auto saveProjectBehavior = pqACE3PSaveBehavior::instance(this);
  auto exportProjectBehavior = pqACE3PExportBehavior::instance(this);
  auto nerscLoginBehavior = pqNerscLoginBehavior::instance(this);
  auto closeProjectBehavior = pqACE3PCloseBehavior::instance(this);

  QObject::connect(
    newProjectBehavior,
    &pqACE3PNewProjectBehavior::projectCreated,
    this,
    &pqACE3PMenu::onProjectOpened);

  // Initialize Open Project action
  m_openProjectAction = new QAction(tr("Open Project..."), this);
  auto openProjectReaction = new pqACE3POpenReaction(m_openProjectAction);
  auto startIcon = QIcon(":/icons/toolbar/openProject.svg");
  m_openProjectAction->setIcon(startIcon);
  m_openProjectAction->setIconVisibleInMenu(true);

  // Initialize Recent Projects menu
  m_recentProjectsAction = new QAction(tr("Recent Projects"), this);
  QMenu* recentProjectsMenu = new QMenu();
  m_recentProjectsAction->setMenu(recentProjectsMenu);
  m_recentProjectsMenu = new pqACE3PRecentProjectsMenu(recentProjectsMenu, recentProjectsMenu);

  // Initialize New Project action
  m_newProjectAction = new QAction(tr("New Project..."), this);
  auto newProjectReaction = new pqACE3PNewProjectReaction(m_newProjectAction);
  auto newIcon = QIcon(":/icons/toolbar/newProject.svg");
  m_newProjectAction->setIcon(newIcon);
  m_newProjectAction->setIconVisibleInMenu(true);

  // Initialize New Stage action
  m_newStageAction = new QAction(tr("Add Stage..."), this);
  auto newStageReaction = new pqACE3PNewStageReaction(m_newStageAction);
  //auto newIcon = QIcon(":/icons/toolbar/newProject.svg");
  m_newStageAction->setIcon(newIcon);
  m_newStageAction->setIconVisibleInMenu(true);

  // Initialize Save Project action
  m_saveProjectAction = new QAction(tr("Save Project"), this);
  auto saveProjectReaction = new pqACE3PSaveReaction(m_saveProjectAction);
  auto saveIcon = QIcon(":/icons/toolbar/saveProject.svg");
  m_saveProjectAction->setIcon(saveIcon);
  m_saveProjectAction->setIconVisibleInMenu(true);

  // Initialize Export Project action
  m_exportProjectAction = new QAction(tr("Submit Analysis Job..."), this);
  auto exportProjectReaction = new pqACE3PExportReaction(m_exportProjectAction);
  auto exportIcon = QIcon(":/icons/toolbar/exportProject.svg");
  m_exportProjectAction->setIcon(exportIcon);
  m_exportProjectAction->setIconVisibleInMenu(true);

  // Initialize NERSC login action
  m_nerscLoginAction = new QAction(tr("Login to NERSC"), this);
  auto nerscLoginReaction = new pqNerscLoginReaction(m_nerscLoginAction);
  auto nerscIcon = QIcon(":/icons/toolbar/nersc.svg");
  m_nerscLoginAction->setIcon(nerscIcon);
  m_nerscLoginAction->setIconVisibleInMenu(true);

  // Initialize remote paraview menu
#if 0
  m_remoteParaViewAction = new QAction(tr("Start Remote ParaView Server"), this);
  QMenu* remoteParaViewMenu = new QMenu();
  m_remoteParaViewAction->setMenu(remoteParaViewMenu);
  m_remoteParaViewMenu = new pqACE3PRemoteParaViewMenu(remoteParaViewMenu, remoteParaViewMenu);
#else
  // Initialize behavior but leave out of menu
  m_remoteParaViewMenu = new pqACE3PRemoteParaViewMenu(nullptr, this);
#endif

  // Initialize Close Project action
  m_closeProjectAction = new QAction(tr("Close Project"), this);
  auto closeProjectReaction = new pqACE3PCloseReaction(m_closeProjectAction);
  auto closeIcon = QIcon(":/icons/toolbar/closeProject.svg");
  m_closeProjectAction->setIcon(closeIcon);
  m_closeProjectAction->setIconVisibleInMenu(true);
#if 0
  // File browser menu is for dev only
  auto nerscBrowserBehavior = pqNerscFileBrowserBehavior::instance(this);

  m_nerscBrowserAction = new QAction(tr("NERSC File Browser"), this);
  m_nerscBrowserAction->setEnabled(false);
  auto nerscBrowserReaction = new pqNerscFileBrowserReaction(m_nerscBrowserAction);

  // Enable rest of menu when on login signal
  auto newtInterface = newt::qtNewtInterface::instance();
  QObject::connect(newtInterface, &newt::qtNewtInterface::loginComplete,
    [this]() { m_nerscBrowserAction->setEnabled(true); });
#endif

  QObject::connect(
    closeProjectBehavior,
    &pqACE3PCloseBehavior::projectClosed,
    this,
    &pqACE3PMenu::onProjectClosed);

  // For now, presume that there is no project loaded at startup
  this->onProjectClosed();

  auto projectLoader = pqACE3PProjectLoader::instance();
  QObject::connect(
    projectLoader, &pqACE3PProjectLoader::projectOpened, this, &pqACE3PMenu::onProjectOpened);
  return true;
}

void pqACE3PMenu::shutdown() {}

//-----------------------------------------------------------------------------
void pqACE3PMenu::onProjectOpened(smtk::project::ProjectPtr project)
{
  m_newProjectAction->setEnabled(false);
  m_newStageAction->setEnabled(true);
  m_openProjectAction->setEnabled(false);
  m_recentProjectsAction->setEnabled(false);
  m_closeProjectAction->setEnabled(true);
  m_exportProjectAction->setEnabled(true);

  if (!m_saveMenuConfigured)
  {
    m_saveMenuConfigured = true; // only do this once
    m_saveProjectAction->setEnabled(false);

    // Get ACE3P menu and enable the save-project item based on project state
    QMainWindow* mainWindow = qobject_cast<QMainWindow*>(pqCoreUtilities::mainWidget());
    if (mainWindow == nullptr)
    {
      qWarning() << __FILE__ << __LINE__ << "Internal Error main window null.";
      return;
    }

    QList<QAction*> menuBarActions = mainWindow->menuBar()->actions();
    QMenu* menu = nullptr;
    foreach (QAction* existingMenuAction, menuBarActions)
    {
      QString menuName = existingMenuAction->text();
      menuName.remove('&');
      if (menuName == "ACE3P")
      {
        menu = existingMenuAction->menu();
        break;
      }
    }

    if (menu == nullptr)
    {
      qWarning() << __FILE__ << __LINE__ << "Internal Error ACE3P menu not found.";
      return;
    }

    // Update the project-save item each time the menu is activated
    QObject::connect(menu, &QMenu::aboutToShow, [this]() {
      const auto project = smtk::simulation::ace3p::qtProjectRuntime::instance()->project();
      bool modified = project && !project->clean();
      this->m_saveProjectAction->setEnabled(modified);
    });
  }
}

//-----------------------------------------------------------------------------
void pqACE3PMenu::onProjectClosed()
{
  m_newProjectAction->setEnabled(true);
  m_newStageAction->setEnabled(false);
  m_openProjectAction->setEnabled(true);
  m_recentProjectsAction->setEnabled(true);
  m_saveProjectAction->setEnabled(false);
  m_closeProjectAction->setEnabled(false);
  m_exportProjectAction->setEnabled(false);
}
