#ifndef KEYBINDINGMAP_H
#define KEYBINDINGMAP_H
#ifdef _WIN32
#pragma once
#endif

#include "utlvector.h"

namespace vgui
{

	class Panel;

	enum
	{
		MODIFIER_SHIFT = (1 << 0),
		MODIFIER_CONTROL = (1 << 1),
		MODIFIER_ALT = (1 << 2),
	};

	struct BoundKey_t
	{
		BoundKey_t();
		BoundKey_t(const BoundKey_t& src);
		~BoundKey_t();
		BoundKey_t& operator =(const BoundKey_t& src);

		bool				isbuiltin;		             
		char const* bindingname;     
		int					keycode;	  
		int					modifiers;    
	};

	struct KeyBindingMap_t
	{
		KeyBindingMap_t();
		KeyBindingMap_t(const KeyBindingMap_t& src);
		~KeyBindingMap_t();

		char const* bindingname;     
		ALIGN16 MessageFunc_t	func;
		char const* helpstring;   
		char const* docstring;    
		bool					passive;      
	};

#define DECLARE_KEYBINDINGMAP( className )												\
	static void KB_AddToMap																\
	(																					\
		char const			*bindingname,												\
		vgui::KeyCode		defaultcode,												\
		int					default_modifiers,											\
		vgui::MessageFunc_t function,													\
		char const			*helpstring,												\
		char const			*docstring,													\
		bool				passive														\
	) 																					\
	{																					\
		vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() ); \
																						\
		vgui::KeyBindingMap_t entry;													\
		entry.bindingname = bindingname;												\
																						\
		entry.func = function;															\
																						\
		entry.helpstring = helpstring;													\
		entry.docstring = docstring;													\
																						\
		entry.passive = passive;														\
																						\
		map->entries.AddToTail( entry );												\
																						\
		vgui::BoundKey_t kb;															\
		kb.isbuiltin = true;															\
		kb.bindingname = bindingname;													\
		kb.keycode = defaultcode;														\
		kb.modifiers = default_modifiers;												\
		map->defaultkeys.AddToTail( kb );													\
		map->boundkeys.AddToTail( kb );													\
	}																					\
																						\
	static void KB_ChainToMap( void )													\
	{																					\
		static bool chained = false;													\
		if ( chained )																	\
			return;																		\
		chained = true;																	\
		vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() );	\
		map->pfnClassName = &GetPanelClassName;											\
		if ( map && GetPanelBaseClassName() && GetPanelBaseClassName()[0] )				\
		{																				\
			map->baseMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelBaseClassName() );	\
		}																				\
	}																					\
																						\
	static void KB_AddBoundKey															\
	(																					\
		char const			*bindingname,												\
		int					keycode,													\
		int					modifiers													\
	)																					\
	{																					\
		vgui::PanelKeyBindingMap *map = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() );	\
		vgui::BoundKey_t kb;															\
		kb.isbuiltin = true;															\
		kb.bindingname = bindingname;													\
		kb.keycode = keycode;															\
		kb.modifiers = modifiers;														\
		map->defaultkeys.AddToTail( kb );													\
		map->boundkeys.AddToTail( kb );													\
	}																					\
																						\
	class className##_RegisterKBMap;													\
	friend class className##_RegisterKBMap;												\
	class className##_RegisterKBMap														\
	{																					\
	public:																				\
		className##_RegisterKBMap()														\
		{																				\
			className::KB_ChainToMap();													\
		}																				\
	};																					\
	className##_RegisterKBMap m_RegisterClassKB;										\
																						\
	virtual vgui::PanelKeyBindingMap *GetKBMap()										\
	{																					\
		static vgui::PanelKeyBindingMap *s_pMap = vgui::FindOrAddPanelKeyBindingMap( GetPanelClassName() );	\
		return s_pMap;																	\
	}

#define _KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, passive )	\
	class PanelKBMapFunc_##name; \
	friend class PanelKBMapFunc_##name; \
	class PanelKBMapFunc_##name \
	{ \
	public: \
		static void InitVar() \
		{ \
			static bool bAdded = false; \
			if ( !bAdded ) \
			{ \
				bAdded = true; \
				KB_AddToMap( #name, keycode, modifiers, (vgui::MessageFunc_t)&ThisClass::function, help, doc, passive ); \
			}											\
		}												\
		PanelKBMapFunc_##name()							\
		{												\
			PanelKBMapFunc_##name::InitVar();			\
		}												\
	};													\
	PanelKBMapFunc_##name m_##name##_register;		

#define _KBBindKeyCommon( name, keycode, modifiers, _classname )	\
	class PanelKBBindFunc_##_classname; \
	friend class PanelKBBindFunc_##_classname; \
	class PanelKBBindFunc_##_classname \
	{ \
	public: \
		static void InitVar() \
		{ \
			static bool bAdded = false; \
			if ( !bAdded ) \
			{ \
				bAdded = true; \
				KB_AddBoundKey( #name, keycode, modifiers ); \
			}											\
		}												\
		PanelKBBindFunc_##_classname()					\
		{												\
			PanelKBBindFunc_##_classname::InitVar();	\
		}												\
	};													\
	PanelKBBindFunc_##_classname m_##_classname##_bindkey_register;	

#define KEYBINDING_FUNC( name, keycode, modifiers, function, help, doc )				_KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false ); virtual void function()
#define KEYBINDING_FUNC_NODECLARE( name, keycode, modifiers, function, help, doc )		_KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, false );
#define KEYBINDING_FUNC_PASSIVE( name, keycode, modifiers, function, help, doc )		_KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true );	virtual void function()
#define KEYBINDING_FUNC_PASSIVE_NODECLARE( name, keycode, modifiers, function, help, doc )		_KBMapFuncCommonFunc( name, keycode, modifiers, function, help, doc, true );

#define KEYBINDING_ADDBINDING( name, keycode, modifiers )									_KBBindKeyCommon( name, keycode, modifiers, name );
#define KEYBINDING_ADDBINDING_MULTIPLE( name, keycode, modifiers, _classname )				_KBBindKeyCommon( name, keycode, modifiers, _classname );

	struct PanelKeyBindingMap
	{
		PanelKeyBindingMap()
		{
			baseMap = NULL;
			pfnClassName = NULL;
			processed = false;
		}

		CUtlVector< KeyBindingMap_t > entries;
		bool processed;
		PanelKeyBindingMap* baseMap;
		CUtlVector< BoundKey_t > defaultkeys;
		CUtlVector< BoundKey_t > boundkeys;
		char const* (*pfnClassName)(void);
	};

	PanelKeyBindingMap* FindPanelKeyBindingMap(char const* className);
	PanelKeyBindingMap* FindOrAddPanelKeyBindingMap(char const* className);

}   


#endif  