//! The allocator to be implemented by ableOS
//!
//! NOTE: All memory regions are taken from https://wiki.osdev.org/Memory_Map_(x86)

use alloc::alloc::{GlobalAlloc, Layout};
use core::{fmt::Display, ptr::null_mut};

const HEAP_START: usize = 600_000_000;
const BLOCK_SIZE: usize = 1024;
const BLOCK_COUNT: usize = 512;
#[derive(Debug, Clone, Copy)]
pub struct MemoryRegion {
    _start: usize,
    _end: usize,
}
#[derive(Debug, Clone, Copy)]
pub struct AAlloc {
    current_region: usize,
    memory_regions: [Option<MemoryRegion>; 512],
}

impl AAlloc {
    pub fn add_region(&mut self, mem: MemoryRegion) {
        self.memory_regions[self.current_region] = Some(mem);
        self.current_region += 1;
    }

    pub fn intialize() {
        info!("Heap Start: {}", HEAP_START);
        info!("Heap Size:  {}", BLOCK_SIZE * BLOCK_COUNT);
        info!("Heap End:   {}", HEAP_START + BLOCK_SIZE * BLOCK_COUNT);

        let mut aalloc = AAlloc {
            current_region: 0,
            memory_regions: [None; 512],
        };

        aalloc.add_region(MemoryRegion {
            _start: 0x00100000,
            _end: 0x00EFFFFF,
        });
        debug!("{}", aalloc);
    }
}

impl Display for AAlloc {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "AAlloc {{\n\tcurrent_region: {},\n", self.current_region)?;

        for x in 0..self.current_region {
            if let Some(region) = self.memory_regions[x] {
                write!(f, "\tRegion {}: {:?}\n", x, region)?;
            }
        }
        write!(f, "}}")?;
        Ok(())
    }
}

unsafe impl GlobalAlloc for AAlloc {
    unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
        println!("Allocating memory");

        println!("{}", _layout.size());
        println!("{}", _layout.align());

        null_mut()
    }

    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
        panic!("dealloc should be never called")
    }
}