
#ifndef __SHORTCUTS_H__
#define __SHORTCUTS_H__

#include <wx/string.h>
#include <vector>
#include "variant.h"


class wxCommandEvent;
class wxAcceleratorEntry;

namespace VRUT
{

	class VRUT_CORE_API ShortCutManager
	{

	public:

		// user filled in structure passed to shortcut callback
		// used to distinguish different situations handled by the same callback 
		struct ShortCutUserData
		{
			union
			{
				struct
				{
					SCENE_ID sceneID;
					VARIANT_ID variantID;
					size_t stateID;
				} variantData;

				struct
				{
				} xxxData;

			} data;
		};

		enum ShortCutOwnerID
		{
			SHORTCUT_OWNER_UNKNOWN = -1,
			SHORTCUT_OWNER_SCENEGRAPH,
			SHORTCUT_OWNER_VARIANTS,
			SHORTCUT_OWNER_NAVIGATION,
			SHORTCUT_OWNER_MAINWINDOW
		};

		// callback type for application wide events
		typedef void (*ShortCutCallback)(ShortCutOwnerID, ShortCutUserData*);

		// a shortcut
		struct ShortCutItem
		{
			// constructor
			ShortCutItem(ShortCut& sc, ShortCutOwnerID scID = SHORTCUT_OWNER_UNKNOWN, const ShortCutCallback scCallback = NULL, ShortCutUserData* scUserData = NULL, const wxString& scModule = wxEmptyString, const wxString& scDescription = wxEmptyString);

			~ShortCutItem()
			{
				// SAFE_DELETE(callbackUserData);
			}

			// modifiers and key code
			ShortCut shortCut;
			// the callback owner id
			ShortCutOwnerID id;
			// callback
			ShortCutCallback callback;
			// used defined data passed into the callback
			ShortCutUserData* callbackUserData;

			// module for which the shortcut is registered
			wxString moduleName;
			// brief shortcut and associated action description
			wxString description;

			// equality operator
			bool operator == (const ShortCutItem& sc);
			// equality operator with an accelerator entry
			bool operator == (const wxAcceleratorEntry& value);
		};

		typedef std::vector<ShortCutItem> ShortCutList;

	protected:

		// the registered application wide shortcuts
		ShortCutList shortCuts;

	public:

		ShortCutManager() {}

		~ShortCutManager()
		{
			// shortCuts.clear();
			ShortCutList::iterator it = shortCuts.begin();
			while (it != shortCuts.end()) {
				SAFE_DELETE(it->callbackUserData);
				it = shortCuts.erase(it);    
			}
		}

		int ShortCutsCount(void)
		{
			return shortCuts.size();
		}

		ShortCutItem& GetShortCut(int index)
		{
			return shortCuts.at(index);
		}

		bool GetShortCutUserData(ShortCut sc, ShortCutOwnerID& scID, ShortCutCallback& scCallback, ShortCutUserData*& scUserData);

		// register an application wide shortcut
		bool RegisterShortCut(ShortCut& sc, ShortCutOwnerID scID = SHORTCUT_OWNER_UNKNOWN, const ShortCutCallback scCallback = NULL, ShortCutUserData* scUserData = NULL, const wxString& scModule = wxEmptyString, const wxString & scDescription = wxEmptyString);

		bool RegisterShortCut(int scModifiers, int scKeyCode, ShortCutOwnerID scID = SHORTCUT_OWNER_UNKNOWN, const ShortCutCallback scCallback = NULL, ShortCutUserData* scUserData = NULL, const wxString& scModule = wxEmptyString, const wxString& scDescription = wxEmptyString)
		{
			ShortCut shortCut(scModifiers, scKeyCode);
			return RegisterShortCut(shortCut, scID, scCallback, scUserData, scModule, scDescription);
		}

		bool UnregisterShortCut(ShortCut& sc);

		bool UnregisterShortCut(int modifiers, int keyCode)
		{
			ShortCut shortCut(modifiers, keyCode);
			return UnregisterShortCut(shortCut);
		}

		bool UnregisterShortCut(ShortCut& sc, ShortCutOwnerID scID);

		bool UnregisterShortCut(int modifiers, int keyCode, ShortCutOwnerID scID)
		{
			ShortCut shortCut(modifiers, keyCode);
			return UnregisterShortCut(shortCut, scID);
		}

		bool IsShortCutRegistered(ShortCut& sc);

		bool IsShortCutRegistered(int modifiers, int keyCode)
		{
			ShortCut shortCut(modifiers, keyCode);
			return IsShortCutRegistered(shortCut);
		}

		bool HandleShortCut(ShortCut& sc);

		bool HandleShortCut(int modifiers, int keyCode)
		{
			ShortCut shortCut(modifiers, keyCode);
			return HandleShortCut(shortCut);
		}

		static const char* GetVirtualKeyCodeName(int keycode);

		static wxString GetKeyName(const ShortCut& sc);
	};

}

#endif 
