#pragma once
#include "Component.h"
#include "Event.h"
#include "SafeList.h"
#include <utility>
#include <hash_map>
#include <boost/tuple/tuple.hpp>
#include <boost/utility.hpp>

#define STRING(ARG) #ARG

template <class Arguments> class Event;

/**
 * @brief Base class for event handlers, which are receptors that listen to and handle events.
 *        The virtual destructor is necessary only so that this class is virtual.
 */
class EventHandlerBase : public virtual Component
{
public:

  virtual ~EventHandlerBase()
  {
  }

#ifdef _DEBUG_COMPONENT
  virtual void _printErrorIfStillSubscribed(const char* error) const = 0;
#endif
};

/**
 * @brief Base class for event handlers, templated on the type of arguments sent with the particular event.
 *        Extensive debugging is conducted when the _DEBUG_COMPONENT flag is on.
 * @tparam Arguments Type of arguments, must be boost::tuple<...>
 */
template <class Arguments>
class EventHandlerT : public EventHandlerBase
{
  EventHandlerT & operator=(const EventHandlerT &);
public:
  typedef Arguments arguments;

  /**
   * @brief Handles the event.
   * @param data Arbitrary data passed to the event upon registration.
   * @param args Arguments sent with the event.
   */
  virtual void onEvent(void* data, arguments& args) = 0;

#ifndef _DEBUG_COMPONENT
  /**
   * @brief Constructs a new event handler.
   * @param owner The owner of this event handler, only used for debugging purposes.
   */
  EventHandlerT(const Component& owner)
  {
    unused(owner);
  }

#else

  struct EventData
  {
    EventData(::Event<Arguments>*)
    {}
    std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator> m_subscriptions;
  };

  /**
   * @brief Constructs a new event handler.
   * @param owner The owner of this event handler, only used for debugging purposes.
   */
  EventHandlerT(const Component& owner)
    : m_owner(owner)
  {
    m_owner._onNewEventHandler(this);
  }

  /**
   * @brief Event handler's destructor. Prints error messages in debug mode if it is still connected to events.
   */
  virtual ~EventHandlerT()
  {
    m_owner._onDestroyEventHandler(this);

    for (stdext::hash_map<::Event<Arguments>*, EventData>::const_iterator eventIt = m_eventsSubscribedTo.begin();
         eventIt != m_eventsSubscribedTo.end();
         ++eventIt)
    {
      const std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>& subscriberIDs = eventIt->second.m_subscriptions;
      for (std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>::const_iterator idIt = subscriberIDs.begin();
           idIt != subscriberIDs.end();
           ++idIt)
      {
        eventIt->first->_onEventHandlerDestroyed(*idIt);
      }
    }

    _printErrorIfStillSubscribed("ERROR EventHandlerT::~EventHandlerT(): Event handler \"%s\" is still subscribed to event \"%s\"");
  }

  /**
   * @brief For each pending event this event handler is subscribed to, and for each subscription on this event (usually one),
   *        print an error message.
   * @param error The error message to print, must have two %s parameters, the first one will be set to the name of this event handler,
   *              and the second one will be set to the name of the pending event.
   */
  void _printErrorIfStillSubscribed(const char* error) const
  {
    for (stdext::hash_map<::Event<Arguments>*, EventData>::const_iterator eventIt = m_eventsSubscribedTo.begin();
         eventIt != m_eventsSubscribedTo.end();
         ++eventIt)
    {
      const std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>& subscriberIDs = eventIt->second.m_subscriptions;
      for (std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>::const_iterator idIt = subscriberIDs.begin();
           idIt != subscriberIDs.end();
           ++idIt)
      {
        SPAR_LOG(LogTypes.GENERAL_ERROR, error, m_debugName.c_str(), eventIt->first->m_debugName.c_str());
      }
    }
  }

  void _onSubscribeTo(Event<Arguments>* ev, typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator it) const
  {
    std::pair<stdext::hash_map< ::Event<Arguments>*, EventData>::iterator, bool> result = m_eventsSubscribedTo.insert(std::make_pair(ev, EventData(ev)));
    result.first->second.m_subscriptions.push_back(it);
  }

  void _onUnsubscribeFrom(Event<Arguments>* ev, typename SafeList<typename Event<Arguments>::SubscriberInfo>::iterator it) const
  {
    bool found = false;
    stdext::hash_map< ::Event<Arguments>*, EventData>::iterator pos = m_eventsSubscribedTo.find(ev);
    if (pos != m_eventsSubscribedTo.end())
    {
      std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>& subscriberIDs = pos->second.m_subscriptions;
      std::list<typename SafeList<typename ::Event<Arguments>::SubscriberInfo>::iterator>::iterator posInList = std::find(subscriberIDs.begin(), subscriberIDs.end(), it);
      if (posInList != subscriberIDs.end())
      {
        subscriberIDs.erase(posInList);
        found = true;
      }
    }
    if (!found)
    {
      SPAR_LOG(LogTypes.GENERAL_ERROR, "ERROR EventHandlerT::_onUnsubscribeFrom(): Event handler \"%s\" has no matching subscription to event \"%s\"",
        toString(this).c_str(),
        ev->m_debugName.c_str());
    }
  }

