//=========================================================================
//  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 "plugin/pqACE3PNewStageBehavior.h"
#include "plugin/pqACE3PStagesBehavior.h"

#include "smtk/simulation/ace3p/Project.h"
#include "smtk/simulation/ace3p/operations/NewStage.h"
#include "smtk/simulation/ace3p/qt/qtProjectRuntime.h"

// SMTK
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/extension/paraview/appcomponents/pqSMTKBehavior.h"
#include "smtk/extension/paraview/appcomponents/pqSMTKWrapper.h"
#include "smtk/extension/qt/qtOperationDialog.h"
#include "smtk/operation/Manager.h"

// Paraview client
#include "pqActiveObjects.h"
#include "pqCoreUtilities.h"

// Qt
#include <QDebug>

namespace
{
const std::string SurfacePaletteName = "Brewer Qualitative Dark2";
const std::string VolumePaletteName = "Brewer Qualitative Pastel2";

const int OP_SUCCEEDED = static_cast<int>(smtk::operation::Operation::Outcome::SUCCEEDED);
} // namespace

class pqACE3PNewStageBehaviorInternals
{
public:
  pqACE3PNewStageBehaviorInternals(QWidget* parent) { ; }
  ~pqACE3PNewStageBehaviorInternals() = default;

protected:
  // smtk::simulation::ace3p::ModelUtils m_modelUtils;
  std::vector<std::string> m_surfacePalette;
  std::vector<std::string> m_volumePalette;
};

//-----------------------------------------------------------------------------
pqACE3PNewStageReaction::pqACE3PNewStageReaction(QAction* parentObject)
  : Superclass(parentObject)
{
}

//-----------------------------------------------------------------------------
void pqACE3PNewStageReaction::onTriggered()
{
  pqACE3PNewStageBehavior::instance()->createNewStage();
}

//-----------------------------------------------------------------------------
static pqACE3PNewStageBehavior* g_instance = nullptr;

//-----------------------------------------------------------------------------
pqACE3PNewStageBehavior::pqACE3PNewStageBehavior(QObject* parent)
  : Superclass(parent)
{
  this->Internals = new pqACE3PNewStageBehaviorInternals(pqCoreUtilities::mainWidget());
}

//-----------------------------------------------------------------------------
pqACE3PNewStageBehavior* pqACE3PNewStageBehavior::instance(QObject* parent)
{
  if (!g_instance)
  {
    g_instance = new pqACE3PNewStageBehavior(parent);
  }

  if (g_instance->parent() == nullptr && parent)
  {
    g_instance->setParent(parent);
  }

  return g_instance;
}

//-----------------------------------------------------------------------------
pqACE3PNewStageBehavior::~pqACE3PNewStageBehavior()
{
  if (g_instance == this)
  {
    delete this->Internals;
    g_instance = nullptr;
  }

  QObject::disconnect(this);
}

//-----------------------------------------------------------------------------
void pqACE3PNewStageBehavior::createNewStage()
{
  // Access the active server
  pqServer* server = pqActiveObjects::instance().activeServer();
  pqSMTKWrapper* wrapper = pqSMTKBehavior::instance()->resourceManagerForServer(server);
  auto opManager = wrapper->smtkOperationManager();

  // Instantiate the NewStage operator
  auto newStageOp = opManager->create<smtk::simulation::ace3p::NewStage>();
  assert(newStageOp != nullptr);

  // connect to the current project
  auto project = smtk::simulation::ace3p::qtProjectRuntime::instance()->ace3pProject();
  newStageOp->parameters()->associate(project);

  // Construct a default stage name
  QString defaultName = QString("Stage%1").arg(1 + project->numberOfStages());
  newStageOp->parameters()->findString("stage-name")->setValue(defaultName.toStdString());

  // Construct a modal dialog for the operation spec
  QSharedPointer<smtk::extension::qtOperationDialog> dialog =
    QSharedPointer<smtk::extension::qtOperationDialog>(new smtk::extension::qtOperationDialog(
      newStageOp,
      wrapper->smtkResourceManager(),
      wrapper->smtkViewManager(),
      pqCoreUtilities::mainWidget()));
  dialog->setObjectName("NewStageACE3PDialog");
  dialog->setWindowTitle("Specify New Stage Properties");
  QObject::connect(
    dialog.get(),
    &smtk::extension::qtOperationDialog::operationExecuted,
    this,
    &pqACE3PNewStageBehavior::onOperationExecuted);
  dialog->exec();

  // set visibility of the Stages panel based on number of Stages present
  auto runtime = smtk::simulation::ace3p::qtProjectRuntime::instance();
  auto ace3pProject = runtime->ace3pProject();
  pqACE3PStagesBehavior::instance()->updateStagesPanelVisibility(ace3pProject);
}

void pqACE3PNewStageBehavior::onOperationExecuted(const smtk::operation::Operation::Result& result)
{
  if (result->findInt("outcome")->value() != OP_SUCCEEDED)
  {
    return;
  }

  // Get the new stage's index
  auto resource = result->findResource("resource")->value();
  auto project = std::dynamic_pointer_cast<smtk::simulation::ace3p::Project>(resource);
  if (project == nullptr)
  {
    qCritical() << "Internal Error: project not found" << __FILE__ << __LINE__;
    return;
  }

  int stageNumber = project->numberOfStages() - 1;
  emit this->stageAdded(stageNumber);
}
