
#ifndef PLS_ROOT_MASTER_TASK_H
#define PLS_ROOT_MASTER_TASK_H

#include <mutex>

#include "pls/internal/helpers/profiler.h"
#include "pls/internal/base/swmr_spin_lock.h"

#include "abstract_task.h"

namespace pls {
namespace internal {
namespace scheduling {

template<typename Function>
class root_task : public abstract_task {
  Function function_;
  std::atomic_uint8_t finished_;
 public:
  static constexpr auto create_id = helpers::unique_id::create<root_task<Function>>;

  explicit root_task(Function function) :
      abstract_task{0, create_id()},
      function_{function},
      finished_{0} {}
  root_task(const root_task &other) :
      abstract_task{0, create_id()},
      function_{other.function_},
      finished_{0} {}

  bool finished() {
    return finished_;
  }

  void execute() override {
    PROFILE_WORK_BLOCK("execute root_task");
    function_();
    finished_ = 1;
  }

  bool internal_stealing(abstract_task * /*other_task*/) override {
    return false;
  }

  bool split_task(base::swmr_spin_lock * /*lock*/) override {
    return false;
  }
};

template<typename Function>
class root_worker_task : public abstract_task {
  root_task<Function> *master_task_;

 public:
  static constexpr auto create_id = root_task<Function>::create_id;

  explicit root_worker_task(root_task<Function> *master_task) :
      abstract_task{0, create_id()},
      master_task_{master_task} {}

  void execute() override {
    PROFILE_WORK_BLOCK("execute root_task");
    do {
      steal_work();
    } while (!master_task_->finished());
  }

  bool internal_stealing(abstract_task * /*other_task*/) override {
    return false;
  }

  bool split_task(base::swmr_spin_lock * /*lock*/) override {
    return false;
  }
};

}
}
}

#endif //PLS_ROOT_MASTER_TASK_H
