use crate::DefaultDebug;
use parking_lot::Once;


static INITIALIZED: Once = Once::new();


pub fn initialize() {
    INITIALIZED.call_once(|| {
        crate::initialize();
        crate::env::setup();
    });
}


pub fn run<F>(run: F)
where
    F: FnOnce() -> (),
{
    initialize();
    run();
}

pub fn run_with_exit_code<F>(run: F)
where
    F: FnOnce() -> i32,
{
    initialize();

    match run() {
        0 => {},
        code => std::process::exit(code),
    }
}

pub fn run_with_result<F, R, E>(run: F)
where
    F: FnOnce() -> Result<R, E>,
{
    run_with_result_and_exit_code(run, -1);
}

pub fn run_with_result_and_exit_code<F, R, E>(run: F, error_exit_code: i32)
where
    F: FnOnce() -> Result<R, E>,
{
    initialize();

    match run() {
        Ok(_) => {},
        Err(e) => {
            if cfg!(debug) {
                println!("application terminated with an error:");
                println!("    {:?}", DefaultDebug(e));
            }

            std::process::exit(error_exit_code);
        },
    }
}