//=========================================================================
//  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.
//=========================================================================
#ifndef smtk_simulation_ace3p_Project_h
#define smtk_simulation_ace3p_Project_h

#include "smtk/simulation/ace3p/Exports.h"
#include "smtk/simulation/ace3p/JobsManifest.h"

#include "smtk/PublicPointerDefs.h"
#include "smtk/project/Project.h"

#include "smtk/simulation/ace3p/DerivedFrom.h"
#include "smtk/simulation/ace3p/Stage.h"

#include "smtk/io/Logger.h"

#include <nlohmann/json.hpp>

#include <string>
#include <vector>

namespace smtk
{
namespace simulation
{
namespace ace3p
{

class SMTKACE3P_EXPORT Project // : public smtk::project::Project
  : public DerivedFrom<Project, smtk::project::Project>
{
public:
  smtkTypeMacro(smtk::simulation::ace3p::Project);
  smtkCreateMacro(smtk::project::Project);
  smtkSharedFromThisMacro(smtk::project::Project);

  virtual ~Project() = default;

  /** \brief Return number of stored stages. */
  std::size_t numberOfStages() const;
  /** \brief Add a stage to the project. */
  void addStage(std::shared_ptr<Stage> stage, bool bMakeCurrent = true);
  /** \brief Remove a stage from the project using its storage index. */
  bool removeStage(std::size_t index);
  /** \brief Return the index of the current stage. */
  std::size_t currentStageIndex() const;
  /** \brief Set the current stage using its storage index. */
  void setCurrentStage(int index, bool bMarkUnclean);
  /** \brief Get a stage using its storage index. */
  std::shared_ptr<Stage> stage(std::size_t index) const;
  /** \brief Returns the stageID for a given stageIndex */
  std::string stageID(int stageIndex) const;

  /** \brief add job record field */
  bool addJobRecord(nlohmann::json jRecord, int stageIndex);
  /** \brief remove job record field */
  bool removeJobRecord(const std::string& jobId);
  /** \brief write data to a job record field */
  void setJobRecordField(int idx, std::string key, std::string value);
  /** \brief read data from a job record field */
  void getJobRecordField(int idx, std::string key, std::string& value);
  /** \brief read a Jobs Manifest from file */
  bool readJobsManifest();
  /** \brief Write current manifest to file */
  bool writeJobsManifest() const;
  /** \brief get the jobs Manifest */
  std::shared_ptr<JobsManifest> jobsManifest() const { return m_jobsManifest; }
  std::string jobData(int idx, std::string key);
  /** \brief Updates project for NEWT job-submit */
  bool onJobSubmit(
    nlohmann::json& record,
    const std::vector<std::string>& exportFiles,
    smtk::io::Logger& logger);
  /** \brief Updates project for Cumulus job-submit */
  bool onJobSubmit(
    smtk::attribute::AttributePtr exportSpec,
    smtk::attribute::AttributePtr exportResult,
    smtk::io::Logger& logger);

  std::string projectDirectory() const;
  std::string assetsDirectory() const;
  std::string exportDirectory() const;
  std::string jobsDirectory() const;
  std::string resourcesDirectory() const;

protected:
  Project();

  /** \brief Looks up stage (storage) using attribute resource */
  int findStageIndex(smtk::attribute::ResourcePtr attResource) const;
  int findStageIndex(const nlohmann::json& jobRecord) const;

private:
  std::shared_ptr<JobsManifest> m_jobsManifest;
  std::vector<std::shared_ptr<Stage>> m_stages;
  std::size_t m_currentStageIndex = 0;
};

} // namespace ace3p
} // namespace simulation
} // namespace smtk

#endif
