
#ifndef PLS_THREAD_STATE_H
#define PLS_THREAD_STATE_H

#include <random>
#include <memory>
#include <array>
#include <chrono>

#include "pls/internal/base/thread.h"
#include "pls/internal/scheduling/task_manager.h"
#include "pls/internal/scheduling/cont_manager.h"

namespace pls {
namespace internal {
namespace scheduling {

// forward declaration
class scheduler;
class task;

struct alignas(base::system_details::CACHE_LINE_SIZE) thread_state {
  scheduler *scheduler_;
  size_t id_;

  task_manager &task_manager_;
  cont_manager &cont_manager_;

  alignas(base::system_details::CACHE_LINE_SIZE) task *current_task_;
  alignas(base::system_details::CACHE_LINE_SIZE) std::minstd_rand random_;

 protected:
  thread_state(task_manager &task_manager,
               cont_manager &cont_manager) :
      scheduler_{nullptr},
      id_{0},
      task_manager_{task_manager},
      cont_manager_{cont_manager},
      current_task_{nullptr},
      random_{static_cast<unsigned long>(std::chrono::steady_clock::now().time_since_epoch().count())} {}

 public:
  /**
   * Convenience helper to get the thread_state instance associated with this thread.
   * Must only be called on threads that are associated with a thread_state,
   * this will most likely be threads created by the scheduler.
   *
   * @return The thread_state of this thread.
   */
  static thread_state *get() { return base::this_thread::state<thread_state>(); }

  // Do not allow move/copy operations.
  // State is a pure memory container with references/pointers into it from all over the code.
  // It should be allocated, used and de-allocated, nothing more.
  thread_state(thread_state &&) = delete;
  thread_state &operator=(thread_state &&) = delete;

  thread_state(const thread_state &) = delete;
  thread_state &operator=(const thread_state &) = delete;
};

template<size_t NUM_TASKS, size_t MAX_TASK_STACK_SIZE, size_t NUM_CONTS, size_t MAX_CONT_SIZE>
struct static_thread_state : public thread_state {
 public:
  static_thread_state() : thread_state{static_task_manager_, static_cont_manager_} {}

 private:
  static_task_manager<NUM_TASKS, MAX_TASK_STACK_SIZE> static_task_manager_;
  static_cont_manager<NUM_CONTS, MAX_CONT_SIZE> static_cont_manager_;
};

}
}
}

#endif //PLS_THREAD_STATE_H
