#include <shade/platform/drivers/vga_text_mode.h>
#include <shade/platform/ports.h>
#include <strings.h>

int row = 0;
int col = 0;
char color = PRINT_COLOR_WHITE | PRINT_COLOR_BLACK << 4;

cansid_state state;

void clear_row(int row) {
    struct Char* buffer = (struct Char*) 0xb8000;

    struct Char empty = (struct Char) {
        character: ' ',
        color: color,
    };

    for (int x = 0; x < NUM_COLS; x++) {
        buffer[x + NUM_COLS * row] = empty;
    }
    set_cursor_pos(col, row);
}

void clear_all() {
    for (int i = 0; i < NUM_ROWS; i++) {
        clear_row(i);
    }
    set_cursor_pos(col, row);
}

void print_newline() {
    struct Char* buffer = (struct Char*) 0xb8000;

    col = 0;

    if (row < NUM_ROWS - 1) {
        row++;
        return;
    }

    for (int row = 1; row < NUM_ROWS; row++) {
        for (int col = 0; col < NUM_COLS; col++) {
            struct Char character = buffer[col + NUM_COLS * row];
            buffer[col + NUM_COLS * (row - 1)] = character;
        }
    }

    clear_row(NUM_COLS - 1);
    set_cursor_pos(col, row);
}


void print_char(char character) {
    color_char ch = cansid_process(&state, character);
    color = ch.style;
    _print_char(ch.ascii);
}

void _print_char(char character) {
    struct Char* buffer = (struct Char*) 0xb8000;

    if (character == 0) {
        return;
    }

    if (character == '\n') {
        print_newline();
        return;
    }

    if (col > NUM_COLS) {
        print_newline();
    }

    struct Char cr = (struct Char) {
        character: character,
        color: color,
    };
    buffer[col + NUM_COLS * row] = cr;

    col++;
    set_cursor_pos(col, row);
}

void print_str(char* str) {
    for (int i = 0; 1; i++) {
        char character = (char) str[i];

        if (character == '\0') {
            return;
        }

        print_char(character);
    }
}

void print_set_color(char foreground, char background) {
    color = foreground + (background << 4);
}

void set_cursor_pos(int col, int row) {
   int offset = col + NUM_COLS * row;
   outb(REG_SCREEN_CTRL, 14);
   outb(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
   outb(REG_SCREEN_CTRL, 15);
   outb(REG_SCREEN_DATA, (unsigned char)(offset & 0xff)); 
}

void kernel_msg_ok(char* msg) {
	char ok_p1[] = "[ ";
	char ok_p2[] = "OK ";
	char ok_p3[] = "] ";
	
	print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
	print_str(ok_p1);
	
	print_set_color(PRINT_COLOR_GREEN, PRINT_COLOR_BLACK);
	print_str(ok_p2);
	
	print_set_color(PRINT_COLOR_WHITE, PRINT_COLOR_BLACK);
	print_str(ok_p3);
	print_str(msg);
}

void init_state() {
    state = cansid_init();
}