//=========================================================================
//  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.
//=========================================================================

// Local includes
#include "smtk/simulation/ace3p/Metadata.h"
#include "smtk/simulation/ace3p/Project.h"
#include "smtk/simulation/ace3p/Registrar.h"
#include "smtk/simulation/ace3p/operations/Create.h"
#include "smtk/simulation/ace3p/operations/NewStage.h"
#include "smtk/simulation/ace3p/operations/Write.h"

// SMTK includes
#include "smtk/attribute/Attribute.h"
#include "smtk/attribute/DirectoryItem.h"
#include "smtk/attribute/FileItem.h"
#include "smtk/attribute/IntItem.h"
#include "smtk/attribute/Registrar.h"
#include "smtk/attribute/Resource.h"
#include "smtk/attribute/ResourceItem.h"
#include "smtk/attribute/StringItem.h"
#include "smtk/model/Registrar.h"
#include "smtk/model/Resource.h"
#include "smtk/operation/Manager.h"
#include "smtk/operation/Operation.h"
#include "smtk/project/Manager.h"
#include "smtk/project/Registrar.h"
#include "smtk/resource/Manager.h"
#include "smtk/session/vtk/Registrar.h"

#include <boost/filesystem.hpp>

#include <cassert>
#include <iostream>
#include <sstream>

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

int main(int /*argc*/, char* /*argv*/[])
{
  // Remove project folder
  std::stringstream ss;
  ss << SCRATCH_DIR << "/cxx/"
     << "RfGun";
  std::string projectDirectory = ss.str();
  std::cout << "Line " << __LINE__ << ": project directory " << projectDirectory << std::endl;
  if (boost::filesystem::is_directory(projectDirectory))
  {
    std::cout << "Line " << __LINE__ << ": erasing current project directory" << std::endl;
    boost::filesystem::remove_all(projectDirectory);
  }

  // Create smtk managers
  smtk::resource::ManagerPtr resManager = smtk::resource::Manager::create();
  smtk::attribute::Registrar::registerTo(resManager);
  smtk::model::Registrar::registerTo(resManager);
  smtk::session::vtk::Registrar::registerTo(resManager);

  smtk::operation::ManagerPtr opManager = smtk::operation::Manager::create();
  smtk::operation::Registrar::registerTo(opManager);
  smtk::attribute::Registrar::registerTo(opManager);
  smtk::session::vtk::Registrar::registerTo(opManager);

  smtk::project::ManagerPtr projectManager = smtk::project::Manager::create(resManager, opManager);
  smtk::project::Registrar::registerTo(projectManager);
  smtk::simulation::ace3p::Registrar::registerTo(projectManager);

// Application must set workflows directory
#ifndef WORKFLOWS_SOURCE_DIR
#error WORKFLOWS_SOURCE_DIR must be defined
#endif
  smtk::simulation::ace3p::Metadata::WORKFLOWS_DIRECTORY = WORKFLOWS_SOURCE_DIR;

  // Data directory is set by CMake (target_compile_definitions)
  boost::filesystem::path dataPath(DATA_DIR);

  // Create project (first stage)
  std::shared_ptr<smtk::simulation::ace3p::Project> project;
  {
    std::cout << "Line " << __LINE__ << ": creating project" << std::endl;
    auto createOp = opManager->create<smtk::simulation::ace3p::Create>();
    smtk::attribute::AttributePtr params = createOp->parameters();
    params->findDirectory("location")->setValue(projectDirectory);
    params->findString("stage-name")->setValue("Stage1");

    boost::filesystem::path meshPath = dataPath / "model" / "3d" / "genesis" / "RfGunVacuum.gen";
    auto fileItem = params->findFile("analysis-mesh");
    fileItem->setIsEnabled(true);
    fileItem->setValue(meshPath.string());

    auto result = createOp->operate();
    int outcome = result->findInt("outcome")->value();
    assert(outcome == OP_SUCCEEDED);

    smtk::attribute::ResourceItemPtr projectItem = result->findResource("resource");
    auto resource = projectItem->value();
    project = std::dynamic_pointer_cast<smtk::simulation::ace3p::Project>(resource);
    assert(project != nullptr);
  }

  // Add second stage
  {
    std::cout << "Line " << __LINE__ << ": creating second stage" << std::endl;
    auto stageOp = opManager->create<smtk::simulation::ace3p::NewStage>();
    smtk::attribute::AttributePtr params = stageOp->parameters();
    params->associate(project);
    params->findString("stage-name")->setValue("Stage2");

    params->findString("assign-mesh")->setValue("open-new-mesh");
    boost::filesystem::path meshPath = dataPath / "model" / "3d" / "genesis" / "RfGunBody.gen";
    auto fileItem = params->findFile("analysis-mesh-file")->setValue(meshPath.string());

    auto result = stageOp->operate();
    int outcome = result->findInt("outcome")->value();
    assert(outcome == OP_SUCCEEDED);
  }

  // Write project to file system
  {
    std::cout << "Line " << __LINE__ << ": writing project" << std::endl;
    auto writeOp = opManager->create<smtk::simulation::ace3p::Write>();
    writeOp->parameters()->associate(project);
    auto result = writeOp->operate();
    int outcome = result->findInt("outcome")->value();
    assert(outcome == OP_SUCCEEDED);
  }

  std::cout << "finis" << std::endl;
  return 0;
}
