#include "Keyboard.h"
#include <luna/CType.h>

static const char table[] = {
    // Function keys
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    // System keys
    '\x1b',
    '\0',
    '\0',
    '\0',
    '\0',
    // Modifier keys
    '\0',
    '\0',
    '\0',
    '\0', // or AltGr on some keyboards
    '\0',
    '\0',
    // Navigation keys
    '\t',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    // Editing keys
    '\b',
    '\n',
    '\0',
    '\x7f',
    '\n',
    // Lock keys
    '\0',
    '\0',
    '\0',
    // Keypad keys
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '.',
    '+',
    '-',
    '*',
    '/',
    // Character keys (depending on keyboard layout), examples in US QWERTY
    '`',  // `
    '1',  // 1
    '2',  // 2
    '3',  // 3
    '4',  // 4
    '5',  // 5
    '6',  // 6
    '7',  // 7
    '8',  // 8
    '9',  // 9
    '0',  // 0
    '-',  // -
    '=',  // =
    'q',  // Q
    'w',  // W
    'e',  // E
    'r',  // R
    't',  // T
    'y',  // Y
    'u',  // U
    'i',  // I
    'o',  // O
    'p',  // P
    '[',  // [
    ']',  // ]
    'a',  // A
    's',  // S
    'd',  // D
    'f',  // F
    'g',  // G
    'h',  // H
    'j',  // J
    'k',  // K
    'l',  // L
    ';',  // ;
    '\'', // '
    '#',  // #
    '\\', // Backslash
    'z',  // Z
    'x',  // X
    'c',  // C
    'v',  // V
    'b',  // B
    'n',  // N
    'm',  // M
    ',',  // ,
    '.',  // .
    '/',  // /
    ' ',  // Space
          // Unknown key
    '\0',
};

static const char shift_table[] = {
    // Function keys
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    // System keys
    '\x1b',
    '\0',
    '\0',
    '\0',
    '\0',
    // Modifier keys
    '\0',
    '\0',
    '\0',
    '\0', // or AltGr on some keyboards
    '\0',
    '\0',
    // Navigation keys
    '\t',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    '\0',
    // Editing keys
    '\b',
    '\n',
    '\0',
    '\x7f',
    '\n',
    // Lock keys
    '\0',
    '\0',
    '\0',
    // Keypad keys
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9',
    '.',
    '+',
    '-',
    '*',
    '/',
    // Character keys (depending on keyboard layout), examples in US QWERTY
    '~', // `
    '!',
    '@',
    '#',
    '$',
    '%',
    '^',
    '&',
    '*',
    '(',
    ')',
    '_',
    '+',
    'Q',
    'W',
    'E',
    'R',
    'T',
    'Y',
    'U',
    'I',
    'O',
    'P',
    '{',
    '}',
    'A',
    'S',
    'D',
    'F',
    'G',
    'H',
    'J',
    'K',
    'L',
    ':',
    '"',
    ' ', // #
    '|', // Backslash
    'Z',
    'X',
    'C',
    'V',
    'B',
    'N',
    'M',
    '<',
    '>',
    '?',
    ' ', // Space
         // Unknown key
    '\0',
};

namespace wind::Keyboard
{
    static bool g_caps_lock = false;
    static bool g_right_shift = false;
    static bool g_left_shift = false;
    static bool g_right_control = false;
    static bool g_left_control = false;
    static bool g_altgr = false;
    static bool g_alt = false;
    static bool g_super = false;

    ui::KeyEventRequest decode_keyboard_event(moon::KeyCode code, bool released)
    {
        ui::KeyEventRequest request;
        request.code = code;
        request.pressed = !released;
        request.modifiers = 0;

        switch (code)
        {
        case moon::K_CapsLock:
            if (!released) { g_caps_lock = !g_caps_lock; }
            break;
        case moon::K_RightShift: g_right_shift = !released; break;
        case moon::K_LeftShift: g_left_shift = !released; break;
        case moon::K_RightControl: g_right_control = !released; break;
        case moon::K_LeftControl: g_left_control = !released; break;
        case moon::K_RightAlt: g_altgr = !released; break;
        case moon::K_LeftAlt: g_alt = !released; break;
        case moon::K_Super: g_super = !released; break;
        default: break;
        }

        if ((g_caps_lock && !(g_left_shift || g_right_shift)) || (g_left_shift || g_right_shift))
        {
            request.modifiers |= ui::Mod_Shift;
        }

        if (g_right_control || g_left_control) request.modifiers |= ui::Mod_Ctrl;

        if (g_alt) request.modifiers |= ui::Mod_Alt;
        if (g_altgr) request.modifiers |= ui::Mod_AltGr;
        if (g_super) request.modifiers |= ui::Mod_Super;

        request.key = table[code];

        if (request.modifiers & ui::Mod_Ctrl)
        {
            char letter;
            if (request.modifiers & ui::Mod_Shift) letter = shift_table[code];
            else
                letter = table[code];
            if (_islower(letter)) letter = (char)_toupper(letter);
            if (_isupper(letter)) letter = letter - 0x40;
            if (letter == '@') letter = letter - 0x40;
            if (letter > 'Z' && letter < '`') letter = letter - 0x40;
            if (letter == '?') letter = 0x7f;
            request.letter = letter;
            return request;
        }

        if (request.modifiers & ui::Mod_Shift) request.letter = shift_table[code];
        else
            request.letter = table[code];

        return request;
    }
}