#include "print.h"
#include "stream.h"
#include "tasks.h"

#include <stdarg.h>

#include <drivers/vga/vga.h>
#include <drivers/console/console.h>

spinlock_t kwrite_lock = {0};

extern psf_font_t* kfont;

static char* hex_chars = "0123456789abcdef";

static void kprint(const char *str) {
    while (*str) {
        console_putchar(*str);
        str++;
    }
}

static void kputd(int d) {
    if (d == 0) {
        console_putchar('0');
        return;
    }
    char buffer[12];
    int i = 0;
    while (d > 0) {
        buffer[i++] = '0' + (d % 10);
        d /= 10;
    }
    for (int j = i - 1; j >= 0; j--) {
        console_putchar(buffer[j]);
    }
}

static void kputx(unsigned int x) {
    if (x == 0) {
        console_putchar('0');
        return;
    }
    char buffer[8];
    
    int i = 0;
    while (x > 0) {
        buffer[i++] = hex_chars[x & 0xF];
        x >>= 4;
    }
    for (int j = i - 1; j >= 0; j--) {
        console_putchar(buffer[j]);
    }
}

void kputc(const char c) {
    spin_lock(&kwrite_lock);
    console_putchar(c);
    spin_unlock(&kwrite_lock);
}

void kprintf(const char* fmt, ...) {
    spin_lock(&kwrite_lock);
    va_list args;
    va_start(args, fmt);
    
    while (*fmt) {
        if (*fmt == '%') {
            fmt++;
            switch (*fmt) {
                case 's': {
                    const char* str = va_arg(args, const char*);
                    kprint(str);
                    break;
                }
                case 'd': {
                    int d = va_arg(args, int);
                    kputd(d);
                    break;
                }
                case 'x': {
                    unsigned int x = va_arg(args, unsigned int);
                    kputx(x);
                    break;
                }
                case 'c': {
                    int c = va_arg(args, int);
                    console_putchar((char)c);
                    break;
                }
                case '%':
                    console_putchar('%');
                    break;
                default:
                    console_putchar('%');
                    console_putchar(*fmt);
                    break;
            }
            fmt++;
        } else {
            console_putchar(*fmt);
            fmt++;
        }
    }
    
    va_end(args);
    spin_unlock(&kwrite_lock);
}