#include "mouse.h"
#include "io.h"

#define PS2_DATA    0x60
#define PS2_STATUS  0x64
#define PS2_COMMAND 0x64

static void ps2_wait_write(void) {
    while (inb(PS2_STATUS) & 0x02);
}

static void ps2_wait_read(void) {
    while (!(inb(PS2_STATUS) & 0x01));
}

static void mouse_write(uint8_t data) {
    ps2_wait_write();
    outb(PS2_COMMAND, 0xD4);
    ps2_wait_write();
    outb(PS2_DATA, data);
}

static uint8_t mouse_read(void) {
    ps2_wait_read();
    return inb(PS2_DATA);
}

void mouse_init(void) {
    uint8_t status;

    ps2_wait_write();
    outb(PS2_COMMAND, 0xA8);
    io_wait();

    ps2_wait_write();
    outb(PS2_COMMAND, 0x20);
    ps2_wait_read();
    status = inb(PS2_DATA) | 2;
    status &= ~0x20;

    ps2_wait_write();
    outb(PS2_COMMAND, 0x60);
    ps2_wait_write();
    outb(PS2_DATA, status);

    mouse_write(0xF6);
    mouse_read();

    mouse_write(0xF4);
    mouse_read();
}

static uint8_t mouse_cycle = 0;
static uint8_t mouse_packet[3];
volatile int mouse_x = 200;
volatile int mouse_y = 200;
volatile int left_click = 0;
volatile int right_click = 0;

void mouse_handler(void) {
    uint8_t status = inb(PS2_STATUS);

    if (!(status & 0x01) || !(status & 0x20)) {
        return;
    }

    mouse_packet[mouse_cycle++] = inb(PS2_DATA);

    if (mouse_cycle == 3) {
        mouse_cycle = 0;

        if (!(mouse_packet[0] & 0x08)) {
            return;
        }

        uint8_t flags = mouse_packet[0];
        int offset_x = (int)mouse_packet[1];
        int offset_y = (int)mouse_packet[2];

        if (flags & 0x10) offset_x |= 0xFFFFFF00;
        if (flags & 0x20) offset_y |= 0xFFFFFF00;

        mouse_x += offset_x;
        mouse_y -= offset_y;

        if (mouse_x < 0)  mouse_x = 0;
        if (mouse_x >= 1024) mouse_x = 1023;
        if (mouse_y < 0)  mouse_y = 0;
        if (mouse_y >= 768) mouse_y = 767;

        left_click  = flags & 0x01;
        right_click = flags & 0x02;
    }
}
