//=========================================================================
//  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_Pin_h
#define __smtk_session_rgg_Pin_h

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

#include <memory>
#include <set>
#include <string>
#include <vector>


namespace smtk
{
namespace session
{
namespace rgg
{

/**\brief A nuclear pin description for RGG. A user can specifiy the sub pieces
  * along the height and layer materials along the radius.
  * 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 pin's labels. The logic should
  * be if the holding smtk auxgeom is removed from the resource, then do we update
  * s_usedLabels.
  */
struct SMTKRGGSESSION_EXPORT Pin
{
  // a string used to fetch pin json rep from string property
  static constexpr const char* const propDescription = "pin_descriptions";
  // a string to uniquely identify if an auxgeom is a pin under the cover
  static constexpr const char* const typeDescription = "_rgg_pin";
  // a name for subpart
  static constexpr const char* const subpartDescription = "_subpart_";
  // a name for layer
  static constexpr const char* const layerDescription = "_layer_";
  // a name for materialLayer
  static constexpr const char* const materialDescription = "_material";

  enum class PieceType : int
  {
    CYLINDER = 0,
    FRUSTUM = 1,
  };

  // piece which is used to form the the nuclear pin from bottom to top
  struct SMTKRGGSESSION_EXPORT Piece
  {
    Piece()
    {
      this->pieceType = PieceType::CYLINDER;
      this->length = 10;
      this->baseRadius = 0.5;
      this->topRadius = 0.5;
    }

    Piece(PieceType pt, double l, double b, double t):
      pieceType(pt), length(l), baseRadius(b), topRadius(t)
    {
    }

    PieceType pieceType;
    double length;
    double baseRadius;
    double topRadius;
  };

  // layer material which is used to form the inner layers of the nuclear pin.
  struct SMTKRGGSESSION_EXPORT LayerMaterial
  {
    LayerMaterial()
    {
      this->subMaterialIndex = 0;
      this->normRadius = 1;
    }

    LayerMaterial(int mi, double nr) : subMaterialIndex(mi), normRadius(nr)
    {
    }
    // TODO: find a better representation for a pin material
    int subMaterialIndex;
    double normRadius;
  };

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

  static bool isAnUniqueLabel(const std::string& label);
  static std::string generateUniqueLabel();
  const std::string& name() const;
  const std::string& label() const;
  const int& cellMaterialIndex() const;
  const smtk::model::FloatList& color() const;
  bool isCutAway() const;
  const double& zOrigin() const;
  std::vector<Piece>& pieces();
  const std::vector<Piece>& pieces() const;
  std::vector<LayerMaterial>& layerMaterials();
  const std::vector<LayerMaterial>& layerMaterials() const;


  void setName(const std::string& name);
  bool setLabel(const std::string& label);
  // Outer material for the nuclear pin.
  void setCellMaterialIndex(const int& index);
  void setColor(const smtk::model::FloatList& color);
  // A clipping plane that is perpendicular to the bottom face and goes through
  // the base radius will be used to cut the pin into half so that the inner
  // layers are visible
  void setCutAway(bool cutAway);
  void setZOrigin(const double& zOrigin);
  // A set of sections which form the the nuclear pin from bottom to top
  void setPieces(const std::vector<Piece>& pieces);
  // A set of materials which form the inner layers of the nuclear pin
  void setLayerMaterials(const std::vector<LayerMaterial>& lm);

  bool operator==(const Pin& other) const;
  bool operator!=(const Pin& other) const;

  static std::set<std::string> s_usedLabels;
private:
  struct Internal;
  std::shared_ptr<Internal> m_internal;
};

} // namespace rgg
} // namespace session
} // namespace smtk

#endif // __smtk_session_rgg_Pin_h
