////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
//
// This file is part of Nestopia.
//
// Nestopia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// Nestopia is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Nestopia; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
////////////////////////////////////////////////////////////////////////////////////////

#ifndef NST_HOOK_H
#define NST_HOOK_H

#ifdef NST_PRAGMA_ONCE
#pragma once
#endif

namespace Nes
{
	namespace Core
	{
	#ifdef NST_FASTDELEGATE

		class Hook : public ImplicitBool<Hook>
		{
			class Component {};
			typedef void (Component::*Executor)();

			Component* component;
			Executor executor;

			NST_COMPILE_ASSERT( sizeof(Executor) <= sizeof(void (*)(void*)) );

		public:

			Hook() {}

			template<typename T>
			Hook(T* c,void (T::*e)())
			:
			component ( reinterpret_cast<Component*>(c) ),
			executor  ( reinterpret_cast<Executor>(e) )
			{
				NST_COMPILE_ASSERT( sizeof(executor) == sizeof(e) );
			}

			void Execute() const
			{
				(*component.*executor)();
			}

			void Unset()
			{
				component = NULL;
				executor = NULL;
			}

			bool operator ! () const
			{
				return !executor;
			}

			bool operator == (const Hook& h) const
			{
				return executor == h.executor && component == h.component;
			}
		};

		#define NES_DECL_HOOK(a_) void Hook_##a_()
		#define NES_HOOK(o_,a_) void o_::Hook_##a_()
		#define NES_HOOK_T(t_,o_,a_) t_ void o_::Hook_##a_()
		#define NES_DO_HOOK(a_) Hook_##a_()

	#else

		class Hook : public ImplicitBool<Hook>
		{
			typedef void* Component;
			typedef void (NST_REGCALL *Executor)(Component);

			Component component;
			Executor executor;

		public:

			Hook() {}

			Hook(Component c,Executor e)
			:
			component ( c ),
			executor  ( e )
			{}

			void Execute() const
			{
				executor( component );
			}

			void Unset()
			{
				component = NULL;
				executor = NULL;
			}

			bool operator ! () const
			{
				return !executor;
			}

			bool operator == (const Hook& h) const
			{
				return executor == h.executor && component == h.component;
			}
		};

		#define NES_DECL_HOOK(a_)                                   \
																	\
			NST_FORCE_INLINE void NST_FASTCALL Hook_M_##a_();       \
			static void NST_REGCALL Hook_##a_(void*)

		#define NES_HOOK(o_,a_)                                     \
																	\
			void NST_REGCALL o_::Hook_##a_(void* p_)                \
			{                                                       \
				static_cast<o_*>(p_)->Hook_M_##a_();                \
			}                                                       \
																	\
			NST_FORCE_INLINE void NST_FASTCALL o_::Hook_M_##a_()

		#define NES_HOOK_T(t_,o_,a_)                                \
																	\
			t_ void NST_REGCALL o_::Hook_##a_(void* p_)             \
			{                                                       \
				static_cast<o_*>(p_)->Hook_M_##a_();                \
			}                                                       \
																	\
			t_ NST_FORCE_INLINE void NST_FASTCALL o_::Hook_M_##a_()

		#define NES_DO_HOOK(a_) Hook_##a_(this)

	#endif
	}
}

#endif
