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

#ifdef HAVE_IPOPT
#undef HAVE_IPOPT
#endif

#include <dune/solvers/common/numproc.hh> // Solver::FULL

#include "mysolver.hh"

template <int dim, class MatrixType, class VectorType, class GridType>
MySolver<dim, MatrixType, VectorType, GridType>::MySolver(
    Dune::ParameterTree const &parset, int refinements, double solver_tolerance,
    GridType const &grid, Dune::BitSetVector<dim> const &ignoreNodes)
    : baseEnergyNorm(linearBaseSolverStep),
      linearBaseSolver(&linearBaseSolverStep,
                       parset.get<int>("linear.maxiterations"),
                       solver_tolerance, &baseEnergyNorm, Solver::QUIET),
      transferOperators(refinements),
      multigridStep(new SolverType(linearIterationStep, nonlinearSmoother)) {
  // linear iteration step
  linearIterationStep.setMGType(parset.get<int>("linear.cycle"),
                                parset.get<int>("linear.pre"),
                                parset.get<int>("linear.post"));
  linearIterationStep.basesolver_ = &linearBaseSolver;
  linearIterationStep.setSmoother(&linearPresmoother, &linearPostsmoother);

  // transfer operators
  for (auto &x : transferOperators)
    x = new CompressedMultigridTransfer<VectorType>;
  TransferOperatorAssembler<GridType>(grid)
      .assembleOperatorPointerHierarchy(transferOperators);
  linearIterationStep.setTransferOperators(transferOperators);

  // tnnmg iteration step
  multigridStep->setSmoothingSteps(parset.get<int>("main.pre"),
                                   parset.get<int>("main.multi"),
                                   parset.get<int>("main.post"));
  multigridStep->ignoreNodes_ = &ignoreNodes;
}

template <int dim, class MatrixType, class VectorType, class GridType>
MySolver<dim, MatrixType, VectorType, GridType>::~MySolver() {
  for (auto &x : transferOperators)
    delete x;

  delete multigridStep;
}

template <int dim, class MatrixType, class VectorType, class GridType>
typename MySolver<dim, MatrixType, VectorType, GridType>::SolverType *
MySolver<dim, MatrixType, VectorType, GridType>::getSolver() {
  return multigridStep;
}

#include "mysolver_tmpl.cc"