#ifndef SPEC_CONTROL_HH
#define SPEC_CONTROL_HH

#include <flecsi/flog.hh>
#include <flecsi/run/control.hh>

namespace spec::control {
/// Control Points.
enum class cp {
  /// Application initialization.
  initialize,
  /// Time evolution (cycled).
  advance,
  /// Running analysis (cycled).
  analyze,
  /// Application finalization.
  finalize
};

inline const char *
operator*(cp control_point) {
  switch(control_point) {
    case cp::initialize:
      return "initialize";
    case cp::advance:
      return "advance";
    case cp::analyze:
      return "analyze";
    case cp::finalize:
      return "finalize";
  }
  flog_fatal("invalid control point");
}

template<typename S>
struct control_policy : flecsi::run::control_base {

  using control_points_enum = cp;

  /// Control Model Constructor
  /// @param steps Maximum number of time steps.
  /// @param log   Logging frequency.
  control_policy(std::size_t steps, std::size_t log)
    : steps_(steps), log_(log) {}

  S & state() {
    return state_;
  }
  auto step() const {
    return step_;
  }
  auto steps() const {
    return steps_;
  }
  auto log() const {
    return log_;
  }

  static bool cycle_control(control_policy & cp) {
    return cp.step_++ < cp.steps_ && S::cycle_control(cp);
  }

  using evolve = cycle<cycle_control, point<cp::advance>, point<cp::analyze>>;

  using control_points =
    list<point<cp::initialize>, evolve, point<cp::finalize>>;

protected:
  S state_;
  std::size_t step_{0};
  std::size_t steps_;
  std::size_t log_;
};
} // namespace spec::control

#endif // SPEC_CONTROL_HH
