#include "keyboard.h"
#include "io.h"

static int is_e0 = 0;
static int shift_pressed = 0;
static int caps_lock_active = 0;

#define SCAN_LSHIFT       0x2A
#define SCAN_RSHIFT       0x36
#define SCAN_CAPS_LOCK    0x3A

#define SCAN_UP           0x48
#define SCAN_DOWN         0x50
#define SCAN_LEFT         0x4B
#define SCAN_RIGHT        0x4D

static const char kbdus_lower[128] = {
    0,  27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',
  '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',
    0,  'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',   0,
 '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/',   0, '*',   0,
  ' ',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0, '-',   0,   0,   0, '+',   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
};

static const char kbdus_upper[128] = {
    0,  27, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',
  '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',
    0,  'A', 's', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',   0,
 '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?',   0, '*',   0,
  ' ',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0, '_',   0,   0,   0, '+',   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
};

void keyboard_init(void) {
    shift_pressed = 0;
    caps_lock_active = 0;
    is_e0 = 0;
}

void keyboard_handler(void) {
    uint8_t status = inb(0x64);

    if (status & 0x20) {
        inb(0x60);
        return;
    }

    if (!(status & 0x01)) return;

    uint8_t scancode = inb(0x60);

    if (scancode == 0xE0) {
        is_e0 = 1;
        return;
    }

    if (scancode & 0x80) {
        uint8_t released_code = scancode & 0x7F;
        if (released_code == SCAN_LSHIFT || released_code == SCAN_RSHIFT) {
            shift_pressed = 0;
        }
        is_e0 = 0;
        return;
    }

    if (is_e0) {
        is_e0 = 0;
        switch (scancode) {
            case SCAN_UP:    break;
            case SCAN_DOWN:  break;
            case SCAN_LEFT:  break;
            case SCAN_RIGHT: break;
        }
        return;
    }

    if (scancode == SCAN_LSHIFT || scancode == SCAN_RSHIFT) {
        shift_pressed = 1;
        return;
    }

    if (scancode == SCAN_CAPS_LOCK) {
        caps_lock_active = !caps_lock_active;
        return;
    }

    if (scancode < 128) {
        char c = 0;
        int use_upper = shift_pressed;
        char base_char = kbdus_lower[scancode];
        int is_alpha = (base_char >= 'a' && base_char <= 'z');

        if (is_alpha && caps_lock_active) use_upper = !use_upper;

        c = (use_upper) ? kbdus_upper[scancode] : kbdus_lower[scancode];

        (void)c;
    }
}
