
use x86_64::structures::paging::PageTable;
use x86_64::VirtAddr;
use lazy_static::lazy_static;
use x86_64::structures::paging::PageTableFlags;

use crate::log::*;
use crate::memory::format;
use crate::memory::HHDM_RESPONSE;

#[allow(dead_code)]
pub unsafe fn active_level_4_table()
    -> &'static mut PageTable
{
    use x86_64::registers::control::Cr3;

    let (level_4_table_frame, _) = Cr3::read();

    let phys = level_4_table_frame.start_address();
    let virt: VirtAddr = VirtAddr::new(HHDM_RESPONSE.offset() + phys.as_u64());
    let page_table_ptr: *mut PageTable = virt.as_mut_ptr();

    unsafe { &mut *page_table_ptr }
}

lazy_static! {
    pub static ref PML4: &'static mut PageTable = unsafe { active_level_4_table() };
}

// Not used right now, helpful for debugging
#[allow(dead_code)]
pub fn iter_table(level: usize, table: &PageTable) {
    for (i, entry) in table.iter().enumerate() {
        if !entry.is_unused() & entry.flags().contains(PageTableFlags::PRESENT) {
            log_info!("L{} Entry {}: {:?}", level, i, entry);
            if (level > 1) & !entry.flags().contains(PageTableFlags::HUGE_PAGE) {
                let phys = entry.frame().unwrap().start_address();
                let virt = phys.as_u64() + HHDM_RESPONSE.offset();
                let ptr = VirtAddr::new(virt).as_mut_ptr();
                let new_table: &PageTable = unsafe { &*ptr };
                iter_table(level - 1, new_table);
            }
        }
    }
}




/*
    let l4_table = unsafe { active_level_4_table() };

    for (i, entry) in l4_table.iter().enumerate() {
        if !entry.is_unused() {
            log_info!("L4 Entry {}: {:?}", i, entry);

            // get the physical address from the entry and convert it
            let phys = entry.frame().unwrap().start_address();
            let virt = phys.as_u64() + HHDM_RESPONSE.offset();
            let ptr = VirtAddr::new(virt).as_mut_ptr();
            let l3_table: &PageTable = unsafe { &*ptr };

            // print non-empty entries of the level 3 table
            for (i, entry) in l3_table.iter().enumerate() {
                if !entry.is_unused() {
                    log_info!("  L3 Entry {}: {:?}", i, entry);
                }
            }
        }
    }
*/