
#include <wx/window.h>
#include <wx/textctrl.h>
#include <wx/stc/stc.h>

#include "kernel.h"
#include "shortcuts.h"


using namespace VRUT;

bool ShortCutManager::HandleShortCut(ShortCut& sc)
{
	// dummy shortcut used for search
	ShortCutItem shortCutItem(sc);

    ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);
 
	// shortcut exists and has non NULL callback
	if (shortCutIt != shortCuts.end())
	{
		// this is where we do the job: if we found a shortcut, we need
		// to make sure of a few things. First, that the application has
		// the focus. Then, that the focused control is not a text editing
		// one.
		wxWindow* focusedWin = wxWindow::FindFocus();

		if ( focusedWin && !dynamic_cast<wxTextCtrl *>(focusedWin) && !dynamic_cast<wxStyledTextCtrl *>(focusedWin))
		{
			// ok, we're clear, we can execute the callback of the shortcut !

			if (shortCutIt->callback)
			{
				shortCutIt->callback(shortCutIt->id, shortCutIt->callbackUserData);
			}
			else
			{
				// default callbacks
				switch (shortCutIt->id)
				{
					case ShortCutManager::SHORTCUT_OWNER_VARIANTS:
						KERNEL->GetMainWindow()->ApplyVariantState(shortCutIt->id, shortCutIt->callbackUserData);
						break;
					default:
						return false;
				}
			}
			return true;
		}
	}

	// let go of the event
	return false;
}

bool ShortCutManager::IsShortCutRegistered(ShortCut& sc)
{
	// dummy shortcut used for search
	ShortCutItem shortCutItem(sc);

    ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);
 
	return (shortCutIt != shortCuts.end());
}

bool ShortCutManager::UnregisterShortCut(ShortCut& sc)
{
	// dummy shortcut used for search
	ShortCutItem shortCutItem(sc);

	ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);

	bool found = (shortCutIt != shortCuts.end());

	if (found)
		shortCuts.erase(shortCutIt);

	return found;
}

bool ShortCutManager::UnregisterShortCut(ShortCut& sc, ShortCutOwnerID scID)
{
	// dummy shortcut used for search
	ShortCutItem shortCutItem(sc);

	ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);

	bool found = (shortCutIt != shortCuts.end());

	found = found && (shortCutIt->id == scID);

	if (found)
	{
		SAFE_DELETE(shortCutIt->callbackUserData);
		shortCuts.erase(shortCutIt);
	}

	return found;
}

bool ShortCutManager::GetShortCutUserData(ShortCut sc, ShortCutOwnerID& scID, ShortCutCallback& scCallback, ShortCutUserData*& scUserData)
{
	// dummy shortcut used for search
	ShortCutItem shortCutItem(sc);

	ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);

	bool found = (shortCutIt != shortCuts.end());

	if (found)
	{
		scID = shortCutIt->id;
		scCallback = shortCutIt->callback;
		scUserData = shortCutIt->callbackUserData;
	}

	return found;
}

inline ShortCutManager::ShortCutItem::ShortCutItem(ShortCut& sc, ShortCutOwnerID scID, const ShortCutCallback scCallback, ShortCutUserData* scUserData, const wxString& scModule, const wxString& scDescription)
	: shortCut(sc), id(scID), callback(scCallback), callbackUserData(scUserData), moduleName(scModule), description(scDescription)
{
}
 
inline bool ShortCutManager::ShortCutItem::operator == (const ShortCutItem& sc)
{
    return (sc.shortCut.modifiers == shortCut.modifiers) && (sc.shortCut.keyCode == shortCut.keyCode);
}
 
inline bool ShortCutManager::ShortCutItem::operator == (const wxAcceleratorEntry& value)
{
    return (shortCut.keyCode == tolower(value.GetKeyCode())) && (shortCut.modifiers == value.GetFlags());
}

bool ShortCutManager::RegisterShortCut(ShortCut& sc, ShortCutOwnerID scID, const ShortCutCallback scCallback, ShortCutUserData* scUserData, const wxString& scModule, const wxString& scDescription)
{
	ShortCutItem shortCutItem(sc);

	// check if the shortcut is not already registered
	ShortCutList::iterator shortCutIt = std::find(shortCuts.begin(), shortCuts.end(), shortCutItem);

	bool notFound = (shortCutIt == shortCuts.end());

	if (notFound)
	{
		shortCutItem.id = scID;
		shortCutItem.callback = scCallback;
		shortCutItem.callbackUserData = scUserData;
		shortCutItem.moduleName = scModule;
		shortCutItem.description = scDescription;

		shortCuts.push_back(shortCutItem);
	}

	return notFound;
}

