
#ifndef PLS_TASK_MANAGER_H_
#define PLS_TASK_MANAGER_H_

#include <memory>
#include <utility>
#include <array>

#include "pls/internal/scheduling/task.h"
#include "pls/internal/scheduling/external_trading_deque.h"

#include "pls/internal/base/stack_allocator.h"

namespace pls::internal::scheduling {

/**
 * Handles management of tasks in the system. Each thread has a local task manager,
 * responsible for allocating, freeing and publishing tasks for stealing.
 *
 * All interaction for spawning, stealing and task trading are managed through this class.
 */
class task_manager {
  using stack_allocator = pls::internal::base::stack_allocator;

 public:
  explicit task_manager(unsigned thread_id,
                        size_t num_tasks,
                        size_t stack_size,
                        std::shared_ptr<stack_allocator> &stack_allocator);
  ~task_manager();

  void push_resource_on_task(task *target_task, task *spare_task_chain);
  task *pop_resource_from_task(task *target_task);

  task &get_this_thread_task(size_t depth) {
    return *tasks_[depth];
  }

  task &get_active_task() {
    return *active_task_;
  }
  void set_active_task(task *active_task) {
    active_task_ = active_task;
  }

  template<typename F>
  void spawn_child(F &&lambda);
  void sync();

  task *steal_task(task_manager &stealing_task_manager);

  bool try_clean_return(context_switcher::continuation &result_cont);

  /**
   * Helper to check if a task chain is correctly chained forward form the given starting task.
   *
   * @param start_task The start of the 'to be clean' chain
   * @return true if the chain is clean/consistent.
   */
  bool check_task_chain_forward(task *start_task);
  /**
   * Helper to check if a task chain is correctly chained backward form the given starting task.
   *
   * @param start_task The end of the 'to be clean' chain
   * @return true if the chain was is clean/consistent.
   */
  bool check_task_chain_backward(task *start_task);
  /**
   * Check the task chain maintained by this task manager.
   *
   * @return true if the chain is in a clean/consistent state.
   */
  bool check_task_chain();

 private:
  std::shared_ptr<stack_allocator> stack_allocator_;
  std::vector<std::unique_ptr<task>> tasks_;
  task *active_task_;

  external_trading_deque deque_;
};

}
#include "task_manager_impl.h"

#endif //PLS_TASK_MANAGER_H_
