#ifndef CHECKPOINT_UTILS_HPP
#define CHECKPOINT_UTILS_HPP

#include <utils/HighFivePugsUtils.hpp>

#include <language/utils/SymbolTable.hpp>
#include <mesh/CellType.hpp>
#include <mesh/ItemValue.hpp>

template <typename DataType>
PUGS_INLINE void
write(HighFive::Group& group, const std::string& name, const Array<DataType>& array)
{
  using data_type = std::remove_const_t<DataType>;
  HighFive::DataSetCreateProps properties;
  properties.add(HighFive::Chunking(std::vector<hsize_t>{std::min(4ul * 1024ul * 1024ul, array.size())}));
  properties.add(HighFive::Shuffle());
  properties.add(HighFive::Deflate(3));

  if constexpr (std::is_same_v<CellType, data_type>) {
    auto dataset = group.createDataSet<short>(name, HighFive::DataSpace{std::vector<size_t>{array.size()}}, properties);
    dataset.template write_raw<short>(reinterpret_cast<const short*>(&(array[0])));
  } else if constexpr ((std::is_same_v<CellId, data_type>) or (std::is_same_v<FaceId, data_type>) or
                       (std::is_same_v<EdgeId, data_type>) or (std::is_same_v<NodeId, data_type>)) {
    using base_type = typename data_type::base_type;
    auto dataset =
      group.createDataSet<base_type>(name, HighFive::DataSpace{std::vector<size_t>{array.size()}}, properties);
    dataset.template write_raw<base_type>(reinterpret_cast<const base_type*>(&(array[0])));
  } else {
    auto dataset =
      group.createDataSet<data_type>(name, HighFive::DataSpace{std::vector<size_t>{array.size()}}, properties);
    dataset.template write_raw<data_type>(&(array[0]));
  }
}

template <typename DataType, ItemType item_type, typename ConnectivityPtr>
PUGS_INLINE void
write(HighFive::Group& group,
      const std::string& name,
      const ItemValue<DataType, item_type, ConnectivityPtr>& item_value)
{
  write(group, name, item_value.arrayView());
}

void writeMesh(const std::string& symbol_name,
               const EmbeddedData& embedded_data,
               HighFive::File& file,
               HighFive::Group& checkpoint_group,
               HighFive::Group& symbol_table_group);

void writeIBoundaryDescriptor(const std::string& symbol_name,
                              const EmbeddedData& embedded_data,
                              HighFive::File& file,
                              HighFive::Group& checkpoint_group,
                              HighFive::Group& symbol_table_group);

#endif   // CHECKPOINT_UTILS_HPP