/**
 * Example 4
 * =========
 * This example demonstrates how to interact with the dune-vtk writers and readers for parametrized
 * grids. This dune module provides grid writers that support Lagrange parametrized elements.
 * Also a file reader is available that exports the local element parametrization via a grid function
 * that can be used to construct a new parametrized (curved) grid.
 **/

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

#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI
#include <dune/common/exceptions.hh> // We use exceptions

#include <dune/vtk/vtkreader.hh>
#include <dune/vtk/gridcreators/lagrangegridcreator.hh>
#include <dune/vtk/writers/unstructuredgridwriter.hh>
#include <dune/vtk/datacollectors/lagrangedatacollector.hh>

#include <dune/foamgrid/foamgrid.hh>
#include <dune/curvedgrid/curvedgrid.hh>
#include <dune/curvedgrid/geometries/sphere.hh>
#include <dune/grid/io/file/gmshreader.hh>

using namespace Dune;

template <int order, class Grid>
void write_grid (const Grid& grid, std::string filename)
{
  Vtk::LagrangeDataCollector dataCollector{grid.leafGridView(), order};
  Vtk::UnstructuredGridWriter vtkWriter{dataCollector, Vtk::FormatTypes::ASCII};
  vtkWriter.write(filename);
}

int main(int argc, char** argv)
{
  Dune::MPIHelper::instance(argc, argv);

  using GridType = FoamGrid<2, 3>;

  {
    // Construct a reference grid
    auto refGrid = GmshReader<GridType>::read(DUNE_GRID_PATH "sphere.msh");

    // Define the geometry mapping
    auto sphere = sphereGridFunction<GridType>(1.0);

    // Wrap the reference grid to build a curved grid
    CurvedGrid grid{*refGrid, sphere};

    write_grid<3>(grid, "sphere_order3.vtu");
  }

  using GridCreator = Vtk::LagrangeGridCreator<GridType>;

  GridFactory<GridType> factory;
  GridCreator creator(factory);

  VtkReader reader(creator);
  reader.read("sphere_order3.vtu");
  std::unique_ptr grid = reader.createGrid();

  CurvedGrid curvedGrid{*grid, creator, 3};

  write_grid<3>(*grid, "sphere_order3_test.vtu");

  return 0;
}