#ifndef ITEM_OF_ITEM_TYPE_HPP
#define ITEM_OF_ITEM_TYPE_HPP

#include <mesh/ItemType.hpp>

template <ItemType sub_item_t, ItemType item_t>
struct ItemOfItemType
{
  static_assert(sub_item_t != item_t, "item and its sub-item cannot be of same type");

  constexpr static ItemType sub_item_type = sub_item_t;
  constexpr static ItemType item_type     = item_t;

  using Reversed = ItemOfItemType<item_type, sub_item_type>;
};

using FaceOfCell = ItemOfItemType<ItemType::face, ItemType::cell>;
using EdgeOfCell = ItemOfItemType<ItemType::edge, ItemType::cell>;
using NodeOfCell = ItemOfItemType<ItemType::node, ItemType::cell>;

using CellOfFace = ItemOfItemType<ItemType::cell, ItemType::face>;
using EdgeOfFace = ItemOfItemType<ItemType::edge, ItemType::face>;
using NodeOfFace = ItemOfItemType<ItemType::node, ItemType::face>;

using CellOfEdge = ItemOfItemType<ItemType::cell, ItemType::edge>;
using FaceOfEdge = ItemOfItemType<ItemType::face, ItemType::edge>;
using NodeOfEdge = ItemOfItemType<ItemType::node, ItemType::edge>;

using CellOfNode = ItemOfItemType<ItemType::cell, ItemType::node>;
using FaceOfNode = ItemOfItemType<ItemType::face, ItemType::node>;
using EdgeOfNode = ItemOfItemType<ItemType::edge, ItemType::node>;

template <ItemType sub_item_type, ItemType item_type>
constexpr inline int item_of_item_type_index;

template <>
constexpr inline int item_of_item_type_index<ItemType::face, ItemType::cell> = 0;
template <>
constexpr inline int item_of_item_type_index<ItemType::edge, ItemType::cell> = 1;
template <>
constexpr inline int item_of_item_type_index<ItemType::node, ItemType::cell> = 2;

template <>
constexpr inline int item_of_item_type_index<ItemType::cell, ItemType::face> = 3;
template <>
constexpr inline int item_of_item_type_index<ItemType::edge, ItemType::face> = 4;
template <>
constexpr inline int item_of_item_type_index<ItemType::node, ItemType::face> = 5;

template <>
constexpr inline int item_of_item_type_index<ItemType::cell, ItemType::edge> = 6;
template <>
constexpr inline int item_of_item_type_index<ItemType::face, ItemType::edge> = 7;
template <>
constexpr inline int item_of_item_type_index<ItemType::node, ItemType::edge> = 8;

template <>
constexpr inline int item_of_item_type_index<ItemType::cell, ItemType::node> = 9;
template <>
constexpr inline int item_of_item_type_index<ItemType::face, ItemType::node> = 10;
template <>
constexpr inline int item_of_item_type_index<ItemType::edge, ItemType::node> = 11;

#endif   // ITEM_OF_ITEM_TYPE_HPP