#include "keyboard.h"
#include "io.h"
#include "klibc.h"
#include "ringbuffer.h"

#define KEYBOARD_BUFFER_SIZE 128

static ringbuffer_t buf;

int keyboardSetup()
{
    buf = ringbufferCreate(KEYBOARD_BUFFER_SIZE);

    return 0;
}

const char *scancode[128] = {
    /* 0 */ 0,
    /* 1 */ "\e", /* escape */
    /* 2 */ "&",
    /* 3 */ "é",
    /* 4 */ "\"",
    /* 5 */ "'",
    /* 6 */ "(",
    /* 7 */ "-",
    /* 8 */ "è",
    /* 9 */ "_",
    /* 10 */ "ç",
    /* 11 */ "à",
    /* 12 */ ")",
    /* 13 */ "=",
    /* 14 */ "\b", /* Backspace */
    /* 15 */ "\t", /* Tab */
    /* 16 */ "a",
    /* 17 */ "z",
    /* 18 */ "e",
    /* 19 */ "r",
    /* 20 */ "t",
    /* 21 */ "y",
    /* 22 */ "u",
    /* 23 */ "i",
    /* 24 */ "o",
    /* 25 */ "p",
    /* 26 */ "^",
    /* 27 */ "$",
    /* 28 */ "\n",
    /* 29 */ 0, /* left control */
    /* 30 */ "q",
    /* 31 */ "s",
    /* 32 */ "d",
    /* 33 */ "f",
    /* 34 */ "g",
    /* 35 */ "h",
    /* 36 */ "j",
    /* 37 */ "k",
    /* 38 */ "l",
    /* 39 */ "m",
    /* 40 */ "ù",
    /* 41 */ 0, /*²*/
    /* 42 */ 0, /* left shift */
    /* 43 */ "*",
    /* 44 */ "w",
    /* 45 */ "x",
    /* 46 */ "c",
    /* 47 */ "v",
    /* 48 */ "b",
    /* 49 */ "n",
    /* 50 */ ",",
    /* 51 */ ";",
    /* 52 */ ":",
    /* 53 */ "!",
    /* 54 */ 0, /* right shift*/
    /* 55 */ "*",
    /* 56 */ 0, /* left alt*/
    /* 57 */ " ",
    /* 58 */ 0,        /* caps Lock */
    /* 59 */ "\eOP",   /* F1 */
    /* 60 */ "\eOQ",   /* F2 */
    /* 61 */ "\eOR",   /* F3 */
    /* 62 */ "\eOS",   /* F4 */
    /* 63 */ "\e[15~", /* F5 */
    /* 64 */ "\e[17~", /* F6 */
    /* 65 */ "\e[18~", /* F7 */
    /* 66 */ "\e[19~", /* F8 */
    /* 67 */ "\e[20~", /* F9 */
    /* 68 */ "\e[21~", /* F10 */
    /* 69 */ 0,        /* VerrNum*/
    /* 70 */ 0,
    /* 71 */ "7",
    /* 72 */ "8",
    /* 73 */ "9",
    /* 74 */ "-",
    /* 75 */ "4",
    /* 76 */ "5",
    /* 77 */ "6",
    /* 78 */ "+",
    /* 79 */ "1", /* pavnum*/
    /* 80 */ "2",
    /* 81 */ "3",
    /* 82 */ "0",
    /* 83 */ ".",
    /* 84 */ 0,
    /* 85 */ 0,
    /* 86 */ "<",
    /* 87 */ "\e[23~", /* F11 */
    /* 88 */ "\e[24~", /* F12 */
    /* 89 */ 0,
    /* 90 */ 0,
    /* 91 */ 0,
    /* 92 */ 0,
    /* 93 */ 0,
    /* 94 */ 0,
    /* 95 */ 0,
    /* 96 */ 0,
    /* 97 */ 0,
    /* 98 */ 0,
    /* 99 */ 0,
    /* 100 */ 0,
    /* 101 */ 0,
    /* 102 */ 0,
    /* 103 */ 0,
    /* 104 */ 0,
    /* 105 */ 0,
    /* 106 */ 0,
    /* 107 */ 0,
    /* 108 */ 0,
    /* 109 */ 0,
    /* 110 */ 0,
    /* 111 */ 0,
    /* 112 */ 0,
    /* 113 */ 0,
    /* 114 */ 0,
    /* 115 */ 0,
    /* 116 */ 0,
    /* 117 */ 0,
    /* 118 */ 0,
    /* 119 */ 0,
    /* 120 */ 0,
    /* 121 */ 0,
    /* 122 */ 0,
    /* 123 */ 0,
    /* 124 */ 0,
    /* 125 */ 0,
    /* 126 */ 0,
    /* 127 */ 0};

