#pragma once

#include "types.h"
#include "acpi/acpi.h"

struct [[gnu::packed]] setup_info {
	u8  setup_sects;
	u16 root_flags;
	u32 syssize;
	u16 ram_size;
	u16 vid_mode;
	u16 root_dev;
	u16 boot_flag;
	u8  jump_instruction;
	u8  jump_offset;
	u32 signature;
	u16 version;
	u32 realmode_switch;
	u16 start_sys_seg;
	u16 kernel_version;
	u8  type_of_loader;
	u8  loadflags;
	u16 setup_move_size;
	u64 code32_start;
	// FUCK THE RAMDISK 
	u32 ramdisk_size;
	u32 bootsect_kludge;
	u16 heap_end_ptr;
	u8  ext_loader_ver;
	u8  ext_loader_type;
	u32 cmd_line_ptr;
	u32 initrd_addr_max;
	u32 kernel_alignment;
	u8  relocatable_kernel;
	u8  min_alignment;
	u16 xloadflags;
	u32 cmdline_size;
	u32 hardware_subarch;
	u64 hardware_subarch_data;
	u32 payload_offset;
	u32 payload_length;
	u64 setup_data;
	u64 pref_address;
	u32 init_size;
	u32 handover_offset;
	u32 kernel_info_offset;
};

struct [[gnu::packed]] screen_info {
	u8  orig_x;
	u8  orig_y;
	u16 ext_mem_k;
	u16 orig_video_page;
	u8  orig_video_mode;
	u8  orig_video_cols;
	u8  flags;
	u8  reserved;
	u16 orig_video_ega_bx;
	u16 reserved2;
	u8  orig_video_lines;
	u8  orig_video_isVGA;
	u16  orig_video_points;

	// linear frame buffer
	u16 lfb_width;
	u16 lfb_height;
	u16 lfb_depth;
	u32 lfb_base;
	u32 lfb_size;
	u16 cl_magic;
	u16 cl_offset;
	u16 lfb_linelength;
	u8  red_size;
	u8  red_pos;
	u8  green_size;
	u8  green_pos;
	u8  blue_size;
	u8  blue_pos;
	u8  reserved_size;
	u8  reserved_pos;
	u16 vesapm_seg;
	u16 vesapm_off;
	u16 pages;
	u16 vesa_attributes;
	u32 capabilities;
	u32 ext_lfb_base;
	u8  reserved3[0x2];
};

struct [[gnu::packed]] apm_bios_info {
	u8 pad[0x14];
};

struct [[gnu::packed]] ist_info {
	u8 pad[0x10];
};

/// \deprecated
struct [[gnu::packed]] sys_desc_table {
	u8 pad[0x10];
};

struct [[gnu::packed]] edid_info {
	u8 pad[0x80];
};

struct [[gnu::packed]] efi_info {
	u32 EfiLoaderSignature;
	u32 EfiSystemTable;
	u32 EfiMemoryDescriptionSize;
	u32 EfiMemoryDescriptionVersion;
	u32 EfiMemoryMap;
	u32 EfiMemoryMapSize;
	u32 EfiSystemTableHigh;
	u32 EfiMemoryMapHigh;
};

struct [[gnu::packed]] e820_entry {
	u64 base;
	u64 length;
	u32 type;
};

struct [[gnu::packed]] edd_info {
	u8 pad;
};

struct [[gnu::packed]] boot_params {
	struct screen_info    screen_info;
	struct apm_bios_info  apm_bios_info;
	u8                    reserved0[0x4];
	void*                 tboot_addr;
	struct ist_info       ist_info;
	struct AcpiRSDP*      acpi_rsdp_addr;
	u8                    reserved1[0x8];
	u8                    hd0_info[0x10];
	u8                    hd1_info[0x10];
	struct sys_desc_table sys_desc_table;
	u8                    olpc_ofw_header[0x10];
	/// ramdisk_image high 32 bits
	u32                   ext_ramdisk_image;
	/// ramdisk_size high 32 bits
	u32                   ext_ramdisk_size;
	/// cmd_line_ptr high 32 bits
	u32                   ext_cmd_line_ptr;
	u8                    reserved2[0x70];
	u32                   cc_blob_address;
	struct edid_info      edid_info;
	struct efi_info       efi_info;
	u32                   alt_mem_k;
	u32                   scratch;
	u8                    e820_entries;
	u8                    eddbuf_entries;
	u8                    edd_mbr_sig_buf_entries;
	u8                    kbd_status;
	u8                    secure_boot;
	u8                    reserved3[0x2];
	u8                    sentinel;
	u8                    reserved4[0xa0]; // setup_info lives here!
	u8                    edd_mbr_sig_buffer[0x40];
	struct e820_entry     e820_table[128];
	u8                    reserved5[0x30];
	u8                    eddbuf[0x1ec];
};

/**
 * Setup info provided by cckernel
 */
extern struct setup_info* BootSetupInfo;

/**
 * Boot params provided by cckernel
 */
extern struct boot_params* BootBootParams;