//=============================================================================
// 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__session__rgg__Assembly_h
#define __smtk__session__rgg__Assembly_h

#include "smtk/common/UUID.h"

#include "smtk/model/FloatData.h"
#include "smtk/model/IntegerData.h"
#include "smtk/session/rgg/meshkit/AssyExportParameters.h"

#include "smtk/session/rgg/Exports.h"

#include <map>
#include <memory>
#include <utility>

namespace smtk {
namespace session {
namespace rgg {

/**\brief A nuclear assembly description for RGG.
  * This class has json serialization support.
  * User is responsible for creating a unique label before/after the construction
  * to compromise nlohmann json's usage of default constructor.
  * TODO: Add logic for removing expunged assembly's labels. The logic should
  * be if the holding smtk group is removed from the resource, then do we update
  * s_usedLabels.
  */
class SMTKRGGSESSION_EXPORT Assembly
{
public:
  using UuidToSchema = std::map<smtk::common::UUID, std::vector<std::pair<int, int>>>;
  using UuidToCoordinates = std::map<smtk::common::UUID,
                       std::vector<std::tuple<double, double, double>>>;
  // a string used to fetch assembly json rep from string property
  static constexpr const char* const propDescription = "assembly_descriptions";
  // a string to uniquely identify if a group is a assembly under the cover
  static constexpr const char* const typeDescription = "_rgg_assembly";

  Assembly();
  Assembly(const std::string& name, const std::string& label);
  ~Assembly();

  static bool isAnUniqueLabel(const std::string& label);
  static std::string generateUniqueLabel();
  const std::string& name() const;
  const std::string& label() const;
  const smtk::model::FloatList& color() const;
  const double& zAxis() const;
  // QUESTION: Should it be moved to export params
  const double& rotate() const;
  // Pin to its layout
  // The index order of each layer is clockwise, starting from upper left corner of the hex.
  // It's prefined in old RGG application.
  UuidToSchema& layout();
  const UuidToSchema& layout() const;
  // Pin to its global coordiantes
  UuidToCoordinates& entityToCoordinates();
  const UuidToCoordinates& entityToCoordinates() const;
  const smtk::common::UUID& associatedDuct() const;
  bool centerPin() const;
  // Hex core only uses pitch0
  const std::pair<double, double>& pitch() const;
  // Hex core only uses size0
  const std::pair<int, int>& latticeSize() const;

  AssyExportParameters& exportParams();
  const AssyExportParameters& exportParams() const;

  void setName(const std::string& name);
  // User is responsible to keep label unique otherwise the json serialization will break
  bool setLabel(const std::string& label);
  void setColor(const smtk::model::FloatList& color);
  void setZAxis(const double& zAxis);
  void setRotate(const double& rotate);
  void setLayout(const UuidToSchema& schema);
  void setEntityToCoordinates(const UuidToCoordinates& uTC);
  void setAssociatedDuct(const smtk::common::UUID& id);
  void setCenterPin(bool centerPin);
  // Hex core only uses pitch0
  void setPitch(const double& p0, const double& p1=0);
  // Hex core only uses size0
  void setLatticeSize(const int& s0, const int& s1=0);
  void setLatticeSize(const std::pair<int, int>& latticeS);

  void setExportParams(const AssyExportParameters& aep);

  bool operator==(const Assembly& other) const;
  bool operator!=(const Assembly& other) const;
private:
  struct Internal;
  std::shared_ptr<Internal> m_internal;
  static std::set<std::string> s_usedLabels;
};

}
}
}

#endif
