#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "Terminal.h"

volatile uint16_t* VgaBuffer = (uint16_t*)0xB8000;
const int VgaCols = 80;
const int VgaRows = 25;
#define VGA_EXTENT 80 * 25
 
int TerminalCol = 0;
int TerminalRow = 0;
uint8_t TerminalColor = 0x0F;

void InitTerminal(){
	for (int col = 0; col < VgaRows; col ++)
	{
		for (int row = 0; row < VgaRows; row ++)
		{
			const size_t index = (VgaCols * row) + col;
			VgaBuffer[index] = ((uint16_t)TerminalColor << 8) | ' ';
		}
	}
}

void TerminalSetColor(uint8_t Color){
	TerminalColor = Color;
}

void TerminalPutc(char c){
	switch (c)
	{
	case '\n':
		{
			TerminalCol = 0;
			TerminalRow ++;
			break;
		}
 
	default:
		{
			const size_t index = (VgaCols * TerminalRow) + TerminalCol;
			VgaBuffer[index] = ((uint16_t)TerminalColor << 8) | c;
			TerminalCol ++;
			break;
		}
	}
	if (TerminalCol >= VgaCols)
	{
		TerminalCol = 0;
		TerminalRow ++;
	}
	if (TerminalRow >= VgaRows)
	{
		TerminalCol = 0;
		TerminalRow = 0;
	}
	Advance();
}

void TerminalPrint(const char* str){
	for (size_t i = 0; str[i] != '\0'; i ++)
		TerminalPutc(str[i]);
}

uint16_t GetPos(){
    uint16_t position = 0;

    outb(CURSOR_PORT_COMMAND, 0x0F);
    position |= inb(CURSOR_PORT_DATA);

    outb(CURSOR_PORT_COMMAND, 0x0E);
    position |= inb(CURSOR_PORT_DATA) << 8;

    return position;
}

void Advance(){
    uint16_t pos = GetPos();
    pos++;

    if (pos >= VGA_EXTENT){
        pos = VGA_EXTENT - 1;
    }

    outb(CURSOR_PORT_COMMAND, 0x0F);
    outb(CURSOR_PORT_DATA, (uint8_t) (pos & 0xFF));

    outb(CURSOR_PORT_COMMAND, 0x0E);
    outb(CURSOR_PORT_DATA, (uint8_t) ((pos >> 8) & 0xFF));
}

