#ifndef method_call_h
#define method_call_h

namespace rsi {

struct method_call_interface { virtual void operator()() = 0; };

#define ARG_TYPE(n) typename tArg ## n = method_arg_unused
#define ARG_TYPES \
	ARG_TYPE(1),ARG_TYPE(2),ARG_TYPE(3),ARG_TYPE(4),ARG_TYPE(5),\
	ARG_TYPE(6),ARG_TYPE(7),ARG_TYPE(8),ARG_TYPE(9)
struct method_arg_unused { };
template<typename tArg> struct method_arg_count { enum { value = 1 }; };
template<> struct method_arg_count<method_arg_unused> { enum { value = 0 }; };
template<ARG_TYPES> struct method_count_args { enum { value = (
	method_arg_count<tArg1>::value+
	method_arg_count<tArg2>::value+
	method_arg_count<tArg3>::value+
	method_arg_count<tArg4>::value+
	method_arg_count<tArg5>::value+
	method_arg_count<tArg6>::value+
	method_arg_count<tArg7>::value+
	method_arg_count<tArg8>::value+
	method_arg_count<tArg9>::value) }; };


template<int Args> struct method_closure { };

template<> struct method_closure<0> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)();
		tClass* mInstance;
		tMethod mMethod;
		void operator()()
		{
			(mInstance->*mMethod)();
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 /*a1*/, tArg2 /*a2*/, tArg3 /*a3*/, tArg4 /*a4*/,
			tArg5 /*a5*/, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
		{
		}
	};
};

template<> struct method_closure<1> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(tArg1 a1);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 /*a2*/, tArg3 /*a3*/, tArg4 /*a4*/,
			tArg5 /*a5*/, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1)
		{
		}
	};
};

template<> struct method_closure<2> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(tArg1 a1, tArg2 a2);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 /*a3*/, tArg4 /*a4*/,
			tArg5 /*a5*/, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2)
		{
		}
	};
};

template<> struct method_closure<3> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(tArg1 a1, tArg2 a2, tArg3 a3);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 /*a4*/,
			tArg5 /*a5*/, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3)
		{
		}
	};
};

template<> struct method_closure<4> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 /*a5*/, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
		{
		}
	};
};

template<> struct method_closure<5> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		tArg5 Arg5;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4,
				Arg5);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 /*a6*/, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
			, Arg5(a5)
		{
		}
	};
};

template<> struct method_closure<6> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		tArg5 Arg5;
		tArg6 Arg6;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4,
				Arg5,Arg6);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 /*a7*/, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
			, Arg5(a5), Arg6(a6)
		{
		}
	};
};

template<> struct method_closure<7> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 a7);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		tArg5 Arg5;
		tArg6 Arg6;
		tArg7 Arg7;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4,
				Arg5,Arg6,Arg7);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4, tArg5 a5,
			tArg6 a6, tArg7 a7, tArg8 /*a8*/, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
			, Arg5(a5), Arg6(a6), Arg7(a7)
		{
		}
	};
};

template<> struct method_closure<8> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		tArg5 Arg5;
		tArg6 Arg6;
		tArg7 Arg7;
		tArg8 Arg8;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4,
				Arg5,Arg6,Arg7,Arg8);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8, tArg9 /*a9*/)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
			, Arg5(a5), Arg6(a6), Arg7(a7), Arg8(a8)
		{
		}
	};
};

template<> struct method_closure<9> {
	template<typename tClass,ARG_TYPES> struct implementation
	{
		typedef void (tClass::* tMethod)(
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8, tArg9 a9);
		tClass* mInstance;
		tMethod mMethod;
		tArg1 Arg1;
		tArg2 Arg2;
		tArg3 Arg3;
		tArg4 Arg4;
		tArg5 Arg5;
		tArg6 Arg6;
		tArg7 Arg7;
		tArg8 Arg8;
		tArg9 Arg9;
		void operator()()
		{
			(mInstance->*mMethod)(Arg1,Arg2,Arg3,Arg4,
				Arg5,Arg6,Arg7,Arg8,Arg9);
		}
		implementation(
			tClass* instance, tMethod method,
			tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
			tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8, tArg9 a9)
			: mInstance(instance), mMethod(method)
			, Arg1(a1), Arg2(a2), Arg3(a3), Arg4(a4)
			, Arg5(a5), Arg6(a6), Arg7(a7), Arg8(a8), Arg9(a9)
		{
		}
	};
};

template<typename tClass,ARG_TYPES> struct method_call
	: public method_call_interface
{
	typedef method_closure<method_count_args<tArg1,tArg2,tArg3,tArg4,
		tArg5,tArg6,tArg7,tArg8,tArg9>::value>
		::template implementation<tClass,tArg1,tArg2,tArg3,tArg4,
			tArg5,tArg6,tArg7,tArg8,tArg9> delegate;
	
	method_call(
		tClass * aInstance, delegate::tMethod aMethod)
		: mDelegate(aInstance,aMethod,
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1)
		: mDelegate(aInstance,aMethod,a1,
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2)
		: mDelegate(aInstance,aMethod,a1,a2,
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3)
		: mDelegate(aInstance,aMethod,a1,a2,a3,
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
		tArg5 a5)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,a5
			method_arg_unused(),method_arg_unused(),method_arg_unused(),
			method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
		tArg5 a5, tArg6 a6)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,a5,a6
			method_arg_unused(),method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
		tArg5 a5, tArg6 a6, tArg7 a7)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,a5,a6,a7,
			method_arg_unused(),method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
		tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,a5,a6,a7,a8,
			method_arg_unused())
	{}
	method_call(
		tClass * aInstance, delegate::tMethod aMethod,
		tArg1 a1, tArg2 a2, tArg3 a3, tArg4 a4,
		tArg5 a5, tArg6 a6, tArg7 a7, tArg8 a8, tArg9 a9)
		: mDelegate(aInstance,aMethod,a1,a2,a3,a4,a5,a6,a7,a8,a9)
	{}
	
	virtual void operator()() { mDelegate(); }
	
	delegate mDelegate;
};

#undef ARG_TYPE
#undef ARG_TYPES

}

#endif