#ifndef MESH_EDGE_BOUNDARY_HPP
#define MESH_EDGE_BOUNDARY_HPP

#include <algebra/TinyVector.hpp>
#include <mesh/IBoundaryDescriptor.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 [[nodiscard]] MeshEdgeBoundary   // clazy:exclude=copyable-polymorphic
{
 protected:
  RefEdgeList m_ref_edge_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 MeshEdgeBoundary<MeshDimension> getMeshEdgeBoundary(const Mesh<Connectivity<MeshDimension>>& mesh,
                                                             const IBoundaryDescriptor& boundary_descriptor);

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

  PUGS_INLINE
  const RefEdgeList& refEdgeList() const
  {
    return m_ref_edge_list;
  }

  PUGS_INLINE
  const Array<const EdgeId>& edgeList() const
  {
    return m_ref_edge_list.list();
  }

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

 public:
  MeshEdgeBoundary(const MeshEdgeBoundary&) = default;   // LCOV_EXCL_LINE
  MeshEdgeBoundary(MeshEdgeBoundary &&)     = default;   // LCOV_EXCL_LINE

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

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

#endif   // MESH_EDGE_BOUNDARY_HPP