#pragma once
#include "../Utils/Component.h"
#include "Scheduler.h"

/**
 * @brief Wrapper for scheduler tasks allowing parameter-less activation and deactivation.
 */
class SchedulerTaskHelper : public virtual Component
{
public:
/**
 * @brief Scheduler task constructor.
 * @param task The task.
 * @param priority Priority of the task.
 * @param period Period of the task, 0 if not periodic.
 * @param waitingTimeBeforeExecution The number of frames to wait before the first execution of the task.
 */
  SchedulerTaskHelper(SchedulerTask* task, unsigned int priority, size_t period, size_t waitingTimeBeforeExecution)
    : m_task(task)
    , m_priority(priority)
    , m_period(period)
    , m_waitingTimeBeforeExecution(waitingTimeBeforeExecution)
  {}

  /**
   * @returns Whether the task is scheduled for execution.
   */
  bool isActive() const
  {
    return m_task->isActive();
  }

  unsigned int getPriority() const
  {
    return m_priority;
  }

  size_t getPeriod() const
  {
    return m_period;
  }

  size_t getWaitingTimeBeforeExecution() const
  {
    return m_waitingTimeBeforeExecution;
  }

  /**
   * @brief Sets the number of frames to wait before execution.
   * @param waitingTimeBeforeExecution the number of frames to wait before execution.
   */
  void setWaitingTimeBeforeExecution(size_t waitingTimeBeforeExecution)
  {
    m_waitingTimeBeforeExecution = waitingTimeBeforeExecution;
  }

  /**
   * @brief Registers the task to the scheduler.
   */
  void activate()
  {
    assert(!isActive());
    Spar->getScheduler()->activate(m_task, m_priority, m_period, m_waitingTimeBeforeExecution);
  }

  /**
   * @brief Unregisters the task from the scheduler.
   */
  void deactivate()
  {
    Spar->getScheduler()->deactivate(m_task);
  }

protected:
  SchedulerTask* const m_task;
  /**
   * @brief The priority of the task.
   */
  unsigned int m_priority;

  /** 
   * @brief Period of the task, 0 if not periodic.
   */
  size_t m_period;
  
  /**
   * @brief The number of frames to wait before the first execution of the task.
   */
  size_t m_waitingTimeBeforeExecution;

private:
  SchedulerTaskHelper & operator=(const SchedulerTaskHelper &);
};

#define SCHEDULER_EVENT_NAME(Type, Function) \
  SchedulerTask_##Type##_##Function

#define SCHEDULER_EVENT_HANDLER(Type, Function) \
class SCHEDULER_EVENT_NAME(Type, Function) : public SchedulerTask, public SchedulerTaskHelper, private boost::noncopyable \
  { \
  public: \
    SCHEDULER_EVENT_NAME(Type, Function)(Type& object, unsigned int priority, size_t period, size_t waitingTimeBeforeExecution) \
      : SchedulerTask(object) \
      , SchedulerTaskHelper(this, priority, period, waitingTimeBeforeExecution) \
      , m_object(object) {} \
    virtual ~SCHEDULER_EVENT_NAME(Type, Function)() {} \
    virtual void run() \
    { \
      m_object.Function(); \
    } \
  protected: \
    virtual void _output(std::ostream& out) const \
    { \
      out << STRING(SchedulerTask_##Type##_##Function); \
    } \
    Type& m_object; \
  }
