#pragma once
#include "Event.h"
#include "Task.h"

template <class Arguments> class RaiseEventTaskT;

/**
 * @brief Base class for tasks raising an event (used to postpone the event).
 */
class RaiseEventTask : public Task
{
public:
  /**
   * @brief Shorthand for RaiseEventTaskT instantiation.
   * @tparam Type of arguments on the event.
   * @param ev The event to raise.
   * @param arguments The arguments to be passed along the event when it is raised.
   * @return The appropriate RaiseEventTaskT instance.
   */
  template <class Arguments>
  static RaiseEventTaskT<Arguments>* instantiate(Event<Arguments>& ev, const Arguments& arguments);
};

/**
 * @brief Task raising an event with the particular arguments.
 * @param Arguments Type of arguments, must be boost::tuple<...>
 */
template <class Arguments>
class RaiseEventTaskT : public RaiseEventTask
{
public:
  /**
   * @brief Creates a new RaiseEventTaskT instance.
   * @param ev The event to raise.
   * @param arguments The arguments to include when raising the event.
   */
  RaiseEventTaskT(Event<Arguments>& ev, const Arguments& arguments)
    : m_ev(ev)
    , m_arguments(arguments)
  {}
  /**
   * @brief Executes the task, which raises the event.
   */
  virtual void run()
  {
    m_ev.internalRaise(m_arguments);
  }
protected:
  /**
   * @brief The event to raise.
   */
  Event<Arguments>& m_ev;
  /**
   * @brief The arguments to include when raising the event.
   */
  Arguments m_arguments;

private:
  // reference to member prevent the use of the assigment operator
  RaiseEventTaskT& operator=(const RaiseEventTaskT&);
};

template <class Arguments>
RaiseEventTaskT<Arguments>* RaiseEventTask::instantiate(Event<Arguments>& ev, const Arguments& arguments)
{
  return new RaiseEventTaskT<Arguments>(ev, arguments);
}
