#ifndef SPEC_RUNTIME_HH
#define SPEC_RUNTIME_HH

#include <flecsi/runtime.hh>

namespace spec {

namespace detail {
template<template<template<std::size_t> typename S, std::size_t> typename C,
  template<std::size_t>
  typename S,
  template<std::size_t>
  typename F,
  auto CP,
  std::size_t... DD>
std::tuple<typename C<S, DD>::template action<F<DD>::action, CP>...>
register_action(std::index_sequence<DD...>) {
  return {};
}

template<template<template<std::size_t> typename S, std::size_t> typename C,
  template<std::size_t>
  typename S,
  std::size_t... DD,
  typename... AA>
auto
dispatch(flecsi::runtime & r,
  std::size_t d,
  std::index_sequence<DD...>,
  AA &&... aa) {
  int ret{0};
  std::initializer_list<int>({(
    d == DD ? (ret = r.control<C<S, DD>>(std::forward<AA>(aa)...)), 0 : 0)...});
  return ret;
}
} // namespace detail

template<template<template<std::size_t> typename S, std::size_t> typename C,
  template<std::size_t>
  typename S,
  template<std::size_t>
  typename F,
  auto CP>
auto
register_action() {
  return detail::register_action<C, S, F, CP>(std::index_sequence<1, 2, 3>{});
}

template<template<template<std::size_t> typename S, std::size_t> typename C,
  template<std::size_t>
  typename S,
  typename... AA>
auto
dispatch(flecsi::runtime & r, std::size_t d, AA &&... aa) {
  return detail::dispatch<C, S>(
    r, d, std::index_sequence<1, 2, 3>{}, std::forward<AA>(aa)...);
} // dispacth

} // namespace spec

#endif // SPEC_RUNTIME_HH
