#![no_std]
#![no_main]

pub mod boot_services;
pub mod macros;
pub mod memory_allocation_services;
pub mod simple_filesystem_protocol;
pub mod simple_text_output;
pub mod structs;
pub mod system_table;
pub mod types;

use boot_services::BootServicesTable;
use core::{
    ffi::c_void,
    panic::PanicInfo,
    ptr::{null, null_mut},
};
use simple_filesystem_protocol::{FileProtocol, OpenMode, SimpleFileSystemProtocol};
use simple_text_output::SimpleTextOutputProtocol;
use structs::Status;
use system_table::SystemTable;
use types::Handle;

#[no_mangle]
#[export_name = "efi_main"]
extern "efiapi" fn efi_main(image_handle: Handle, system_table_ptr: *mut SystemTable) -> usize {
    if system_table_ptr.is_null() {
        return usize::from(Status::OutOfResources);
    }

    let system_table: &SystemTable = initialize_system_table(system_table_ptr);
    let console_out: Option<&SimpleTextOutputProtocol> = initialize_console_out(system_table);
    let boot_services_table: Option<&BootServicesTable> = initialize_boot_services(system_table);

    if let Some(console_out) = console_out {
        (console_out.clear_screen)(console_out);
        let mut columns: usize = 0;
        let mut rows: usize = 0;
        let mut mode_number: usize = 0;

        (console_out.output_string)(console_out, utf16_string!("my-os").as_ptr());
    }

    //    if let Some(boot_services_table) = boot_services_table {
    //        let mut filesystem_protocol: *mut *mut SimpleFileSystemProtocol = null_mut();
    //        let register = null_mut();
    //
    //        let mut status: Status = (boot_services_table.locate_protocol)(
    //            &SimpleFileSystemProtocol::GUID,
    //            register,
    //            filesystem_protocol as *mut _ as *mut _,
    //        );
    //
    //        let mut root: *mut FileProtocol = core::ptr::null_mut();
    //        unsafe {
    //            status =  ((*(*filesystem_protocol)).open_volume)((*filesystem_protocol), &mut root);
    //            let mut kernel_file: *mut FileProtocol = core::ptr::null_mut();
    //            status = ((root.as_mut().unwrap().open)(root, &mut kernel_file, utf16_string!("\\EFI\\BOOT\\KERNEL.BIN").as_ptr(), OpenMode::FileModeRead, 0));
    //        }
    //    }

    loop {}

    //    if let Some(boot_services_table) = boot_services_table {
    //        (boot_services_table.exit)(image_handle, Status::Success, 0, null());
    //    }

    usize::from(Status::Success) // EFI_SUCCESS
}

fn initialize_system_table(system_table_ptr: *mut SystemTable) -> &'static SystemTable {
    unsafe { &*system_table_ptr }
}

fn initialize_console_out(system_table: &SystemTable) -> Option<&SimpleTextOutputProtocol> {
    let console_out = system_table.console_out;
    if !console_out.is_null() {
        unsafe { Some(&*console_out) }
    } else {
        None
    }
}

fn initialize_boot_services(system_table: &SystemTable) -> Option<&BootServicesTable> {
    if !system_table.boot_services_table_pointer.is_null() {
        unsafe { Some(&*system_table.boot_services_table_pointer) }
    } else {
        None
    }
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}
