#![warn(missing_docs)]
use alloc::{vec, vec::Vec};

pub mod capabilities;
pub mod proc;
use proc::{Process, ProcessPermissions, PID};

use self::capabilities::Capabilities;

lazy_static::lazy_static!(

        /// The standard implementation for ableOS
        pub static ref SCHEDULER: spin::Mutex<Scheduler> = spin::Mutex::new(Scheduler::new());

);

// pub struct VirtualMemoryTable {}

/// Scheduler priority model
#[derive(Clone, Copy, Debug)]
pub enum Priority {
    /// Exclusively Kernel space | 20 Timer Tick execution time
    High,
    /// Kernel / User space | 15 Timer Tick execution time
    Medium,
    /// low priority userspace code | 10 Timer Tick execution time
    Low,
}

/// Placeholder
#[derive(Clone, Debug)]
pub struct FileID(u8);

#[derive(Clone, Debug)]
pub enum FileAccessTypes {
    All,
    Some(Vec<FileID>),
    None,
}

///
#[derive(Clone, Debug)]
pub struct Scheduler {
    pub free_pid: PID,

    pub process_exec_time: u64,
    pub list: Vec<Process>,
}

impl Scheduler {
    pub fn new() -> Self {
        Self {
            list: vec![],
            process_exec_time: 0,
            free_pid: PID(0),
        }
    }

    pub fn next_process(&mut self) {
        self.process_exec_time = 0;
        let previous_task = self.list[0].clone();
        self.list.remove(0);
        self.list.push(previous_task);
    }

    /// Create a
    pub fn new_process(&mut self, priority: Priority) {
        // let new_pid = self.free_pid;

        let process = Process {
            id: self.free_pid.clone(),
            capabilities: Capabilities::empty(),
            priority,
        };
        self.free_pid.0 += 1;
        self.list.push(process);
    }
    /// Terminate the process with the matching PID
    pub fn term_process(&mut self, pid: PID) {
        let mut process_index = 0;
        for x in &self.list {
            if x.id == pid {
                self.list.remove(process_index);
                break;
            }
            process_index += 1
        }
    }

    pub fn bump_exec(&mut self) {
        self.process_exec_time += 1;
        use Priority::*;

        if self.list.len() > 0 {
            match (self.process_exec_time, self.list[0].priority) {
                (20, High) => {
                    self.next_process();
                }
                (15, Medium) => {
                    self.next_process();
                }
                (10, Low) => {
                    self.next_process();
                }

                (_, _) => {}
            }
        }
    }
}