#include <grub/text_fb_info.h>
#include "vga.h"
#include "ports.h"
#include <string.h>
#include <stddef.h>
#define xy_to_indx(x,y) ((x+(y*width))*2)
static char* screen;
static int width;
static int height;
static int x;
static int y;
static vga_colors fg_color;
static vga_colors bg_color;
static char* scroll_buf[0xfa0];


static void set_char(int x,int y,char c) {
  screen[xy_to_indx(x,y)]=c;
  screen[xy_to_indx(x,y)+1]=(bg_color<<4)|fg_color;
}

void vga_clear() {
  for (int y=0;y<height;y++) {
    for (int x=0;x<width;x++) {
      set_char(x,y,' ');
    }
  }
}

static void set_cursor(int x,int y) {
  int pos=(x+(y*width));
  port_byte_out(0x3D4,0xF);
  port_byte_out(0x3D5,pos&0xFF);
  port_byte_out(0x3D4,0xE);
  port_byte_out(0x3D5,(pos&0xFF00)>>8);
}

void vga_init(text_fb_info framebuffer_info) {
  x=0;
  y=0;
  fg_color=VGA_WHITE;
  bg_color=VGA_BLACK;
  screen=framebuffer_info.address;
  width=framebuffer_info.width;
  height=framebuffer_info.height;
  port_byte_out(0x3D4,0xA);
  port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xC0)|14);
  port_byte_out(0x3D4,0xB);
  port_byte_out(0x3D5,(port_byte_in(0x3D5)&0xE0)|15);
  set_cursor(0,0);
  vga_clear();
}

void vga_write_string(const char* string) {
  for (size_t i=0;i<strlen(string);i++) {
    char c=string[i];
    if (c=='\n') {
      x=0;
      y++;
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wunused-value"
      for (int i=0;i<67108864;i++) {
        1+1;
      }
      #pragma GCC diagnostic pop
    } else {
      set_char(x,y,c);
      x++;
    }
    if (x==width) {
      x=0;
      y++;
    }
    if (y==height) {
      x=0;
      y=24;
      memcpy(scroll_buf,&screen[xy_to_indx(0,1)],xy_to_indx(0,24));
      vga_clear();
      memcpy(screen,scroll_buf,xy_to_indx(0,25));
    }
  }
  set_cursor(x,y);
}

void vga_backspace() {
  if (x!=0) {
      x--;
      set_char(x,y,' ');
      set_cursor(x,y);
  }
}