#include <iostream>
#include <vector>
#include <algorithm>

const static auto null = 0;

template<typename TFuncSignature>
class Callback;

/////////////////
/* 0 ARGUMENTS */
/////////////////

template<typename R>
class Callback<R ()> {
public:
    typedef R (*TFunc)(void*);

	const static size_t Arity = 0;

	Callback() : obj(0), func(0) {}
	Callback(void* o, TFunc f) : obj(o), func(f) {}

	R operator()( ) const {
		return (*func)(obj);
	}

	typedef void* Callback::*SafeBoolType;
	operator SafeBoolType () const {
		return func != 0? &Callback::obj : 0;
	}

	bool operator! () const {
		return func == 0;
	}

	bool operator== ( const Callback<R ()>& right ) const {
		return obj == right.obj && func == right.func;
	}

	bool operator!= ( const Callback<R ()>& right ) const {
		return obj != right.obj || func != right.func;
	}

private:
	void* obj;
	TFunc func;
};

namespace detail {
	template<typename R, class T>
	struct DeduceConstMemCallback0 { 
		template<R(T::*Func)() const> inline static Callback<R()> Bind(T* o) {
			struct _ { static R wrapper(void* o) { return (static_cast<T*>(o)->*Func)(); } };
			return Callback<R()>(o, (R(*)(void*)) _::wrapper);
		}
	};

	template<typename R, class T>
	struct DeduceMemCallback0 { 
		template<R(T::*Func)()> inline static Callback<R()> Bind(T* o) {
			struct _ { static R wrapper(void* o) { return (static_cast<T*>(o)->*Func)(); } };
			return Callback<R()>(o, (R(*)(void*)) _::wrapper);
		}
	};

	template<typename R>
	struct DeduceStaticCallback0 { 
		template<R(*Func)()> inline static Callback<R()> Bind() { 
			struct _ { static R wrapper(void* ) { return (*Func)(); } };
			return Callback<R()>(0, (R(*)(void*)) _::wrapper); 
		}
	};
}

template<typename R, class T>
detail::DeduceConstMemCallback0<R, T> DeduceCallback0( R(T::*)() const ) {
	return detail::DeduceConstMemCallback0<R, T>();
}

template<typename R, class T>
detail::DeduceMemCallback0<R, T> DeduceCallback0(R(T::*)()) {
	return detail::DeduceMemCallback0<R, T>();
}

template<typename R>
detail::DeduceStaticCallback0<R> DeduceCallback0(R(*)()) {
	return detail::DeduceStaticCallback0<R>();
}

class EventBase {
public:
	const static int ExpectedFunctorCount = 2;
};

class Event {
public:
	typedef void(* TSignature)( );
	typedef Callback<void( )> TCallback;
	typedef std::vector<TCallback> InvocationTable;

protected:
	InvocationTable invocations;

public:
	const static int ExpectedFunctorCount = 2;

	Event () : invocations() {
		invocations.reserve( ExpectedFunctorCount );
	}

	Event ( int expectedfunctorcount ) : invocations() {
		invocations.reserve( expectedfunctorcount );
	}

	template <void (* TFunc)( )> void Add (  ) {
		TCallback c = DeduceCallback0( TFunc ).template Bind< TFunc >( );
		invocations.push_back( c );
	}

	template <typename T, void (T::* TFunc)( )> void Add ( T& object ) {
		Add<T, TFunc>( &object );
	}

	template <typename T, void (T::* TFunc)( )> void Add ( T* object ) {
		TCallback c = DeduceCallback0( TFunc ).template Bind< TFunc >( object );
		invocations.push_back( c );
	}

	template <typename T, void (T::* TFunc)( ) const> void Add ( T& object ) {
		Add<T, TFunc>( &object );
	}

	template <typename T, void (T::* TFunc)( ) const> void Add ( T* object ) {
		TCallback c = DeduceCallback0( TFunc ).template Bind< TFunc >( object );
		invocations.push_back( c );
	}

	void Invoke ( ) {
		size_t i;
		for ( i = 0; i < invocations.size(); ++i ) {
			invocations[i]( );
		}
	}

	void operator() ( ) {
		Invoke( );
	}

	size_t InvocationCount ( ) {
		return invocations.size( );
	}

	template <void (* TFunc)( )> bool Remove ()          
	{ return Remove (DeduceCallback0(TFunc).template Bind<TFunc>()); } 
	
    template <typename T, void (T::* TFunc)( )> bool Remove (T& object) 
	{ return Remove <T, TFunc>(&object); } 
	template <typename T, void (T::* TFunc)( )> bool Remove (T* object) 
	{ return Remove (DeduceCallback0(TFunc).template Bind<TFunc>(object)); } 

    template <typename T, void (T::* TFunc)( ) const> bool Remove (T& object) 
    { return Remove <T, TFunc>(&object); } 
	template <typename T, void (T::* TFunc)( ) const> bool Remove (T* object) 
	{ return Remove (DeduceCallback0(TFunc).template Bind<TFunc>(object)); } 

protected:

	bool Remove( TCallback const& target ) {
		auto it = std::find(invocations.begin(), invocations.end(), target);
		if ( it == invocations.end() ) 
			return false;
		invocations.erase( it );
		return true;
	}

};

void Arf () {
	std::cout << "Puppy Static Function" << std::endl;
}

struct Robot {
	void Beep () {
		std::cout << "RoZ Beep() Member Function" << std::endl;
	}

	void operator() () {
		std::cout << "RoZ Operator() Member Function" << std::endl;
	}
};

int main(int argc, char* argv[]) {
	Event ev;
	int i = 500;
	auto a = [] () {     
		std::cout << "Lambda me baby!" << std::endl;
	};
	typedef decltype( a ) alambda;
	auto b = [&i] () {     
		std::cout << "Lambda's captured my " << i << "<3!" << std::endl;
	};
	typedef decltype( b ) blambda;
	i = 600;

	void( * funcpointer )() = null;
	void( Robot::* robotmemfuncpointer )() = null;
	// No good, operator() is const ( Why ? )
	//void( blambda::* memfuncpointer )() const = null;
	void( alambda::* amemfuncpointer )() const = null;
	void( blambda::* bmemfuncpointer )() const = null;
	
	funcpointer = a;
	robotmemfuncpointer = &Robot::operator();
	amemfuncpointer = &alambda::operator();
	bmemfuncpointer = &blambda::operator();
	
	std::cout <<
		"===========================================================\n" <<
		"Calling Lambdas statically, using Member Function Pointers\n" <<
		"===========================================================\n" <<
		std::endl;
	(a.*amemfuncpointer)();
	(b.*bmemfuncpointer)();
	
	std::cout <<
		"===============================================================\n" <<
		"Calling Lambdas through Callback, because I can, Mother Fucker.\n" <<
		"I will also change a captured-by-value integer on the lambda...\n" <<
		" because I can, Mother Fucker!\n" <<
		"===============================================================\n" <<
		std::endl;

	i = 200;
	ev.Add<alambda, &alambda::operator()>( a );
	ev.Add<blambda, &blambda::operator()>( b );
	ev();
    
    ev.Remove<blambda, &blambda::operator()>( b );
    ev();
    // Doesn't remove alambda, it's unique!
    ev.Remove<blambda, &blambda::operator()>( b );
    ev();
    // Now removes alambda
    ev.Remove<alambda, &alambda::operator()>( a );
    ev();
    
	return 0;
}