const char *scancode_alt[128] = {
    /* 0 */ 0,
    /* 1 */ "\e",
    /* 2 */ "1",
    /* 3 */ "~",
    /* 4 */ "#",
    /* 5 */ "{",
    /* 6 */ "[",
    /* 7 */ "|",
    /* 8 */ "`",
    /* 9 */ "\\",
    /* 10 */ "^",
    /* 11 */ "@",
    /* 12 */ "]",
    /* 13 */ "}",
    /* 14 */ "\b",   /* Shift-Backspace */
    /* 15 */ "\e[Z", /* Shift-Tab */
    /* 16 */ "A",
    /* 17 */ "Z",
    /* 18 */ "E",
    /* 19 */ "R",
    /* 20 */ "T",
    /* 21 */ "Y",
    /* 22 */ "U",
    /* 23 */ "I",
    /* 24 */ "O",
    /* 25 */ "P",
    /* 26 */ "\"",
    /* 27 */ "£",
    /* 28 */ "\n",
    /* 29 */ 0, /* left control */
    /* 30 */ "Q",
    /* 31 */ "S",
    /* 32 */ "D",
    /* 33 */ "F",
    /* 34 */ "G",
    /* 35 */ "H",
    /* 36 */ "J",
    /* 37 */ "K",
    /* 38 */ "L",
    /* 39 */ "M",
    /* 40 */ "%",
    /* 41 */ 0,
    /* 42 */ 0,
    /* 43 */ "µ",
    /* 44 */ "W",
    /* 45 */ "X",
    /* 46 */ "C",
    /* 47 */ "V",
    /* 48 */ "B",
    /* 49 */ "N",
    /* 50 */ "?",
    /* 51 */ ".",
    /* 52 */ "/",
    /* 53 */ "§",
    /* 54 */ 0,
    /* 55 */ 0,
    /* 56 */ 0,
    /* 57 */ 0,
    /* 58 */ 0,
    /* 59 */ "\eOP",     /* Shift-F1 */
    /* 60 */ "\eOQ",     /* Shift-F2 */
    /* 61 */ "\eOR",     /* Shift-F3 */
    /* 62 */ "\eOS",     /* Shift-F4 */
    /* 63 */ "\e[15;2~", /* Shift-F5 */
    /* 64 */ "\e[17;2~", /* Shift-F6 */
    /* 65 */ "\e[18;2~", /* Shift-F7 */
    /* 66 */ "\e[19;2~", /* Shift-F8 */
    /* 67 */ "\e[20:2~", /* Shift-F9 */
    /* 68 */ "\e[21:2~", /* Shift-F10 */
    /* 69 */ 0,
    /* 70 */ 0,
    /* 71 */ 0,
    /* 72 */ 0,
    /* 73 */ 0,
    /* 74 */ 0,
    /* 75 */ 0,
    /* 76 */ 0,
    /* 77 */ 0,
    /* 78 */ 0,
    /* 79 */ 0,
    /* 80 */ 0,
    /* 81 */ 0,
    /* 82 */ 0,
    /* 83 */ 0,
    /* 84 */ 0,
    /* 85 */ 0,
    /* 86 */ ">",
    /* 87 */ "\e[23;2~", /* Shift-F11 */
    /* 88 */ "\e[24;2~", /* Shift-F12 */
    /* 89 */ 0,
    /* 90 */ 0,
    /* 91 */ 0,
    /* 92 */ 0,
    /* 93 */ 0,
    /* 94 */ 0,
    /* 95 */ 0,
    /* 96 */ 0,
    /* 97 */ 0,
    /* 98 */ 0,
    /* 99 */ 0,
    /* 100 */ 0,
    /* 101 */ 0,
    /* 102 */ 0,
    /* 103 */ 0,
    /* 104 */ 0,
    /* 105 */ 0,
    /* 106 */ 0,
    /* 107 */ 0,
    /* 108 */ 0,
    /* 109 */ 0,
    /* 110 */ 0,
    /* 111 */ 0,
    /* 112 */ 0,
    /* 113 */ 0,
    /* 114 */ 0,
    /* 115 */ 0,
    /* 116 */ 0,
    /* 117 */ 0,
    /* 118 */ 0,
    /* 119 */ 0,
    /* 120 */ 0,
    /* 121 */ 0,
    /* 122 */ 0,
    /* 123 */ 0,
    /* 124 */ 0,
    /* 125 */ 0,
    /* 126 */ 0,
    /* 127 */ 0};
