//
// Code to handle user-defined keyboard shortcuts.
//

#include <stdio.h>
#include "system.h"
#include "keyboard.h"
#include "file.h"
#include "str.h"

// ============================================================================
// Globals.

LC_KEYBOARD_COMMAND DefaultKeyboardShortcuts[] = 
{
	{ LC_FILE_NEW, "New Project", LC_KEYMOD1_CONTROL, LC_KEY_N, 0 },
	{ LC_FILE_OPEN, "Open Project", LC_KEYMOD1_CONTROL, LC_KEY_O, 0 },
	{ LC_FILE_MERGE, "Merge Project", 0, 0, 0 },
	{ LC_FILE_SAVE, "Save Project", LC_KEYMOD1_CONTROL, LC_KEY_S, 0 },
	{ LC_FILE_SAVEAS, "Save Project As", 0, 0, 0 },
	{ LC_FILE_PICTURE, "Save Picture", 0, 0, 0 },
	{ LC_FILE_3DS, "Export 3D Studio", 0, 0, 0 },
	{ LC_FILE_HTML, "Export HTML", 0, 0, 0 },
	{ LC_FILE_POVRAY, "Export POV-Ray", 0, 0, 0 },
	{ LC_FILE_WAVEFRONT, "Export Wavefront", 0, 0, 0 },
	{ LC_FILE_PROPERTIES, "Project Properties", 0, 0, 0 },
//	{ LC_FILE_TERRAIN, "Terrain Editor", 0, 0, 0 },
	{ LC_FILE_LIBRARY, "Piece Library Manager", 0, 0, 0 },
//	{ LC_FILE_RECENT, "Open Recent File", 0, 0, 0 },
	{ LC_EDIT_UNDO, "Undo", LC_KEYMOD1_CONTROL, LC_KEY_Z, 0 },
	{ LC_EDIT_REDO, "Redo", LC_KEYMOD1_CONTROL, LC_KEY_Y, 0 },
	{ LC_EDIT_CUT, "Cut", LC_KEYMOD1_CONTROL, LC_KEY_X, 0 },
	{ LC_EDIT_COPY, "Copy", LC_KEYMOD1_CONTROL, LC_KEY_C, 0 },
	{ LC_EDIT_PASTE, "Paste", LC_KEYMOD1_CONTROL, LC_KEY_V, 0 },
	{ LC_EDIT_SELECT_ALL, "Select All", LC_KEYMOD1_CONTROL, LC_KEY_A, 0 },
	{ LC_EDIT_SELECT_NONE, "Select None", 0, 0, 0 },
	{ LC_EDIT_SELECT_INVERT, "Select Invert", 0, 0, 0 },
	{ LC_EDIT_SELECT_BYNAME, "Select By Name", 0, 0, 0 },
	{ LC_PIECE_INSERT, "Piece Insert", 0, LC_KEY_INSERT, 0 },
	{ LC_PIECE_DELETE, "Piece Delete", 0, LC_KEY_DELETE, 0 },
//	{ LC_PIECE_MINIFIG, "Minifig Wizard", 0, 0, 0 },
	{ LC_PIECE_ARRAY, "Piece Array", 0, 0, 0 },
//	{ LC_PIECE_COPYKEYS, "", 0, 0, 0 },
	{ LC_PIECE_GROUP, "Piece Group", LC_KEYMOD1_CONTROL, LC_KEY_G, 0 },
	{ LC_PIECE_UNGROUP, "Piece Ungroup", LC_KEYMOD1_CONTROL, LC_KEY_U, 0 },
	{ LC_PIECE_GROUP_ADD, "Group Add Piece", 0, 0, 0 },
	{ LC_PIECE_GROUP_REMOVE, "Group Remove Piece", 0, 0, 0 },
	{ LC_PIECE_GROUP_EDIT, "Group Edit", 0, 0, 0 },
	{ LC_PIECE_HIDE_SELECTED, "Hide Selection", LC_KEYMOD1_CONTROL, LC_KEY_H, 0 },
	{ LC_PIECE_HIDE_UNSELECTED, "Unhide Selection", 0, 0, 0 },
	{ LC_PIECE_UNHIDE_ALL, "Unhide All", 0, 0, 0 },
	{ LC_PIECE_PREVIOUS, "Piece Previous Step", 0, 0, 0 },
	{ LC_PIECE_NEXT, "Piece Next Step", 0, 0, 0 },
	{ LC_VIEW_PREFERENCES, "Preferences", 0, 0, 0 },
//	{ LC_VIEW_ZOOM, "", 0, 0, 0 },
	{ LC_VIEW_ZOOMIN, "Zoom In", 0, 0, 0 },
	{ LC_VIEW_ZOOMOUT, "Zoom Out", 0, 0, 0 },
	{ LC_VIEW_ZOOMEXTENTS, "Zoom Extents", 0, 0, 0 },
//	{ LC_VIEW_VIEWPORTS, "", 0, 0, 0 },
	{ LC_VIEW_STEP_NEXT, "Step Next", 0, 0, 0 },
	{ LC_VIEW_STEP_PREVIOUS, "Step Previous", 0, 0, 0 },
	{ LC_VIEW_STEP_FIRST, "Step First", 0, 0, 0 },
	{ LC_VIEW_STEP_LAST, "Step Last", 0, 0, 0 },
//	{ LC_VIEW_STEP_CHOOSE, "", 0, 0, 0 },
//	{ LC_VIEW_STEP_SET, "", 0, 0, 0 },
//	{ LC_VIEW_STOP, "", 0, 0, 0 },
//	{ LC_VIEW_PLAY, "", 0, 0, 0 },
	{ LC_VIEW_CAMERA_FRONT, "Camera Front", LC_KEYMOD_VIEWONLY, LC_KEY_F, 0 },
	{	LC_VIEW_CAMERA_BACK, "Camera Back", LC_KEYMOD_VIEWONLY, LC_KEY_B, 0 },
	{	LC_VIEW_CAMERA_TOP, "Camera Top", LC_KEYMOD_VIEWONLY, LC_KEY_T, 0 },
	{	LC_VIEW_CAMERA_BOTTOM, "Camera Bottom", LC_KEYMOD_VIEWONLY, LC_KEY_U, 0 },
	{	LC_VIEW_CAMERA_LEFT, "Camera Left", LC_KEYMOD_VIEWONLY, LC_KEY_L, 0 },
	{	LC_VIEW_CAMERA_RIGHT, "Camera Right", LC_KEYMOD_VIEWONLY, LC_KEY_R, 0 },
	{	LC_VIEW_CAMERA_MAIN, "Camera Main", LC_KEYMOD_VIEWONLY, LC_KEY_M, 0 },
//	{ LC_VIEW_CAMERA_MENU, "", 0, 0, 0 },
//	{ LC_VIEW_CAMERA_RESET, "", 0, 0, 0 },
//	{ LC_VIEW_AUTOPAN, "", 0, 0, 0 },
//	{ LC_HELP_ABOUT, "", 0, 0, 0 },
//	{ LC_TOOLBAR_ANIMATION, "", 0, 0, 0 },
//	{ LC_TOOLBAR_ADDKEYS, "", 0, 0, 0 },
//	{ LC_TOOLBAR_SNAPMENU, "", 0, 0, 0 },
//	{ LC_TOOLBAR_LOCKMENU, "", 0, 0, 0 },
//	{ LC_TOOLBAR_FASTRENDER, "", 0, 0, 0 },
//	{ LC_TOOLBAR_BACKGROUND, "", 0, 0, 0 },
	{ LC_VIEW_STEP_INSERT, "Step Insert", 0, 0, 0 },
	{ LC_VIEW_STEP_DELETE, "Step Delete", 0, 0, 0 },
	{ LC_EDIT_MOVEXY_SNAP_0, "Move XY Snap 0", 0, LC_KEY_0, 0 },
	{ LC_EDIT_MOVEXY_SNAP_1, "Move XY Snap 1", 0, LC_KEY_1, 0 },
	{ LC_EDIT_MOVEXY_SNAP_2, "Move XY Snap 2", 0, LC_KEY_2, 0 },
	{ LC_EDIT_MOVEXY_SNAP_3, "Move XY Snap 3", 0, LC_KEY_3, 0 },
	{ LC_EDIT_MOVEXY_SNAP_4, "Move XY Snap 4", 0, LC_KEY_4, 0 },
	{ LC_EDIT_MOVEXY_SNAP_5, "Move XY Snap 5", 0, LC_KEY_5, 0 },
	{ LC_EDIT_MOVEXY_SNAP_6, "Move XY Snap 6", 0, LC_KEY_6, 0 },
	{ LC_EDIT_MOVEXY_SNAP_7, "Move XY Snap 7", 0, LC_KEY_7, 0 },
	{ LC_EDIT_MOVEXY_SNAP_8, "Move XY Snap 8", 0, LC_KEY_8, 0 },
	{ LC_EDIT_MOVEXY_SNAP_9, "Move XY Snap 9", 0, LC_KEY_9, 0 },
	{ LC_EDIT_MOVEZ_SNAP_0, "Move Z Snap 0", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_0, 0 },
	{ LC_EDIT_MOVEZ_SNAP_1, "Move Z Snap 1", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_1, 0 },
	{ LC_EDIT_MOVEZ_SNAP_2, "Move Z Snap 2", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_2, 0 },
	{ LC_EDIT_MOVEZ_SNAP_3, "Move Z Snap 3", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_3, 0 },
	{ LC_EDIT_MOVEZ_SNAP_4, "Move Z Snap 4", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_4, 0 },
	{ LC_EDIT_MOVEZ_SNAP_5, "Move Z Snap 5", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_5, 0 },
	{ LC_EDIT_MOVEZ_SNAP_6, "Move Z Snap 6", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_6, 0 },
	{ LC_EDIT_MOVEZ_SNAP_7, "Move Z Snap 7", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_7, 0 },
	{ LC_EDIT_MOVEZ_SNAP_8, "Move Z Snap 8", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_8, 0 },
	{ LC_EDIT_MOVEZ_SNAP_9, "Move Z Snap 9", LC_KEYMOD1_SHIFT|LC_KEYMOD1_CONTROL, LC_KEY_9, 0 },
	{ LC_EDIT_ANGLE_SNAP_0, "Angle Snap 1", LC_KEYMOD1_SHIFT, LC_KEY_0, 0 },
	{ LC_EDIT_ANGLE_SNAP_1, "Angle Snap 5", LC_KEYMOD1_SHIFT, LC_KEY_1, 0 },
	{ LC_EDIT_ANGLE_SNAP_2, "Angle Snap 10", LC_KEYMOD1_SHIFT, LC_KEY_2, 0 },
	{ LC_EDIT_ANGLE_SNAP_3, "Angle Snap 15", LC_KEYMOD1_SHIFT, LC_KEY_3, 0 },
	{ LC_EDIT_ANGLE_SNAP_4, "Angle Snap 30", LC_KEYMOD1_SHIFT, LC_KEY_4, 0 },
	{ LC_EDIT_ANGLE_SNAP_5, "Angle Snap 45", LC_KEYMOD1_SHIFT, LC_KEY_5, 0 },
	{ LC_EDIT_ANGLE_SNAP_6, "Angle Snap 60", LC_KEYMOD1_SHIFT, LC_KEY_6, 0 },
	{ LC_EDIT_ANGLE_SNAP_7, "Angle Snap 90", LC_KEYMOD1_SHIFT, LC_KEY_7, 0 },
	{ LC_EDIT_ANGLE_SNAP_8, "Angle Snap 180", LC_KEYMOD1_SHIFT, LC_KEY_8, 0 },
	{ LC_EDIT_ACTION_SELECT, "Select Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_INSERT, "Insert Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_LIGHT, "Light Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_SPOTLIGHT, "Spotlight Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_CAMERA, "Camera Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_MOVE, "Move Mode", LC_KEYMOD1_SHIFT, LC_KEY_M, 0 },
	{ LC_EDIT_ACTION_ROTATE, "Rotate Mode", LC_KEYMOD1_SHIFT, LC_KEY_R, 0 },
	{ LC_EDIT_ACTION_ERASER, "Eraser Mode", LC_KEYMOD1_SHIFT, LC_KEY_E, 0 },
	{ LC_EDIT_ACTION_PAINT, "Paint Mode", LC_KEYMOD1_SHIFT, LC_KEY_N, 0 },
	{ LC_EDIT_ACTION_ZOOM, "Zoom Mode", LC_KEYMOD1_SHIFT, LC_KEY_Z, 0 },
	{ LC_EDIT_ACTION_ZOOM_REGION, "Zoom Region Mode", 0, 0, 0 },
	{ LC_EDIT_ACTION_PAN, "Pan Mode", LC_KEYMOD1_SHIFT, LC_KEY_P, 0 },
	{ LC_EDIT_ACTION_ROTATE_VIEW, "Rotate View Mode", LC_KEYMOD1_SHIFT, LC_KEY_T, 0 },
	{ LC_EDIT_ACTION_ROLL, "Roll Camera Mode", LC_KEYMOD1_SHIFT, LC_KEY_L, 0 },
};

const int KeyboardShortcutsCount = sizeof(DefaultKeyboardShortcuts)/sizeof(KeyboardShortcuts[0]);

LC_KEYBOARD_COMMAND KeyboardShortcuts[KeyboardShortcutsCount];

// ============================================================================
// Functions

bool SaveKeyboardShortcuts(const char* FileName)
{
	FileDisk f;

	if (!f.Open(FileName, "wt"))
		return false;

	for (int i = 0; i < KeyboardShortcutsCount; i++)
	{
		LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];
		String str;

		str = Cmd.Description;
		str += "=";

		if (Cmd.Key1)
		{
			if (Cmd.Flags & LC_KEYMOD1_SHIFT)
				str += "Shift+";

			if (Cmd.Flags & LC_KEYMOD1_CONTROL)
				str += "Ctrl+";

			str += "\"";
			str += GetKeyName(Cmd.Key1);
			str += "\"";
		}

		if (Cmd.Key2)
		{
			str += ",";

			if (Cmd.Flags & LC_KEYMOD2_SHIFT)
				str += "Shift+";

			if (Cmd.Flags & LC_KEYMOD2_CONTROL)
				str += "Ctrl+";

			str += "\"";
			str += GetKeyName(Cmd.Key2);
			str += "\"";
		}

		str += "\n";

		f.Write((const char*)str, str.GetLength());
	}

	return true;
}

