#ifndef CONNECTIVITY_1D_HPP
#define CONNECTIVITY_1D_HPP

#include <Kokkos_Core.hpp>
#include <TinyVector.hpp>

class Connectivity1D
{
public:
  static constexpr size_t dimension = 1;

private:
  const size_t  m_number_of_cells;
  const size_t& m_number_of_faces;
  const size_t  m_number_of_nodes;

  Kokkos::View<unsigned int*[2]> m_cell_nodes;
  const Kokkos::View<unsigned int*[2]>& m_cell_faces;

  Kokkos::View<unsigned short*> m_node_nb_cells;
  const Kokkos::View<unsigned short*>& m_face_nb_cells;

  Kokkos::View<unsigned int*[2]> m_node_cells;
  const Kokkos::View<unsigned int*[2]>& m_face_cells;

  Kokkos::View<unsigned short*[2]> m_node_cell_local_node;
  const Kokkos::View<unsigned short*[2]>& m_face_cell_local_face;

public:
  const size_t& numberOfNodes() const
  {
    return m_number_of_nodes;
  }

  const size_t& numberOfFaces() const
  {
    return m_number_of_faces;
  }

  const size_t& numberOfCells() const
  {
    return m_number_of_cells;
  }

  const Kokkos::View<const unsigned int*[2]> cellNodes() const
  {
    return m_cell_nodes;
  }

  const Kokkos::View<const unsigned int*[2]> cellFaces() const
  {
    return m_cell_faces;
  }

  const Kokkos::View<const unsigned short*> nodeNbCells() const
  {
    return m_node_nb_cells;
  }

  const Kokkos::View<const unsigned short*> faceNbCells() const
  {
    return m_face_nb_cells;
  }

  const Kokkos::View<const unsigned int*[2]> nodeCells() const
  {
    return m_node_cells;
  }

  const Kokkos::View<const unsigned int*[2]> faceCells() const
  {
    return m_face_cells;
  }

  const Kokkos::View<const unsigned short*[2]> nodeCellLocalNode() const
  {
    return m_node_cell_local_node;
  }

  const Kokkos::View<const unsigned short*[2]> faceCellLocalFace() const
  {
    return m_face_cell_local_face;
  }

  Connectivity1D(const Connectivity1D&) = delete;
  
  Connectivity1D(const size_t& number_of_cells)
    : m_number_of_cells (number_of_cells),
      m_number_of_faces (m_number_of_nodes),
      m_number_of_nodes (number_of_cells+1),
      m_cell_nodes ("cell_nodes", m_number_of_cells),
      m_cell_faces (m_cell_nodes),
      m_node_nb_cells ("node_nb_cells",m_number_of_nodes),
      m_face_nb_cells (m_node_nb_cells),
      m_node_cells ("node_cells", m_number_of_nodes),
      m_face_cells (m_node_cells),
      m_node_cell_local_node ("node_cell_local_node", m_number_of_nodes),
      m_face_cell_local_face (m_node_cell_local_node)
  {
    assert(number_of_cells>0);

    Kokkos::parallel_for(m_number_of_cells, KOKKOS_LAMBDA(const size_t& j) {
	m_cell_nodes(j,0)=j;
	m_cell_nodes(j,1)=j+1;
      });

    Kokkos::parallel_for(m_number_of_nodes, KOKKOS_LAMBDA(const size_t& r) {
	m_node_nb_cells(r) = 2;
      });
    m_node_nb_cells(0) = 1;
    m_node_nb_cells(m_number_of_nodes-1) = 1;


    m_node_cells(0,0) = 0;
    Kokkos::parallel_for(m_number_of_nodes-2, KOKKOS_LAMBDA(const int& r) {
	m_node_cells(r+1,0) = r;
	m_node_cells(r+1,1) = r+1;
      });
    m_node_cells(m_number_of_nodes-1,0) = m_number_of_cells-1;

    Kokkos::parallel_for(m_number_of_nodes, KOKKOS_LAMBDA(const int& r) {
	for (int J=0; J<m_node_nb_cells(r); ++J) {
	  int j = m_node_cells(r,J);
	  for (int R=0; R<2; ++R) {
	    if (m_cell_nodes(j,R) == r) {
	      m_node_cell_local_node(r,J) = R;
	    }
	  }
	}
      });
  }

  ~Connectivity1D()
  {
    ;
  }
};

#endif // CONNECTIVITY_1D_HPP