  void _onEventDestroyed(Event<Arguments>* ev, typename SafeList<typename Event<Arguments>::SubscriberInfo>::iterator it) const
  {
    _onUnsubscribeFrom(ev, it);
  }

  /**
   * @brief A mapping from each pending event this event handler is subscribed to, to the list of
   *        subscriptions (usually only one) associated to this pending event.
   */
  mutable stdext::hash_map<Event<Arguments>*, EventData> m_eventsSubscribedTo;
  /**
   * @brief The owner of this component, present only for debugging purposes.
   */
  const Component& m_owner;

#endif

protected:
  virtual void _output(std::ostream& out) const
  {
    out << getName();
#ifdef _DEBUG_COMPONENT
    out << " (owner: \"" << m_owner << "\")";
#endif
  }

//private:
//  EventHandlerT(const EventHandlerT& other);
};

/**
 * @brief Shorthand for event handlers with no argument.
 */
class EventHandler : public EventHandlerT<boost::tuple<>> 
{
public:
  EventHandler(const Component& owner)
    : EventHandlerT(owner)
  {}
};

/**
 * @brief Shorthand for event handlers with one argument.
 * @tparam T1 Type of first argument.
 */
template<class T1>
class EventHandler1 : public EventHandlerT<boost::tuple<T1>>
{
public:
  EventHandler1(const Component& owner)
    : EventHandlerT(owner)
  {}
};

/**
 * @brief Shorthand for event handlers with two arguments.
 * @tparam T1 Type of first argument.
 * @tparam T2 Type of second argument.
 */
template<class T1, class T2>
class EventHandler2 : public EventHandlerT<boost::tuple<T1,T2>>
{
public:
  EventHandler2(const Component& owner)
    : EventHandlerT(owner)
  {}
};

/**
 * @brief Shorthand for event handlers with three arguments.
 * @tparam T1 Type of first argument.
 * @tparam T2 Type of second argument.
 * @tparam T3 Type of third argument.
 */
template<class T1, class T2, class T3>
class EventHandler3 : public EventHandlerT<boost::tuple<T1,T2,T3>>
{
public:
  EventHandler3(const Component& owner)
    : EventHandlerT(owner)
  {}
};

/**
 * @brief Shorthand for event handlers with four arguments.
 * @tparam T1 Type of first argument.
 * @tparam T2 Type of second argument.
 * @tparam T3 Type of third argument.
 * @tparam T4 Type of fourth argument.
 */
template<class T1, class T2, class T3, class T4>
class EventHandler4 : public EventHandlerT<boost::tuple<T1,T2,T3,T4>>
{
public:
  EventHandler4(const Component& owner)
    : EventHandlerT(owner)
  {}
};

/**
 * @brief Shorthand for event handlers with five arguments.
 * @tparam T1 Type of first argument.
 * @tparam T2 Type of second argument.
 * @tparam T3 Type of third argument.
 * @tparam T4 Type of fourth argument.
 * @tparam T5 Type of fifth argument.
 */
template<class T1, class T2, class T3, class T4, class T5>
class EventHandler5 : public EventHandlerT<boost::tuple<T1,T2,T3,T4,T5>>
{
public:
  EventHandler5(const Component& owner)
    : EventHandlerT(owner)
  {}
};

//-----------------------------------------------------------------------------
// Event handler macros

#define EVENT_HANDLER_NAME(Type, Function) \
  EventHandler_##Type##_##Function


#define EVENT_HANDLER(Type, Function) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments&) \
    { \
      m_object.Function(data); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)


#define EVENT_HANDLER1(Type, Function, T1) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler1<T1>, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler1(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments& args) \
    { \
      m_object.Function(data, args.get<0>()); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)

#define EVENT_HANDLER2(Type, Function, T1, T2) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler2<T1,T2>, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler2(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments& args) \
    { \
      m_object.Function(data, args.get<0>(), args.get<1>()); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)

#define EVENT_HANDLER3(Type, Function, T1, T2, T3) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler3<T1,T2,T3>, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler3(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments& args) \
    { \
      m_object.Function(data, args.get<0>(), args.get<1>(), args.get<2>()); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)

#define EVENT_HANDLER4(Type, Function, T1, T2, T3, T4) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler4<T1,T2,T3,T4>, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler4(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments& args) \
    { \
      m_object.Function(data, args.get<0>(), args.get<1>(), args.get<2>(), args.get<3>()); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)

#define EVENT_HANDLER5(Type, Function, T1, T2, T3, T4, T5) \
  class EVENT_HANDLER_NAME(Type, Function) : public EventHandler5<T1,T2,T3,T4,T5>, private boost::noncopyable \
  { \
  public: \
    EVENT_HANDLER_NAME(Type, Function)(Type& object) \
      : EventHandler5(object) \
      , m_object(object) {} \
    virtual ~EVENT_HANDLER_NAME(Type, Function)() {} \
    virtual void onEvent(void* data, arguments& args) \
    { \
      m_object.Function(data, args.get<0>(), args.get<1>(), args.get<2>(), args.get<3>(), args.get<4>()); \
    } \
  protected: \
    Type& m_object; \
  }; \
  mutable EVENT_HANDLER_NAME(Type, Function)