const char *scancode_shift[128] = {
    /* 0 */ 0,
    /* 1 */ "\e",
    /* 2 */ "1",
    /* 3 */ "2",
    /* 4 */ "3",
    /* 5 */ "4",
    /* 6 */ "5",
    /* 7 */ "6",
    /* 8 */ "7",
    /* 9 */ "8",
    /* 10 */ "9",
    /* 11 */ "0",
    /* 12 */ "°",
    /* 13 */ "+",
    /* 14 */ "\b",   /* Shift-Backspace */
    /* 15 */ "\e[Z", /* Shift-Tab */
    /* 16 */ "A",
    /* 17 */ "Z",
    /* 18 */ "E",
    /* 19 */ "R",
    /* 20 */ "T",
    /* 21 */ "Y",
    /* 22 */ "U",
    /* 23 */ "I",
    /* 24 */ "O",
    /* 25 */ "P",
    /* 26 */ "\"",
    /* 27 */ "£",
    /* 28 */ "\n",
    /* 29 */ 0, /* left control */
    /* 30 */ "Q",
    /* 31 */ "S",
    /* 32 */ "D",
    /* 33 */ "F",
    /* 34 */ "G",
    /* 35 */ "H",
    /* 36 */ "J",
    /* 37 */ "K",
    /* 38 */ "L",
    /* 39 */ "M",
    /* 40 */ "%",
    /* 41 */ 0,
    /* 42 */ 0,
    /* 43 */ "µ",
    /* 44 */ "W",
    /* 45 */ "X",
    /* 46 */ "C",
    /* 47 */ "V",
    /* 48 */ "B",
    /* 49 */ "N",
    /* 50 */ "?",
    /* 51 */ ".",
    /* 52 */ "/",
    /* 53 */ "§",
    /* 54 */ 0,
    /* 55 */ 0,
    /* 56 */ 0,
    /* 57 */ 0,
    /* 58 */ 0,
    /* 59 */ "\eOP",     /* Shift-F1 */
    /* 60 */ "\eOQ",     /* Shift-F2 */
    /* 61 */ "\eOR",     /* Shift-F3 */
    /* 62 */ "\eOS",     /* Shift-F4 */
    /* 63 */ "\e[15;2~", /* Shift-F5 */
    /* 64 */ "\e[17;2~", /* Shift-F6 */
    /* 65 */ "\e[18;2~", /* Shift-F7 */
    /* 66 */ "\e[19;2~", /* Shift-F8 */
    /* 67 */ "\e[20:2~", /* Shift-F9 */
    /* 68 */ "\e[21:2~", /* Shift-F10 */
    /* 69 */ 0,
    /* 70 */ 0,
    /* 71 */ 0,
    /* 72 */ 0,
    /* 73 */ 0,
    /* 74 */ 0,
    /* 75 */ 0,
    /* 76 */ 0,
    /* 77 */ 0,
    /* 78 */ 0,
    /* 79 */ 0,
    /* 80 */ 0,
    /* 81 */ 0,
    /* 82 */ 0,
    /* 83 */ 0,
    /* 84 */ 0,
    /* 85 */ 0,
    /* 86 */ ">",
    /* 87 */ "\e[23;2~", /* Shift-F11 */
    /* 88 */ "\e[24;2~", /* Shift-F12 */
    /* 89 */ 0,
    /* 90 */ 0,
    /* 91 */ 0,
    /* 92 */ 0,
    /* 93 */ 0,
    /* 94 */ 0,
    /* 95 */ 0,
    /* 96 */ 0,
    /* 97 */ 0,
    /* 98 */ 0,
    /* 99 */ 0,
    /* 100 */ 0,
    /* 101 */ 0,
    /* 102 */ 0,
    /* 103 */ 0,
    /* 104 */ 0,
    /* 105 */ 0,
    /* 106 */ 0,
    /* 107 */ 0,
    /* 108 */ 0,
    /* 109 */ 0,
    /* 110 */ 0,
    /* 111 */ 0,
    /* 112 */ 0,
    /* 113 */ 0,
    /* 114 */ 0,
    /* 115 */ 0,
    /* 116 */ 0,
    /* 117 */ 0,
    /* 118 */ 0,
    /* 119 */ 0,
    /* 120 */ 0,
    /* 121 */ 0,
    /* 122 */ 0,
    /* 123 */ 0,
    /* 124 */ 0,
    /* 125 */ 0,
    /* 126 */ 0,
    /* 127 */ 0};

void keyboard_do_irq()
{
    static int lshift   = 0;
    static int rshift   = 0;
    static int capslock = 0;
    static int alt      = 0;
    static int isExt    = 0;
    unsigned char c     = inb(KEYBOARD_DATA_PORT);
    const char *key     = NULL;
    if (c > 0) {
        if (c == 0xE0) { // non printable such as page up/down ... See
                         // https://wiki.osdev.org/Keyboard
            isExt = 1;
        } else if (isExt) {
            isExt = 0;
            return;
        }
        if (c < BREAK_CODE) {
            switch (c) {
                case 42:
                    lshift = 1;
                    break;
                case 54:
                    rshift = 1;
                    break;
                case 56:
                    alt = 1;
                    break;
                case 58:
                    capslock = 1 - capslock;
                    break;
                default:
                    if ((lshift || rshift) ^ capslock) {
                        key = scancode_shift[(int)c];
                    } else if (alt) {
                        key = scancode_alt[(int)c];
                    } else {
                        key = scancode[(int)c];
                    }
            }
        } else {
            c = c - BREAK_CODE;
            switch (c) {
                case 42:
                    lshift = 0;
                    break;
                case 54:
                    rshift = 0;
                    break;
                case 56:
                    alt = 0;
                    break;
            }
        }
    }

    if (key){
        putc(*key);
        ringbufferEnqueue(buf, *key);
    }
}

char keyboardRead()
{
    uint8_t c;
    if (ringbufferDequeue(buf, &c)){
        return c;
    }

    return 0;
}