#include "uitoolkit/UIKeyShortcut.h"
#include "unittest/TestSuite.h"
#include "shell/ShellKeyCodes.h"

static void testInit(void) {
	UIKeyShortcut * shortcut = UIKeyShortcut_single(KEY_CODE_A, 0);
	TestCase_assertPointerNonNULL(shortcut);
	TestCase_assertUIntEqual(shortcut->keyCode, KEY_CODE_A);
	TestCase_assertUIntEqual(shortcut->modifiers, 0);
	TestCase_assertUIntEqual(shortcut->alternateCount, 0);
	TestCase_assertPointerNULL(shortcut->alternates);
	UIKeyShortcut_free(shortcut);
	
	shortcut = UIKeyShortcut_single(KEY_CODE_B, MODIFIER_CONTROL_BIT);
	TestCase_assertPointerNonNULL(shortcut);
	TestCase_assertUIntEqual(shortcut->keyCode, KEY_CODE_B);
	TestCase_assertUIntEqual(shortcut->modifiers, MODIFIER_CONTROL_BIT);
	TestCase_assertUIntEqual(shortcut->alternateCount, 0);
	TestCase_assertPointerNULL(shortcut->alternates);
	UIKeyShortcut_free(shortcut);
	
	shortcut = UIKeyShortcut_multiple(KEY_CODE_A, 0, KEY_CODE_B, MODIFIER_CONTROL_BIT, NULL);
	TestCase_assertPointerNonNULL(shortcut);
	TestCase_assertUIntEqual(shortcut->keyCode, KEY_CODE_A);
	TestCase_assertUIntEqual(shortcut->modifiers, 0);
	TestCase_assertUIntEqual(shortcut->alternateCount, 1);
	TestCase_assertPointerNonNULL(shortcut->alternates);
	TestCase_assertUIntEqual(shortcut->alternates[0].keyCode, KEY_CODE_B);
	TestCase_assertUIntEqual(shortcut->alternates[0].modifiers, MODIFIER_CONTROL_BIT);
	UIKeyShortcut_free(shortcut);
	
	shortcut = UIKeyShortcut_multiple(KEY_CODE_B, MODIFIER_CONTROL_BIT, KEY_CODE_C, 0, KEY_CODE_D, MODIFIER_SHIFT_BIT | MODIFIER_ALT_BIT, NULL);
	TestCase_assertPointerNonNULL(shortcut);
	TestCase_assertUIntEqual(shortcut->keyCode, KEY_CODE_B);
	TestCase_assertUIntEqual(shortcut->modifiers, MODIFIER_CONTROL_BIT);
	TestCase_assertUIntEqual(shortcut->alternateCount, 2);
	TestCase_assertPointerNonNULL(shortcut->alternates);
	TestCase_assertUIntEqual(shortcut->alternates[0].keyCode, KEY_CODE_C);
	TestCase_assertUIntEqual(shortcut->alternates[0].modifiers, 0);
	TestCase_assertUIntEqual(shortcut->alternates[1].keyCode, KEY_CODE_D);
	TestCase_assertUIntEqual(shortcut->alternates[1].modifiers, MODIFIER_SHIFT_BIT | MODIFIER_ALT_BIT);
	UIKeyShortcut_free(shortcut);
}

static void testCopy(void) {
	UIKeyShortcut * shortcut = UIKeyShortcut_none;
	UIKeyShortcut * copy = UIKeyShortcut_copy(shortcut);
	TestCase_assertPointerEqual(copy, UIKeyShortcut_none);
	
	shortcut = UIKeyShortcut_single(KEY_CODE_A, 0);
	copy = UIKeyShortcut_copy(shortcut);
	TestCase_assertPointerNonNULL(copy);
	TestCase_assertPointerUnequal(copy, shortcut);
	TestCase_assertUIntEqual(copy->keyCode, KEY_CODE_A);
	TestCase_assertUIntEqual(copy->modifiers, 0);
	TestCase_assertUIntEqual(copy->alternateCount, 0);
	TestCase_assertPointerNULL(copy->alternates);
	UIKeyShortcut_free(shortcut);
	free(copy);
	
	shortcut = UIKeyShortcut_multiple(KEY_CODE_A, 0, KEY_CODE_B, MODIFIER_CONTROL_BIT, NULL);
	copy = UIKeyShortcut_copy(shortcut);
	TestCase_assertPointerNonNULL(copy);
	TestCase_assertPointerUnequal(copy, shortcut);
	TestCase_assertUIntEqual(copy->keyCode, KEY_CODE_A);
	TestCase_assertUIntEqual(copy->modifiers, 0);
	TestCase_assertUIntEqual(copy->alternateCount, 1);
	TestCase_assertPointerNonNULL(copy->alternates);
	TestCase_assertUIntEqual(copy->alternates[0].keyCode, KEY_CODE_B);
	TestCase_assertUIntEqual(copy->alternates[0].modifiers, MODIFIER_CONTROL_BIT);
	UIKeyShortcut_free(shortcut);
	free(copy);
}