bool LoadKeyboardShortcuts(const char* FileName)
{
	FileDisk f;
	int i;

	if (!f.Open(FileName, "rt"))
		return false;

	// Remove all existing shortcuts
	for (i = 0; i < KeyboardShortcutsCount; i++)
	{
		LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];

		Cmd.Key1 = 0;
		Cmd.Key2 = 0;
		Cmd.Flags = DefaultKeyboardShortcuts[i].Flags & ~LC_KEYMOD_MASK;
	}

	char Line[1024];
	while (f.ReadLine(Line, 1024))
	{
		char* ptr = strchr(Line, '=');

		if (ptr == NULL)
			continue;

		*ptr = 0;
		ptr++;


		for (i = 0; i < KeyboardShortcutsCount; i++)
		{
			LC_KEYBOARD_COMMAND& Cmd = KeyboardShortcuts[i];

			if (strcmp(Line, Cmd.Description))
				continue;

			if (!strncmp(ptr, "Shift+", 6))
			{
				Cmd.Flags |= LC_KEYMOD1_SHIFT;
				ptr += 6;
			}

			if (!strncmp(ptr, "Ctrl+", 5))
			{
				Cmd.Flags |= LC_KEYMOD1_CONTROL;
				ptr += 5;
			}

			ptr++;
			char* ptr2 = strchr(ptr, '\"');

			if (ptr2 == NULL)
			{
				Cmd.Flags &= ~(LC_KEYMOD1_SHIFT | LC_KEYMOD1_CONTROL);
				break;
			}

			*ptr2 = 0;
			Cmd.Key1 = GetKeyFromName(ptr);

			ptr = ptr2 + 1;

			if (*ptr != ',')
				break;
			ptr++;

			if (!strncmp(ptr, "Shift+", 6))
			{
				Cmd.Flags |= LC_KEYMOD2_SHIFT;
				ptr += 6;
			}

			if (!strncmp(ptr, "Ctrl+", 5))
			{
				Cmd.Flags |= LC_KEYMOD2_CONTROL;
				ptr += 5;
			}

			ptr++;
			ptr2 = strchr(ptr, '\"');

			if (ptr2 == NULL)
			{
				Cmd.Flags &= ~(LC_KEYMOD2_SHIFT | LC_KEYMOD2_CONTROL);
				break;
			}

			*ptr2 = 0;
			Cmd.Key2 = GetKeyFromName(ptr);

			break;
		}
	}

	return true;
}

