#ifndef SRC_HDF_FRICTIONALBOUNDARY_WRITER_HH
#define SRC_HDF_FRICTIONALBOUNDARY_WRITER_HH

#include <dune/fufem/boundarypatch.hh>
#include <dune/fufem/hdf5/file.hh>
#include <dune/fufem/hdf5/sequenceio.hh>
#include <dune/fufem/hdf5/singletonwriter.hh>

#include "restrict.hh"

template <class GridView> class FrictionalBoundaryWriter {
public:
  using Patch = BoundaryPatch<GridView>;

  template <class Vector>
  FrictionalBoundaryWriter(HDF5::Group& group, const Vector& vertexCoordinates,
                           const Patch& frictionalBoundary) : group_(group),
      frictionalBoundary_(frictionalBoundary),
      frictionalBoundaryDisplacementWriter_(group_, "displacement",
                                            frictionalBoundary.numVertices(),
                                            Vector::block_type::dimension),
      frictionalBoundaryVelocityWriter_(group_, "velocity",
                                        frictionalBoundary.numVertices(),
                                        Vector::block_type::dimension),
      frictionalBoundaryStateWriter_(group_, "state",
                                     frictionalBoundary.numVertices()),
      frictionalBoundaryCoefficientWriter_(group_, "coefficient",
                                           frictionalBoundary.numVertices()),
      frictionalBoundaryWeightsWriter_(group_, "weights",
                                           frictionalBoundary.numVertices()),
      frictionalBoundaryWeightedNormalStressWriter_(group_, "weightedNormalStress",
                                           frictionalBoundary.numVertices()){

  auto const frictionalBoundaryCoordinates =
      restrictToSurface(vertexCoordinates, frictionalBoundary);

  HDF5::SingletonWriter<2> frictionalBoundaryCoordinateWriter(
      group_, "coordinates", frictionalBoundaryCoordinates.size(),
      Vector::block_type::dimension);
  setEntry(frictionalBoundaryCoordinateWriter, frictionalBoundaryCoordinates);
}

  template <class Vector, class ScalarVector>
  void write(const size_t timeStep, const Vector& u, const Vector& v, const ScalarVector& alpha, const ScalarVector& frictionCoeff) {

      auto const frictionalBoundaryDisplacements = restrictToSurface(u, frictionalBoundary_);
      addEntry(frictionalBoundaryDisplacementWriter_, timeStep, frictionalBoundaryDisplacements);

      auto const frictionalBoundaryVelocities = restrictToSurface(v, frictionalBoundary_);
      addEntry(frictionalBoundaryVelocityWriter_, timeStep, frictionalBoundaryVelocities);

      auto const frictionalBoundaryStates = restrictToSurface(alpha, frictionalBoundary_);
      addEntry(frictionalBoundaryStateWriter_, timeStep, frictionalBoundaryStates);

      auto const frictionalBoundaryCoefficient = restrictToSurface(frictionCoeff, frictionalBoundary_);
      addEntry(frictionalBoundaryCoefficientWriter_, timeStep, frictionalBoundaryCoefficient);
    }

  template <class ScalarVector>
  void writeWeightedNormalStress(const size_t timeStep, const ScalarVector& weightedNormalStress, const ScalarVector& weights) {

      auto const frictionalBoundaryWeights = restrictToSurface(weights, frictionalBoundary_);
      addEntry(frictionalBoundaryWeightsWriter_, timeStep, frictionalBoundaryWeights);

      auto const frictionalBoundaryWeightedNormalStress = restrictToSurface(weightedNormalStress, frictionalBoundary_);
      addEntry(frictionalBoundaryWeightedNormalStressWriter_, timeStep, frictionalBoundaryWeightedNormalStress);
  }

private:
  HDF5::Group& group_;

  const Patch& frictionalBoundary_;

  HDF5::SequenceIO<2> frictionalBoundaryDisplacementWriter_;
  HDF5::SequenceIO<2> frictionalBoundaryVelocityWriter_;
  HDF5::SequenceIO<1> frictionalBoundaryStateWriter_;
  HDF5::SequenceIO<1> frictionalBoundaryCoefficientWriter_;
  HDF5::SequenceIO<1> frictionalBoundaryWeightsWriter_;
  HDF5::SequenceIO<1> frictionalBoundaryWeightedNormalStressWriter_;
};

#endif