//=========================================================================
//  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 "pqWindTunnelMenu.h"

#include "pqWindTunnelCloseProjectBehavior.h"
#include "pqWindTunnelNewProjectBehavior.h"
#include "pqWindTunnelOpenProjectBehavior.h"
#include "pqWindTunnelProjectLoader.h"
#include "pqWindTunnelRecentProjectsMenu.h"
#include "pqWindTunnelSaveProjectBehavior.h"
#include "smtk/simulation/windtunnel/qt/qtSessionData.h"

#include "smtk/extension/paraview/server/vtkSMTKSettings.h"

// ParaView includes
#include "pqActiveObjects.h"
#include "pqApplicationCore.h"
#include "pqCoreUtilities.h"
#include "pqServer.h"
#include "pqServerManagerModel.h"
#include "vtkSMIntVectorProperty.h"
#include "vtkSMProperty.h"
#include "vtkSMProxy.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMStringVectorProperty.h"

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

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

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

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

  // Access/create the singleton instances of our behaviors.
  auto openProjectBehavior = pqWindTunnelOpenProjectBehavior::instance(this);
  auto newProjectBehavior = pqWindTunnelNewProjectBehavior::instance(this);
  auto saveProjectBehavior = pqWindTunnelSaveProjectBehavior::instance(this);
  auto closeProjectBehavior = pqWindTunnelCloseProjectBehavior::instance(this);

  QObject::connect(
    newProjectBehavior,
    &pqWindTunnelNewProjectBehavior::projectCreated,
    this,
    &pqWindTunnelMenu::onProjectOpened);

  // Initialize Open Project action
  m_openProjectAction = new QAction(tr("Open Project..."), this);
  auto openProjectReaction = new pqWindTunnelOpenProjectReaction(m_openProjectAction);
  auto startIcon = QIcon(":/icons/project/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 pqWindTunnelRecentProjectsMenu(recentProjectsMenu, recentProjectsMenu);
  auto recentIcon = QIcon(":/icons/project/recentFiles.svg");
  m_recentProjectsAction->setIcon(recentIcon);
  m_recentProjectsAction->setIconVisibleInMenu(true);

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

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

  // Initialize Close Project action
  m_closeProjectAction = new QAction(tr("Close Project"), this);
  auto closeProjectReaction = new pqWindTunnelCloseProjectReaction(m_closeProjectAction);
  auto closeIcon = QIcon(":/icons/project/closeProject.svg");
  m_closeProjectAction->setIcon(closeIcon);
  m_closeProjectAction->setIconVisibleInMenu(true);

  QObject::connect(
    closeProjectBehavior,
    &pqWindTunnelCloseProjectBehavior::projectClosed,
    this,
    &pqWindTunnelMenu::onProjectClosed);

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

  auto projectLoader = pqWindTunnelProjectLoader::instance();
  QObject::connect(
    projectLoader,
    &pqWindTunnelProjectLoader::projectOpened,
    this,
    &pqWindTunnelMenu::onProjectOpened);

  return true;
}

void pqWindTunnelMenu::shutdown() {}

//-----------------------------------------------------------------------------
void pqWindTunnelMenu::onProjectOpened(smtk::project::ProjectPtr project)
{
  m_openProjectAction->setEnabled(false);
  m_recentProjectsAction->setEnabled(false);
  m_newProjectAction->setEnabled(false);
  // Note: m_saveProjectAction is set according to project's modified state
  m_closeProjectAction->setEnabled(true);

  if (m_saveMenuConfigured)
  {
    return;
  }

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

  // Get WindTunnel 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;
  Q_FOREACH (QAction* existingMenuAction, menuBarActions)
  {
    QString menuName = existingMenuAction->text();
    menuName.remove('&');
    if (menuName == "WindTunnel")
    {
      menu = existingMenuAction->menu();
      break;
    }
  }

  if (menu == nullptr)
  {
    qWarning() << __FILE__ << __LINE__ << "Internal Error WindTunnel 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::windtunnel::qtSessionData::instance()->project();
    bool modified = project && !project->clean();
    this->m_saveProjectAction->setEnabled(modified);
  });

  // Disable smtk's save-on-close dialog
  // This code is redundant with pqWindTunnelAutoStart because something else is overwriting
  // the setting in production builds. Until that is figured out, use this as a workaround.
  pqServer* server = pqActiveObjects::instance().activeServer();
  vtkSMProxy* proxy = server->proxyManager()->GetProxy("settings", "SMTKSettings");
  if (proxy)
  {
    vtkSMProperty* ssProp = proxy->GetProperty("ShowSaveResourceOnClose");
    vtkSMIntVectorProperty* ssIntProp = vtkSMIntVectorProperty::SafeDownCast(ssProp);
    if (ssIntProp != nullptr)
    {
      ssIntProp->SetElement(0, vtkSMTKSettings::DontShowAndDiscard);
    }
    proxy->UpdateVTKObjects();
  } // if (proxy)
}

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