#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <dune/grid/io/file/vtk/vtkwriter.hh>

#include <dune/fufem/functions/vtkbasisgridfunction.hh>

#include "vtk.hh"

#include "../utils/debugutils.hh"

template <class VertexBasis, class CellBasis>
BodyVTKWriter<VertexBasis, CellBasis>::BodyVTKWriter(
    CellBasis const & cellBasis, VertexBasis const & vertexBasis,
    std::string prefix)
    : cellBasis_(cellBasis), vertexBasis_(vertexBasis), prefix_(prefix) {}

template <class VertexBasis, class CellBasis>
template <class Vector, class ScalarVector>
void BodyVTKWriter<VertexBasis, CellBasis>::write(
    size_t record, Vector const &u, Vector const &v, ScalarVector const &alpha,
    ScalarVector const &stress) const {
  Dune::VTKWriter<typename VertexBasis::GridView> writer(
      vertexBasis_.getGridView());

  auto const displacementPointer =
      std::make_shared<VTKBasisGridFunction<VertexBasis, Vector> const>(
          vertexBasis_, u, "displacement");
  writer.addVertexData(displacementPointer);

  auto const velocityPointer =
      std::make_shared<VTKBasisGridFunction<VertexBasis, Vector> const>(
          vertexBasis_, v, "velocity");
  writer.addVertexData(velocityPointer);

  auto const AlphaPointer =
      std::make_shared<VTKBasisGridFunction<VertexBasis, ScalarVector> const>(
          vertexBasis_, alpha, "Alpha");
  writer.addVertexData(AlphaPointer);

  auto const stressPointer =
      std::make_shared<VTKBasisGridFunction<CellBasis, ScalarVector> const>(
          cellBasis_, stress, "stress");
  writer.addCellData(stressPointer);

  std::string const filename = prefix_ + "_" + std::to_string(record);
  writer.write(filename.c_str(), Dune::VTK::appendedraw);
}

template <class VertexBasis, class CellBasis>
void BodyVTKWriter<VertexBasis, CellBasis>::writeGrid() const {
  Dune::VTKWriter<typename VertexBasis::GridView> writer(
      vertexBasis_.getGridView());

  std::string const filename = prefix_ + "_grid";
  writer.write(filename.c_str(), Dune::VTK::appendedraw);
}

template <class VertexBasis, class CellBasis>
MyVTKWriter<VertexBasis, CellBasis>::MyVTKWriter(const std::vector<const CellBasis* >& cellBases, const std::vector<const VertexBasis* >& vertexBases,
  std::string prefix): bodyVTKWriters_(vertexBases.size()), prefix_(prefix) {

  for (size_t i=0; i<bodyVTKWriters_.size(); i++) {
    bodyVTKWriters_[i] = new BodyVTKWriter<VertexBasis, CellBasis>(*cellBases[i], *vertexBases[i], prefix_+std::to_string(i));
  }
}

template <class VertexBasis, class CellBasis>
MyVTKWriter<VertexBasis, CellBasis>::~MyVTKWriter() {
  for (size_t i=0; i<bodyVTKWriters_.size(); i++) {
    delete bodyVTKWriters_[i];
  }
}

template <class VertexBasis, class CellBasis>
template <class Vector, class ScalarVector>
void MyVTKWriter<VertexBasis, CellBasis>::write(size_t record, const std::vector<Vector>& u, const std::vector<Vector>& v,
                        const std::vector<ScalarVector>& alpha, const std::vector<ScalarVector>& stress) const {

  for (size_t i=0; i<bodyVTKWriters_.size(); i++) {
    bodyVTKWriters_[i]->write(record, u[i], v[i], alpha[i], stress[i]);
  }
}
template <class VertexBasis, class CellBasis>
void MyVTKWriter<VertexBasis, CellBasis>::writeGrids() const {
  for (size_t i=0; i<bodyVTKWriters_.size(); i++) {
    bodyVTKWriters_[i]->writeGrid();
  }
}
#include "vtk_tmpl.cc"