#include "types.h"
#include "screen.h"

extern void itoa (char *buf, int base, int d);

Screen Console;

Screen::Screen(void) : xpos(0), ypos(0) {
    vram = (uint8*)VIDEO;
    clear();
}

void Screen::clear(void) {
    for (int i = 0; i < COLUMNS * LINES * 2; i++) {
        vram[i] = 0;
    }
    xpos = ypos = 0;
}

void Screen::putchar(int c) {
    if (c != '\n' && c != '\r') {
        vram[(xpos + ypos * COLUMNS) * 2]     = c & 0xFF;
        vram[(xpos + ypos * COLUMNS) * 2 + 1] = ATTRIBUTE;
        ++xpos;
    }

    if (c == '\n' || c == '\r' || xpos >= COLUMNS) {
        xpos = 0;
        ypos++;
        if (ypos >= LINES) {
            ypos--;
            scroll();
        }
        return;
    }
}

void Screen::scroll(void) {
    for (int i = 0; i < COLUMNS * (LINES - 1) * 2; i++) {
        vram[i] = vram[i + COLUMNS * 2];
    }
    for (int i = COLUMNS * (LINES - 1) * 2; i < COLUMNS * LINES * 2; i++) {
        vram[i] = 0;
    }
}

void Screen::printf(const char* format, ...) {
    char** arg = (char**)&format;
    int c;
    char buf[20];

    ++arg; // point to args next to fmt

    while ((c = *format++) != 0) {
        if (c != '%') {
            putchar(c);
        } else {
            char* p;
            c = *format++;
            switch (c) {
            case 'd':
            case 'u':
            case 'x':
                itoa(buf, c, *((int*)arg++));
                p = buf;
                goto string;
                break;

            case 's':
                p = *arg++;
                if (p == 0) p = "(null)";

            string:
                while (*p != 0) putchar(*p++);
                break;
            default:
                putchar(*((int*)arg++));
                break;
            }
        }
    }
}

