#include "serial.h"
#include "drawing.h"
#include "mouse.h"
#include "timer.h"
#include "speaker.h"
#include "gdt.h"
#include "idt.h"
#include "heap.h"
#include "pmm.h"
#include "vmm.h"
#include "pic.h"
#include "string.h"
#include "multiboot.h"

uint32_t color_white      = 0x00FFFFFF;
extern uint32_t* fb_ptr;
extern uint32_t* backbuffer;
extern uint32_t screen_width;
extern uint32_t screen_height;
extern uint8_t _binary_assets_logo_bmp_start[];
extern uint8_t _binary_assets_bg_bmp_start[];
extern uint8_t _binary_assets_cursor_bmp_start[];

uint32_t frame_count = 0;
uint32_t last_fps_ticks = 0;
uint32_t current_fps = 0;

extern uint32_t _kernel_end;
uint32_t kernel_end = (uint32_t)&_kernel_end;

void kernel_main(uint32_t mboot_addr, uint32_t magic) {
	serial_init();
	if (magic != MULTIBOOT_BOOTLOADER_MAGIC) {
	    while(1);
	}
	struct multiboot_info* mbi = (struct multiboot_info*)mboot_addr;
	if (!(mbi->flags & (1 << 6))) {
	    while(1);
	}
    gdt_init();
    idt_init();
    pic_remap(32, 40);
    pic_clear_mask(0);
    pic_clear_mask(1);
    pic_clear_mask(2);
    pic_clear_mask(12);
    timer_init(100);
    mouse_init();
    pmm_init(mbi, (uint32_t)&_kernel_end);
    vmm_init();
    kheap_init();

    if (mbi->flags & (1 << 12)) {
	    draw_init(mbi);
	}

    __asm__ __volatile__("sti");

    char fpsbuf[4];
	while (1) {
	    draw_bmp(_binary_assets_bg_bmp_start, 0, 0);
	    draw_cursor_sprite(_binary_assets_cursor_bmp_start, mouse_x, mouse_y);
	    draw_string("FPS: ", 0, 0, color_white);
	    itoa(current_fps, fpsbuf, 10);
	    draw_string(fpsbuf, 40, 0, color_white);

	    flip_buffer();

	    frame_count++;

	    if (system_ticks - last_fps_ticks >= 100) {
	        current_fps = frame_count;
	        frame_count = 0;
	        last_fps_ticks = system_ticks;
	    }
	}
}
