//=============================================================================
// 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_Core_h
#define __smtk_session_rgg_Core_h

#include "smtk/common/UUID.h"

#include "smtk/session/rgg/meshkit/CoreExportParameters.h"

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

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

namespace smtk {
namespace session {
namespace rgg {

/**
 * @brief Representation of a nuclear core. Set its geometry type first before calling
 * any API.
 */
class SMTKRGGSESSION_EXPORT Core
{
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 core json rep from string property
  static constexpr const char* const propDescription = "core_descriptions";
  // a string to uniquely identify if a group is a core under the cover
  static constexpr const char* const typeDescription = "_rgg_core";
  // a string to uniquely identify the geom type of a core hex or rect
  static constexpr const char* const geomDescription = "geometry_type";

  enum class SMTKRGGSESSION_EXPORT GeomType : int
  {
    Hex = 0,
    Rect = 1,
  };

  struct SMTKRGGSESSION_EXPORT GeomBase
  {
    GeomBase();
    GeomBase(double z0, double h);
    virtual ~GeomBase();
    virtual std::pair<int, int> latticeSize() const = 0;
    virtual std::pair<double, double> ductThickness() const = 0;
    virtual void setLatticeSize(const std::pair<int, int>& size) = 0;
    virtual void setDuctThickness(const std::pair<double, double>& thicknesses) = 0;
    double zOrigin;
    double height;
  };

  // A core geometry that has a hexagon shape with one degree of freedom
  struct SMTKRGGSESSION_EXPORT GeomHex : public GeomBase
  {
    GeomHex();
    GeomHex(double zO, double h, int latticeS, double ductT);
    ~GeomHex() override;
    virtual std::pair<int, int> latticeSize() const override;
    virtual std::pair<double, double> ductThickness() const override;
    virtual void setLatticeSize(const std::pair<int, int>& size) override;
    virtual void setDuctThickness(const std::pair<double, double>& thicknesses) override;
    int ls; // lattice size
    double ds;
  };

  // A core geomety that has a rectanglar shape with two degrees of freedom
  struct SMTKRGGSESSION_EXPORT GeomRect : public GeomBase
  {
    GeomRect();
    GeomRect(double zO, double h, int latticeS0, int latticeS1, double ductT0, double ductT1);
    ~GeomRect() override;
    virtual std::pair<int, int> latticeSize() const override;
    virtual std::pair<double, double> ductThickness() const override;
    virtual void setLatticeSize(const std::pair<int, int>& size) override;
    virtual void setDuctThickness(const std::pair<double, double>& thicknesses) override;
    std::pair<int, int> ls; // lattice size
    std::pair<double, double> ds;
  };

  Core();
  ~Core();

  const std::string& name() const;
  GeomType geomType() const;
  const double& zOrigin() const;
  const double& height() const;
  // Assembly to its layout
  UuidToSchema& layout();
  const UuidToSchema& layout() const;
  // Since vtk3DGlyphMapper cannot create instances based on an instance,
  // the underlying pins and ducts are stored instead of assemblies
  // Assembly to its coordinates
  UuidToCoordinates& entityToCoordinates();
  const UuidToCoordinates& entityToCoordinates() const;
  // the underlying pins and ducts to coordinates
  UuidToCoordinates& pinsAndDuctsToCoordinates();
  const UuidToCoordinates& pinsAndDuctsToCoordinates() const;
  // Hex core only uses size0
  std::pair<int, int> latticeSize() const;
  // Hex core only uses thickness0
  std::pair<double, double> ductThickness() const;

  CoreExportParameters& exportParams();
  const CoreExportParameters& exportParams() const;

  void setName(const std::string& name);
  void setGeomType(const GeomType& type);
  void setZOrigin(const double& zOrigin);
  void setHeight(const double& height);
  void setLayout(const UuidToSchema& layout);
  // Store the coordinates of used assemblies
  void setEntityToCoordinates(const UuidToCoordinates& uTC);
  // Store the coordinates of used pins and ducts
  void setPinsAndDuctsToCoordinates(const UuidToCoordinates& uTC);
  // Hex core only uses size0
  void setLatticeSize(const int& size0, const int& size1=0);
  void setLatticeSize(const std::pair<int, int>& latticeS);
  // Hex core only uses thickness0
  void setDuctThickness(const double& t0, const double& t1=0);

  void setExportParams(const CoreExportParameters& aep);

  bool operator==(const Core& other) const;
  bool operator!=(const Core& other) const;
private:
  struct Internal;
  std::shared_ptr<Internal> m_internal;
};

}
}
}

#endif
