use std::cell::RefCell;

pub const VERSION:i32 =  110;
pub const D_DEVSTR: &str =	"Development mode ON.";

/// The number of state updates (ticks) to be done per second
pub const TICRATE: i32 = 35;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GameMode {
    Shareware,
    Registered,
    Retail,
    Commercial,
    Indetermined
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum GameState {
    Level,
    Intermission,
    Finale,
    Demoscreen,
}

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum Skill {
    sk_baby = 0,
    sk_easy = 1,
    sk_medium = 2,
    sk_hard = 3,
    sk_nightmare = 4
}

#[derive(Debug)]
pub struct DoomGlobalState {    
    pub devparm: bool,
    pub nomonsters: bool,
    pub respawnparm: bool,
    pub fastparm: bool,
    pub drone: bool,
    pub singletics: bool,
    pub advancedemo: bool,
    pub automapactive: bool,
    pub scaledviewwidth: usize,
    pub viewheight: usize,
    pub inhelpscreens: bool,
    pub paused: bool,
    pub viewactive: bool,
    pub menuactive: bool,
    pub gameaction: bool,
    pub usergame: bool,
    pub autostart: bool,
    pub demorecording: bool,
    pub modifiedgame: bool,
    pub deathmatch: u32,
    pub language: u32,
    pub singledemo: bool,
    pub consoleplayer: u32,
    pub maketic: u32,

    // Buffers
    pub wadfile: [u8; 1024],
    pub mapdir: [u8; 1024],
    pub basedefault: [u8; 1024],
    pub title: [u8; 128],

    // System State
    pub gamemode: GameMode,
    pub startskill: i32,
    pub startepisode: i32,
    pub startmap: i32,
    pub wipegamestate: GameState,
    pub gametic: u32,

    // Lists
    pub wadfiles: Vec<String>,
}

impl Default for DoomGlobalState {
    fn default () -> Self {
        Self {
            devparm: false,
            nomonsters: false,
            respawnparm: false,
            fastparm: false,
            drone: false,
            singletics: false,
            advancedemo: false,
            automapactive: false,
            scaledviewwidth: 0,
            viewheight: 0,
            inhelpscreens: false,
            paused: false,
            viewactive: true,
            menuactive: false,
            gameaction: false, // ga_nothing
            usergame: true,
            autostart: false,
            demorecording: false,
            modifiedgame: false,
            deathmatch: 0,
            language: 0, // english
            singledemo: false,
            consoleplayer: 0,
            maketic: 0,
            wadfile: [0; 1024],
            mapdir: [0; 1024],
            basedefault: [0; 1024],
            title: [0; 128],
            gamemode: GameMode::Indetermined,
            startskill: Skill::sk_medium as i32,
            startepisode: 1,
            startmap: 1,
            wipegamestate: GameState::Demoscreen,
            gametic: 0,
            wadfiles: Vec::new(),
        }
    }
}

thread_local! {
    // We promise not to be naughty and access this from another thread :)
    static GLOBALS: RefCell<DoomGlobalState> = RefCell::new(DoomGlobalState::default()); 
}


pub struct DOOMGLOBALS;

impl DOOMGLOBALS {
    /// Provides mutable access to the globals
    pub fn with_mut<F, R>(f: F) -> R 
    where
        F: FnOnce(&mut DoomGlobalState) -> R 
    {
        GLOBALS.with(|g| f(&mut g.borrow_mut()))
    }

    /// Provides reference only access to the globals
    pub fn with_ref<F, R>(f: F) -> R 
    where
        F: FnOnce(&DoomGlobalState) -> R 
    {
        GLOBALS.with(|g| f(&g.borrow()))
    }
}