#include <iostream>
#include <vector>

class BaseEvent
{
protected:
	class BaseHandler 
	{
	public:
		virtual ~BaseHandler() {}
	};
	template <typename Parameter>
	class IHandler : public BaseHandler
	{
	public:
		virtual ~IHandler() {} ;
		virtual void Execute(Parameter& aParameter) = 0;
	};
	template <class Class, typename Parameter>
	class Handler : public IHandler<Parameter>
	{
		typedef void (Class::*MethodDef)(Parameter&);
		Class* m_Instance;
		MethodDef m_Method;
	public:
		Handler(Class* instance, MethodDef method) 
			: m_Instance(instance), m_Method(method) { }
		void Execute(Parameter& aParameter)
		{
			return (m_Instance->*m_Method)(aParameter);
		}
	};

	virtual void AddEvent(BaseHandler* aHandler) = 0;

public:
	virtual ~BaseEvent() {}

	template <class Class>
	class Receiver
	{
	public:
		template <typename Parameter>
		void RegisterEvent(BaseEvent& aEvent, void(Class::*fptr)(Parameter&))
		{
			aEvent.AddEvent(new Handler<Class, Parameter>((Class*)(this), fptr));
		}
	};
};

template <typename Parameter>
class Event : public BaseEvent
{
	std::vector<IHandler<Parameter>*> m_Handlers;
	template <class Class> class Receiver;	// Declaring Event<Param>::Receiver private so that BaseEvent must be used

	void AddEvent(BaseHandler* aHandler)
	{
		IHandler<Parameter>* handler = dynamic_cast<IHandler<Parameter>* >(aHandler);
		if(handler != 0)
		{
			m_Handlers.push_back(handler);
		}
	}
public:
	virtual ~Event()
	{
		RemoveAllHandlers();
	}
	inline void RemoveAllHandlers()
	{
		for(size_t i = 0; i < m_Handlers.size(); ++i) { delete m_Handlers[i]; }
		m_Handlers.clear();
	}
	inline bool Fire(size_t& i, Parameter& e)
	{
		if(i < m_Handlers.size())
		{
			m_Handlers[i]->Execute(e);
			++i;
			return true;
		}
		return false;
	}
};

struct GuiEvent
{
	bool cancel;
	GuiEvent() : cancel(false) {}
};

class Button
{
public:
	Event<GuiEvent> OnDown;
	Event<GuiEvent> OnUp;

	void FireClickEvent()
	{
		size_t cycle = 0; GuiEvent e;
		while(OnDown.Fire(cycle, e)) {
			if(e.cancel == true) return;
		}
		e = GuiEvent(); cycle = 0;
		while(OnUp.Fire(cycle, e));
	}
};

class Application : public BaseEvent::Receiver<Application>
{
	Button m_StartButton;
public:
	Application()
	{
		RegisterEvent<GuiEvent>(m_StartButton.OnDown, &Application::StartDown);
		RegisterEvent<GuiEvent>(m_StartButton.OnUp,	&Application::StartUp);
		m_StartButton.FireClickEvent();
	}

	void StartUp(GuiEvent& eventParam)
	{
		std::cout << "The start button was released" << "\n";
	}
	void StartDown(GuiEvent& eventParam)
	{
		// If you set event param to true the release will never be called
		//eventParam.cancel = true;
		std::cout << "The start button is pressed down" << "\n";
	}
};


int main(int argc, const char* argv[])
{
	Application myApp;
	return 0;
}
