#ifndef MESH_NODE_BOUNDARY_HPP
#define MESH_NODE_BOUNDARY_HPP

#include <algebra/TinyVector.hpp>
#include <mesh/IBoundaryDescriptor.hpp>
#include <mesh/ItemValue.hpp>
#include <mesh/RefItemList.hpp>
#include <utils/Array.hpp>

template <size_t Dimension>
class Connectivity;

template <typename ConnectivityType>
class Mesh;

template <size_t Dimension>
class MeshNodeBoundary   // clazy:exclude=copyable-polymorphic
{
 protected:
  Array<const NodeId> m_node_list;
  std::string m_boundary_name;

  std::array<TinyVector<Dimension>, Dimension*(Dimension - 1)> _getBounds(
    const Mesh<Connectivity<Dimension>>& mesh) const;

 public:
  template <size_t MeshDimension>
  friend MeshNodeBoundary<MeshDimension> getMeshNodeBoundary(const Mesh<Connectivity<MeshDimension>>& mesh,
                                                             const IBoundaryDescriptor& boundary_descriptor);

  MeshNodeBoundary& operator=(const MeshNodeBoundary&) = default;
  MeshNodeBoundary& operator=(MeshNodeBoundary&&) = default;

  const Array<const NodeId>&
  nodeList() const
  {
    return m_node_list;
  }

 protected:
  MeshNodeBoundary(const Mesh<Connectivity<Dimension>>& mesh, const RefFaceList& ref_face_list);
  MeshNodeBoundary(const Mesh<Connectivity<Dimension>>& mesh, const RefEdgeList& ref_edge_list);
  MeshNodeBoundary(const Mesh<Connectivity<Dimension>>&, const RefNodeList& ref_node_list);

 public:
  MeshNodeBoundary(const MeshNodeBoundary&) = default;
  MeshNodeBoundary(MeshNodeBoundary&&)      = default;

  MeshNodeBoundary()          = default;
  virtual ~MeshNodeBoundary() = default;
};

template <size_t Dimension>
MeshNodeBoundary<Dimension> getMeshNodeBoundary(const Mesh<Connectivity<Dimension>>& mesh,
                                                const IBoundaryDescriptor& boundary_descriptor);

#endif   // MESH_NODE_BOUNDARY_HPP