#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 VectorType, class OperatorType, class GridType,
          class BlockProblemType>
MySolver<dim, VectorType, OperatorType, GridType, BlockProblemType>::MySolver(
    Dune::ParameterTree 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.setNumberOfLevels(refinements + 1);
  linearIterationStep.setMGType(parset.get<int>("linear.mu"),
                                parset.get<int>("linear.nu1"),
                                parset.get<int>("linear.nu2"));
  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.nu1"),
                                   parset.get<int>("main.mu"),
                                   parset.get<int>("main.nu2"));
  multigridStep->ignoreNodes_ = &ignoreNodes;
}

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

  delete multigridStep;
}

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

#include "mysolver_tmpl.cc"