#ifndef SRC_SPATIAL_SOLVING_SOLVERFACTORY_HH
#define SRC_SPATIAL_SOLVING_SOLVERFACTORY_HH

#define NEW_TNNMG_COMPUTE_ITERATES_DIRECTLY

#include <dune/common/bitsetvector.hh>
#include <dune/common/parametertree.hh>

#include <dune/solvers/norms/energynorm.hh>
#include <dune/solvers/solvers/loopsolver.hh>
#include <dune/solvers/iterationsteps/cgstep.hh>

#include <dune/tnnmg/iterationsteps/tnnmgstep.hh>
#include <dune/tnnmg/iterationsteps/nonlineargsstep.hh>
#include <dune/tnnmg/projections/obstacledefectprojection.hh>

//#include "tnnmg/functional.hh"
#include "tnnmg/linearization.hh"
#include "tnnmg/linesearchsolver.hh"
#include "tnnmg/localbisectionsolver.hh"

template <class FunctionalTEMPLATE, class BitVectorType>
class SolverFactory {
public:
    using Functional = FunctionalTEMPLATE;
    using Matrix = typename Functional::Matrix;
    using Vector = typename Functional::Vector;
    using BitVector = BitVectorType;

    using LocalSolver = LocalBisectionSolver;
    using NonlinearSmoother = Dune::TNNMG::NonlinearGSStep<Functional, LocalSolver>;

    using Linearization = typename Dune::TNNMG::BoxConstrainedQuadraticFunctionalConstrainedLinearization<Functional, BitVector>;
    //using Preconditioner = Dune::Solvers::Preconditioner; //TODO Platzhalter für PatchPreconditioner
    using LinearSolverStep = typename Dune::Solvers::CGStep<Matrix, Vector, BitVector>;
    using LinearSolver = typename Dune::Solvers::LoopSolver<Vector, BitVector>;

    using DefectProjection = typename Dune::TNNMG::ObstacleDefectProjection;

    using Step = typename Dune::TNNMG::TNNMGStep<Functional, BitVector, Linearization, DefectProjection, LineSearchSolver>;


  SolverFactory(Dune::ParameterTree const &,
                Functional&);

  void setProblem(Vector& x);

  auto step() -> std::shared_ptr<Step>;

private:
  Vector dummyIterate_;
  std::shared_ptr<const Functional> J_;

  // nonlinear smoother
  std::shared_ptr<NonlinearSmoother> nonlinearSmoother_;

  // linear solver
  //Preconditioner preconditioner_;
  LinearSolverStep linearSolverStep_;
  EnergyNorm<Matrix, Vector> energyNorm_;
  std::shared_ptr<LinearSolver> linearSolver_;

  // TNNMGStep
  std::shared_ptr<Step> tnnmgStep_;
};
#endif