#![allow(dead_code)]
use alloc::collections::VecDeque;
use lazy_static::lazy_static;
use crate::{prelude::*, sync::SpinLock, task::Task};
lazy_static! {
    pub(crate) static ref GLOBAL_SCHEDULER: SpinLock<GlobalScheduler> =
        SpinLock::new(GlobalScheduler { scheduler: None });
}
pub trait Scheduler: Sync + Send {
    fn enqueue(&self, task: Arc<Task>);
    fn dequeue(&self) -> Option<Arc<Task>>;
    fn should_preempt(&self, task: &Arc<Task>) -> bool;
}
pub struct GlobalScheduler {
    scheduler: Option<&'static dyn Scheduler>,
}
impl GlobalScheduler {
    pub fn new() -> Self {
        Self { scheduler: None }
    }
    pub fn dequeue(&mut self) -> Option<Arc<Task>> {
        self.scheduler.unwrap().dequeue()
    }
    pub fn enqueue(&mut self, task: Arc<Task>) {
        self.scheduler.unwrap().enqueue(task)
    }
    pub fn should_preempt(&self, task: &Arc<Task>) -> bool {
        self.scheduler.unwrap().should_preempt(task)
    }
}
pub fn set_scheduler(scheduler: &'static dyn Scheduler) {
    GLOBAL_SCHEDULER.lock_irq_disabled().scheduler = Some(scheduler);
}
pub fn fetch_task() -> Option<Arc<Task>> {
    GLOBAL_SCHEDULER.lock_irq_disabled().dequeue()
}
pub fn add_task(task: Arc<Task>) {
    GLOBAL_SCHEDULER.lock_irq_disabled().enqueue(task);
}
pub struct FifoScheduler {
    task_queue: SpinLock<VecDeque<Arc<Task>>>,
}
impl FifoScheduler {
    pub const fn new() -> Self {
        FifoScheduler {
            task_queue: SpinLock::new(VecDeque::new()),
        }
    }
}
impl Default for FifoScheduler {
    fn default() -> Self {
        Self::new()
    }
}
impl Scheduler for FifoScheduler {
    fn enqueue(&self, task: Arc<Task>) {
        self.task_queue.lock_irq_disabled().push_back(task);
    }
    fn dequeue(&self) -> Option<Arc<Task>> {
        self.task_queue.lock_irq_disabled().pop_front()
    }
    fn should_preempt(&self, _task: &Arc<Task>) -> bool {
        false
    }
}