void ResetKeyboardShortcuts()
{
	memcpy(KeyboardShortcuts, DefaultKeyboardShortcuts, sizeof(KeyboardShortcuts));
}

void InitKeyboardShortcuts()
{
	const char* FileName = Sys_ProfileLoadString("Settings", "Keyboard", "");

	ResetKeyboardShortcuts();
	LoadKeyboardShortcuts(FileName);
}

typedef struct
{
	int Key;
	const char* Name;

} LC_KEYNAME_ENTRY;

static LC_KEYNAME_ENTRY KeyNames[] =
{
	{ LC_KEY_BACK,       "Backspace" },
	{ LC_KEY_TAB,        "Tab" },
	{ LC_KEY_RETURN,     "Return" },
	{ LC_KEY_PAUSE,      "Pause" },
	{ LC_KEY_CAPITAL,    "Caps" },
	{ LC_KEY_ESCAPE,     "Escape" },
	{ LC_KEY_SPACE,      "Space" },
	{ LC_KEY_PRIOR,      "Page Up" },
	{ LC_KEY_NEXT,       "Page Down" },
	{ LC_KEY_END,        "End" },
	{ LC_KEY_HOME,       "Home" },
	{ LC_KEY_LEFT,       "Left" },
	{ LC_KEY_UP,         "Up" },
	{ LC_KEY_RIGHT,      "Right" },
	{ LC_KEY_DOWN,       "Down" },
	{ LC_KEY_SELECT,     "Select" },
	{ LC_KEY_PRINT,      "Print" },
	{ LC_KEY_INSERT,     "Insert" },
	{ LC_KEY_DELETE,     "Delete" },
	{ LC_KEY_0,          "0" },
	{ LC_KEY_1,          "1" },
	{ LC_KEY_2,          "2" },
	{ LC_KEY_3,          "3" },
	{ LC_KEY_4,          "4" },
	{ LC_KEY_5,          "5" },
	{ LC_KEY_6,          "6" },
	{ LC_KEY_7,          "7" },
	{ LC_KEY_8,          "8" },
	{ LC_KEY_9,          "9" },
	{ LC_KEY_A,          "A" },
	{ LC_KEY_B,          "B" },
	{ LC_KEY_C,          "C" },
	{ LC_KEY_D,          "D" },
	{ LC_KEY_E,          "E" },
	{ LC_KEY_F,          "F" },
	{ LC_KEY_G,          "G" },
	{ LC_KEY_H,          "H" },
	{ LC_KEY_I,          "I" },
	{ LC_KEY_J,          "J" },
	{ LC_KEY_K,          "K" },
	{ LC_KEY_L,          "L" },
	{ LC_KEY_M,          "M" },
	{ LC_KEY_N,          "N" },
	{ LC_KEY_O,          "O" },
	{ LC_KEY_P,          "P" },
	{ LC_KEY_Q,          "Q" },
	{ LC_KEY_R,          "R" },
	{ LC_KEY_S,          "S" },
	{ LC_KEY_T,          "T" },
	{ LC_KEY_U,          "U" },
	{ LC_KEY_V,          "V" },
	{ LC_KEY_W,          "W" },
	{ LC_KEY_X,          "X" },
	{ LC_KEY_Y,          "Y" },
	{ LC_KEY_Z,          "Z" },
	{ LC_KEY_NUMPAD0,    "Numpad 0" },
	{ LC_KEY_NUMPAD1,    "Numpad 1" },
	{ LC_KEY_NUMPAD2,    "Numpad 2" },
	{ LC_KEY_NUMPAD3,    "Numpad 3" },
	{ LC_KEY_NUMPAD4,    "Numpad 4" },
	{ LC_KEY_NUMPAD5,    "Numpad 5" },
	{ LC_KEY_NUMPAD6,    "Numpad 6" },
	{ LC_KEY_NUMPAD7,    "Numpad 7" },
	{ LC_KEY_NUMPAD8,    "Numpad 8" },
	{ LC_KEY_NUMPAD9,    "Numpad 9" },
	{ LC_KEY_MULTIPLY,   "Numpad *" },
	{ LC_KEY_ADD,        "Numpad +" },
	{ LC_KEY_SUBTRACT,   "Numpad -" },
	{ LC_KEY_DECIMAL,    "Numpad ." },
	{ LC_KEY_DIVIDE,     "Numpad /" },
	{ LC_KEY_F1,         "F1" },
	{ LC_KEY_F2,         "F2" },
	{ LC_KEY_F3,         "F3" },
	{ LC_KEY_F4,         "F4" },
	{ LC_KEY_F5,         "F5" },
	{ LC_KEY_F6,         "F6" },
	{ LC_KEY_F7,         "F7" },
	{ LC_KEY_F8,         "F8" },
	{ LC_KEY_F9,         "F9" },
	{ LC_KEY_F10,        "F10" },
	{ LC_KEY_F11,        "F11" },
	{ LC_KEY_F12,        "F12" },
	{ LC_KEY_F13,        "F13" },
	{ LC_KEY_F14,        "F14" },
	{ LC_KEY_F15,        "F15" },
	{ LC_KEY_F16,        "F16" },
	{ LC_KEY_F17,        "F17" },
	{ LC_KEY_F18,        "F18" },
	{ LC_KEY_F19,        "F19" },
	{ LC_KEY_F20,        "F20" },
	{ LC_KEY_F21,        "F21" },
	{ LC_KEY_F22,        "F22" },
	{ LC_KEY_F23,        "F23" },
	{ LC_KEY_F24,        "F24" },
	{ LC_KEY_NUMLOCK,    "Num Lock" },
	{ LC_KEY_SCROLL,     "Scroll" }
};

// Returns a string with the name of the key.
const char* GetKeyName(char Key)
{
	int Count = sizeof(KeyNames)/sizeof(KeyNames[0]);

	for (int i = 0; i < Count; i++)
	{
		if (Key == KeyNames[i].Key)
			return KeyNames[i].Name;
	}

	return NULL;
}

char GetKeyFromName(const char* Name)
{
	int Count = sizeof(KeyNames)/sizeof(KeyNames[0]);

	for (int i = 0; i < Count; i++)
	{
		if (!strcmp(Name, KeyNames[i].Name))
			return KeyNames[i].Key;
	}

	return 0;
}
