#include <iostream>
#include <map>
#include <vector>

/**
* Receiver
*/
class EBaseReceiver
{
    protected:
        static std::size_t nextId;
};

template <typename TEventData>
class Receiver : public EBaseReceiver
{
	friend class EventManager;
    public:
		virtual void onEventReceive( const TEventData& event ) = 0;
        static std::size_t getId() { return ID; }
    private:
         static std::size_t ID;
};

/**
* Event
*/
struct BaseEvent
{
    protected:
         static std::size_t nextId;
};
    	
template <typename T>
struct Event : public BaseEvent
{
    static std::size_t getId() { return ID; }
	static std::size_t ID;
};

/**
* EventManager
*/
class EventManager
{
	private:

		typedef std::vector<EBaseReceiver*> 			ReceiverArray;
		typedef std::map<std::size_t, ReceiverArray> 	ImplSubscriberArray;
		ImplSubscriberArray subscribers;

	public:

		template< class TEvent, template<class> class TReceiver>
		void subscribe( TReceiver<TEvent>* receiver )
		{
    		const std::size_t eventId = TEvent::getId();
    		this->subscribers[eventId].push_back(receiver);
   		}
   		
   		template <typename TEvent>
		void emit( const TEvent& event )
		{
			const ReceiverArray& receivers = this->subscribers[TEvent::getId()];
			for( auto& receiver : receivers )
			{
				static_cast<Receiver<TEvent>&>((*receiver)).onEventReceive(event);
			}
		}
};

/**
* Test events
*/   
EventManager eventManager;
struct HealthEvent : public Event<HealthEvent>{};
struct DamageEvent : public Event<DamageEvent>{};

/**
* Test classes
*/
class DamageSystem : public Receiver<HealthEvent>, public Receiver<DamageEvent>
{
	DamageSystem()
	{
		eventManager.subscribe<HealthEvent>(this);
		eventManager.subscribe<DamageEvent>(this);
	}
	
	void onEventReceive( const HealthEvent& event ) { std::cout << "HealthEvent !" << std::endl; };
	void onEventReceive( const DamageEvent& event ) { std::cout << "DamageEvent !" << std::endl; };
};

int main()
{
	DamateSystem system;
	eventManager.emit(DamageEvent());
return 0;
}