use lazy_static::lazy_static;
use crate::config::MAX_APP_NUM;
use crate::sync::UPSafeCell;
use crate::task::task::{TaskControlBlock, TaskStatus};
use crate::loader::{get_num_app, init_app_cx};
use crate::println;
use crate::task::context::TaskContext;
use crate::task::switch::__switch;

mod context;
mod switch;
mod task;


// 公开到外部的一个全局任务管理器的结构体
pub struct TaskManager {
    num_app: usize,  // app的数量 这个在os运行之后就不会有变化
    inner: UPSafeCell<TaskManagerInner>,  // 这个内部TaskControlBlock 会随着系统运行发生变化
}

impl TaskManager {
    fn run_first_task(&self){
        // 得到下一个需要执行的任务,的上下文 这里我们由于第一次执行, 下一个任务我们指定为0下标的任务即可
        let next_task_context_ptr = {
            let mut inner = self.inner.exclusive_access();
            let task_0 = &mut inner.tasks[0];
            // 修改任务0的状态
            task_0.task_status = TaskStatus::Running;

            &(task_0.task_cx) as *const TaskContext
        };

        // 由于第一次切换, 我们current task context 不存在, 所以我们手动创建一个, 在调用switch的时候
        // 这里调用switch的状态会被保存在unused 这里, 但是一旦程序开始运行, 就开始在内核栈或者用户栈之间切换, 永远
        // 不会走到这里了
        let mut unused = TaskContext::new();

        unsafe {
            __switch(&mut unused as *mut TaskContext, next_task_context_ptr)
        }

        //
        panic!("unreachable in run_first_task!");
    }

    // 停止当前正在运行的任务
    fn mark_current_exit(&self){
        let mut inner = self.inner.exclusive_access();
        let current_task_id = inner.current_task_id;
        let current_task = &mut inner.tasks[current_task_id];
        current_task.task_status = TaskStatus::Exited;
    }

    // 挂起当前任务
    fn mark_current_suspend(&self){
        let mut inner = self.inner.exclusive_access();
        let current_task_id = inner.current_task_id;
        let current_task = &mut inner.tasks[current_task_id];
        current_task.task_status = TaskStatus::Ready;
    }

    // 运行下一个任务
    fn run_next_task(&self){
        if let Some(next_task_id) = self.find_next_task() {
            // 得到当前任务context ptr 以及 下一个任务context的ptr
            let (current_task_ptr,next_task_ptr) = {
                let mut inner = self.inner.exclusive_access();

                // 当前任务id
                let current_task_id = inner.current_task_id;

                // 修改current_task_id 为 下一个任务, 因为一旦到switch就是在运行下一个任务了
                inner.current_task_id = next_task_id;

                // 修改下一个任务的状态
                inner.tasks[next_task_id].task_status = TaskStatus::Running;

                // 得到current的ptr
                let current_task_ptr = &mut inner.tasks[current_task_id].task_cx as *mut TaskContext;

                // 得到需要被切换的下一个任务ptr
                let next_task_ptr = &inner.tasks[next_task_id].task_cx as *const TaskContext;
                (current_task_ptr, next_task_ptr)
            };

            // 开始伟大的切换!
            unsafe {
                __switch(current_task_ptr, next_task_ptr);
            }
        } else {
            panic!("All applications completed!");
        }
    }

    // 找到一个除当前任务之外的 是Ready状态的任务的id
    fn find_next_task(&self) -> Option<usize>{
        let mut inner = self.inner.exclusive_access();
        let current = inner.current_task_id;
        for task_id in current + 1..current + self.num_app + 1 {
            let _tmp_id = task_id % self.num_app;
            if inner.tasks[_tmp_id].task_status == TaskStatus::Ready {
                return Some(_tmp_id)
            }
        }
        None
    }
}


// 不公开的结构体, 有一个MAX_APP_NUM大小的数组, 用来保存TCB, 和当前任务的的TCB的下标
struct TaskManagerInner {
    tasks: [TaskControlBlock; MAX_APP_NUM],
    current_task_id: usize,
}

lazy_static!{
    pub static ref TASK_MANAGER: TaskManager = {
        // 得到app的总数
        let num_app = get_num_app();

        // 初始化内核中的任务列表
        let mut tasks = [
            TaskControlBlock {
                task_cx: TaskContext::new(),
                // UnInit 这个tcb 还没用户应用填充加载
                task_status: TaskStatus::UnInit
            };
            MAX_APP_NUM
        ];

        // 初始化用户的应用对应的 TCB
        for app_idx in 0..num_app {
            // 初始化用户应用的内核栈
            let kernel_app_stack_ptr = init_app_cx(app_idx);

            // 从 初始内核栈的栈顶(保存 trap_context的位置) 创建 任务context
            let task_context = TaskContext::from(kernel_app_stack_ptr);

            // 把内核栈的信息保存到 TCB中
            tasks[app_idx].task_cx = task_context;

            // 初始为 准备好的状态
            tasks[app_idx].task_status = TaskStatus::Ready
        };

        TaskManager {  // 直接返回即可, 所有字段都是sync的, 那这个结构体也是sync
            num_app,
            inner: unsafe {
                UPSafeCell::new(TaskManagerInner {
                    tasks,
                    current_task_id: 0,
                })
            }
        }
    };
}


// 由内核调用, 在main中, 用来 作为执行用户应用的开端
pub fn run_first_task() {
    TASK_MANAGER.run_first_task();
}

// 挂起当前任务, 并运行下一个
pub fn suspend_current_and_run_next(){
    TASK_MANAGER.mark_current_suspend();
    TASK_MANAGER.run_next_task();
}

// 退出当前任务, 并运行下一个
pub fn exit_current_and_run_next(){
    TASK_MANAGER.mark_current_exit();
    TASK_MANAGER.run_next_task();
}