static void testIsMatch(void) {
	UIKeyShortcut * shortcut = UIKeyShortcut_single(KEY_CODE_A, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, MODIFIER_SHIFT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, NULL));
	
	shortcut->keyCode = KEY_CODE_B;
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_SHIFT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, NULL));
	
	shortcut->modifiers = MODIFIER_CONTROL_BIT;
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_CONTROL_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_SHIFT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_CONTROL_BIT | MODIFIER_SHIFT_BIT, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_CONTROL_BIT | MODIFIER_CAPS_LOCK_BIT, NULL));
	UIKeyShortcut_free(shortcut);
	
	shortcut = UIKeyShortcut_multiple(KEY_CODE_A, 0, KEY_CODE_B, MODIFIER_ALT_BIT, NULL);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, MODIFIER_ALT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, MODIFIER_ALT_BIT, NULL));
	UIKeyShortcut_free(shortcut);
	
	shortcut = UIKeyShortcut_multiple(KEY_CODE_C, MODIFIER_SHIFT_BIT, KEY_CODE_D, MODIFIER_ALT_BIT, KEY_CODE_D, MODIFIER_ALT_BIT | MODIFIER_CONTROL_BIT, NULL);
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_C, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_C, MODIFIER_SHIFT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_D, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_D, MODIFIER_ALT_BIT, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_D, MODIFIER_CONTROL_BIT, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_D, MODIFIER_ALT_BIT | MODIFIER_CONTROL_BIT, NULL));
	UIKeyShortcut_free(shortcut);
}

static void testAltGrRemapping(void) {
	UIKeyShortcut * shortcut = UIKeyShortcut_single(KEY_CODE_A, MODIFIER_ALT_BIT);
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, MODIFIER_ALT_BIT, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, MODIFIER_ALTGR_BIT, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, MODIFIER_ALT_BIT | MODIFIER_ALTGR_BIT, NULL));
	UIKeyShortcut_free(shortcut);
}

static void testKeyEquivalents(void) {
	HashTable * keyEquivalents = HashTable_create(sizeof(uint32_t));
	uint32_t equivalent = KEY_CODE_A;
	HashTable_set(keyEquivalents, HashTable_uint32Key(KEY_CODE_B), &equivalent);
	UIKeyShortcut * shortcut = UIKeyShortcut_single(KEY_CODE_A, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_C, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_A, 0, keyEquivalents));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_B, 0, keyEquivalents));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_C, 0, keyEquivalents));
	HashTable_set(keyEquivalents, HashTable_uint32Key(KEY_CODE_C), &equivalent);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_C, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	HashTable_dispose(keyEquivalents);
}

static void testDefaultKeyEquivalents(void) {
	HashTable * keyEquivalents = getDefaultKeyEquivalents();
	UIKeyShortcut * shortcut = UIKeyShortcut_single(KEY_CODE_ENTER, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_ENTER, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_ENTER, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_ENTER, 0, keyEquivalents));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_0, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_0, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_0, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_0, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_0, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_1, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_1, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_1, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_1, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_2, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_2, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_2, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_2, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_3, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_3, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_3, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_3, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_4, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_4, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_4, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_4, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_5, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_5, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_5, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_5, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_6, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_6, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_6, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_6, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_7, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_7, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_7, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_7, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_8, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_8, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_8, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_8, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_9, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_9, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_9, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_NUMPAD_9, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
	shortcut = UIKeyShortcut_single(KEY_CODE_FORWARD_DELETE, 0);
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_FORWARD_DELETE, 0, NULL));
	TestCase_assertBoolFalse(UIKeyShortcut_isMatch(shortcut, KEY_CODE_BACKSPACE, 0, NULL));
	TestCase_assertBoolTrue(UIKeyShortcut_isMatch(shortcut, KEY_CODE_BACKSPACE, 0, keyEquivalents));
	UIKeyShortcut_free(shortcut);
}

TEST_SUITE(UIKeyShortcutTest,
           testInit,
           testCopy,
           testIsMatch,
           testAltGrRemapping,
           testKeyEquivalents,
           testDefaultKeyEquivalents)