// helper function that returns textual description of wx virtual keycode
const char* ShortCutManager::GetVirtualKeyCodeName(int keycode)
{
#define WXK_(x) \
		case WXK_##x: return #x;

	switch ( keycode )
	{
		WXK_(BACK)
		WXK_(TAB)
		WXK_(RETURN)
		WXK_(ESCAPE)
		WXK_(SPACE)
		WXK_(DELETE)
		WXK_(START)
		WXK_(LBUTTON)
		WXK_(RBUTTON)
		WXK_(CANCEL)
		WXK_(MBUTTON)
		WXK_(CLEAR)
		WXK_(SHIFT)
		WXK_(ALT)
		WXK_(CONTROL)
		WXK_(MENU)
		WXK_(PAUSE)
		WXK_(CAPITAL)
		WXK_(END)
		WXK_(HOME)
		WXK_(LEFT)
		WXK_(UP)
		WXK_(RIGHT)
		WXK_(DOWN)
		WXK_(SELECT)
		WXK_(PRINT)
		WXK_(EXECUTE)
		WXK_(SNAPSHOT)
		WXK_(INSERT)
		WXK_(HELP)
		WXK_(NUMPAD0)
		WXK_(NUMPAD1)
		WXK_(NUMPAD2)
		WXK_(NUMPAD3)
		WXK_(NUMPAD4)
		WXK_(NUMPAD5)
		WXK_(NUMPAD6)
		WXK_(NUMPAD7)
		WXK_(NUMPAD8)
		WXK_(NUMPAD9)
		WXK_(MULTIPLY)
		WXK_(ADD)
		WXK_(SEPARATOR)
		WXK_(SUBTRACT)
		WXK_(DECIMAL)
		WXK_(DIVIDE)
		WXK_(F1)
		WXK_(F2)
		WXK_(F3)
		WXK_(F4)
		WXK_(F5)
		WXK_(F6)
		WXK_(F7)
		WXK_(F8)
		WXK_(F9)
		WXK_(F10)
		WXK_(F11)
		WXK_(F12)
		WXK_(F13)
		WXK_(F14)
		WXK_(F15)
		WXK_(F16)
		WXK_(F17)
		WXK_(F18)
		WXK_(F19)
		WXK_(F20)
		WXK_(F21)
		WXK_(F22)
		WXK_(F23)
		WXK_(F24)
		WXK_(NUMLOCK)
		WXK_(SCROLL)
		WXK_(PAGEUP)
		WXK_(PAGEDOWN)
		WXK_(NUMPAD_SPACE)
		WXK_(NUMPAD_TAB)
		WXK_(NUMPAD_ENTER)
		WXK_(NUMPAD_F1)
		WXK_(NUMPAD_F2)
		WXK_(NUMPAD_F3)
		WXK_(NUMPAD_F4)
		WXK_(NUMPAD_HOME)
		WXK_(NUMPAD_LEFT)
		WXK_(NUMPAD_UP)
		WXK_(NUMPAD_RIGHT)
		WXK_(NUMPAD_DOWN)
		WXK_(NUMPAD_PAGEUP)
		WXK_(NUMPAD_PAGEDOWN)
		WXK_(NUMPAD_END)
		WXK_(NUMPAD_BEGIN)
		WXK_(NUMPAD_INSERT)
		WXK_(NUMPAD_DELETE)
		WXK_(NUMPAD_EQUAL)
		WXK_(NUMPAD_MULTIPLY)
		WXK_(NUMPAD_ADD)
		WXK_(NUMPAD_SEPARATOR)
		WXK_(NUMPAD_SUBTRACT)
		WXK_(NUMPAD_DECIMAL)
		WXK_(NUMPAD_DIVIDE)

		WXK_(WINDOWS_LEFT)
		WXK_(WINDOWS_RIGHT)
#ifdef __WXOSX__
		WXK_(RAW_CONTROL)
#endif
#undef WXK_

		default:
			return NULL;
	}
}

// helper function that returns textual description of key in the event
wxString ShortCutManager::GetKeyName(const ShortCut& sc)
{
	wxString shortCutStr;

	if (sc.modifiers != wxMOD_NONE)
	{
		if (sc.modifiers & wxMOD_CONTROL)
			shortCutStr += wxT("Ctrl");
		if (sc.modifiers & wxMOD_ALT)
			shortCutStr += (shortCutStr.IsEmpty()) ? wxT("Alt") : wxT("-Alt");

		// AltGR not supported - its simply combination of Alt and Ctrl flags -> cannot be distinguished
		//if (sc.modifiers & wxMOD_ALTGR)
		//	shortCutStr += (shortCutStr.IsEmpty()) ? wxT("AltGr") : wxT("-AltGr");
		if (sc.modifiers & wxMOD_SHIFT)
			shortCutStr += (shortCutStr.IsEmpty()) ? wxT("Shift") : wxT("-Shift");
	}

	if (!shortCutStr.IsEmpty())
		shortCutStr += wxT("-");

	const char* virt = GetVirtualKeyCodeName(sc.keyCode);
    if (virt)
	{
        return (shortCutStr + virt);
	}

    if ((sc.keyCode > 0) && (sc.keyCode < 32))
	{
		shortCutStr = wxString::Format("Ctrl-%c", (unsigned char)('A' + sc.keyCode - 1));
		return shortCutStr;
	}

    if ( (sc.keyCode >= 32) && (sc.keyCode < 128))
	{
		shortCutStr += wxString::Format("'%c'", (unsigned char)sc.keyCode);
        return shortCutStr; 
	}

//#if wxUSE_UNICODE
//    int uc = event.GetUnicodeKey();
//    if ( uc != WXK_NONE )
//       return wxString::Format("'%c'", uc);
//#endif

    return wxT("unknown");
}
