use core::arch::asm;
use lazy_static::*;
use riscv::register::mcause::Trap;
use crate::println;
use crate::sbi::shutdown;
use crate::sync::UPSafeCell;
use crate::trap::TrapContext;

const USER_STACK_SIZE: usize = 4096 * 2;  // 栈大小为8kb
const KERNEL_STACK_SIZE: usize = 4096 * 2;

const MAX_APP_NUM: usize = 16;  // 系统最大支持的运行程序数量

const APP_BASE_ADDRESS: usize = 0x80400000;  // 载入的app的起始的地址
const APP_SIZE_LIMIT: usize = 0x20000;  // app的最大的二进制文件能够使用的大小

// 在此之后  应用使用UserStack, 而内核使用KernelStack, entry.asm设置的64k启动栈不再被使用(首次运行run_next_app时被接管了 mv sp, a0)
// KERNEL_STACK 保存的是 Trap Context

static KERNEL_STACK: [u8; KERNEL_STACK_SIZE] = [0; KERNEL_STACK_SIZE];
static USER_STACK: [u8; USER_STACK_SIZE] = [0; USER_STACK_SIZE];

lazy_static! {
    static ref APP_MANAGER: UPSafeCell<AppManager> = unsafe {
        UPSafeCell::new({
            extern "C" {
                fn _num_app();
            }
            let num_app_ptr = _num_app as usize as *const usize;
            let num_app = num_app_ptr.read_volatile();  // 用户app的总数量

            let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1];  // 创建一个数组, 用来保存每个app的起始位置

            // 得到每个app的起始地址
            let mut app_start_lis: [usize; MAX_APP_NUM + 1] = [0; MAX_APP_NUM + 1];
            let app_start_raw: &[usize] =
                core::slice::from_raw_parts(num_app_ptr.add(1), num_app + 1);
            app_start_lis[..=num_app].copy_from_slice(app_start_raw);

            AppManager{
                num_app,
                current_app: 0,
                app_start_lis
            }
        })
    };
}

// 由build.rs 生成的link_app.S, 根据里面的信息生成的结构体
struct AppManager {
    num_app: usize,  // 用户app数量
    current_app: usize,  // 当前需要执行的第几个app
    app_start_lis: [usize; MAX_APP_NUM + 1],  // 保存了每个app的起始位置, 后面会跳到这里, +1 是因为end的位置也占了一个usize, 需要知道end的位置
}

impl AppManager{
    fn show_app_info(&self){
        println!("[kernel] num_app = {}", self.num_app);
        for i in 0..self.num_app {
            println!(
                "[kernel] app_{} ({:#x}, {:#x})",
                i,
                self.app_start_lis[i],
                self.app_start_lis[i + 1]
            );
        }
    }
}


pub fn init() {
    APP_MANAGER.exclusive_access().show_app_info();
}

pub fn run_next_app() -> ! {
    // 得到下一个需要运行的app的入口地址
    let mut app_manager = APP_MANAGER.exclusive_access();
    let current_app = app_manager.current_app;
    if current_app >= app_manager.num_app {
        shutdown();
    }
    let app_entry_ptr = app_manager.app_start_lis[current_app];
    println!("------------- run_next_app load app {}, {:x}", current_app, app_entry_ptr);
    app_manager.current_app += 1;
    drop(app_manager);


    extern "C" {
        fn __restore(trap_context_ptr: usize);
    }

    unsafe {
        // 得到用户栈的栈顶
        let user_stack_top = USER_STACK.as_ptr() as usize + USER_STACK_SIZE;
        // 得到用户trap的上下文以及寄存器状态
        let user_trap_context = TrapContext::app_init_context(app_entry_ptr, user_stack_top);

        // 把用户trap copy到内核栈
        let kernel_stack_top = KERNEL_STACK.as_ptr() as usize + KERNEL_STACK_SIZE;  // 现在栈顶和栈底都在一个内存位置
        // 为trap context 分配栈空间
        let kernel_trap_context_ptr = (kernel_stack_top - core::mem::size_of::<TrapContext>()) as * mut TrapContext;

        unsafe {
            // 把user_trap_context copy到内核栈顶
            *kernel_trap_context_ptr = user_trap_context;
            // 返回现在的内核栈顶
            __restore(kernel_trap_context_ptr as *const _ as usize);
        }
    }
    panic!("Unreachable in batch::run_current_app!");
}
