use std::panic::{UnwindSafe, catch_unwind};
use std::sync::atomic::{AtomicBool, Ordering};
use ncursesw;
use ncursesw::{WINDOW, NCurseswError};
use crate::window::Window;
lazy_static! {
pub(crate) static ref INITSCR_CALLED: AtomicBool = AtomicBool::new(false);
pub(crate) static ref COLOR_STARTED: AtomicBool = AtomicBool::new(false);
pub(crate) static ref INITSCR_ALREADY_CALLED: &'static str = "ncursesw::initscr() has already been called!";
pub(crate) static ref INITSCR_NOT_CALLED: &'static str = "ncursesw::initscr() has not been called!";
}
pub struct NCurses {
handle: WINDOW
}
impl NCurses {
pub fn initscr() -> result!(Self) {
if !INITSCR_CALLED.load(Ordering::SeqCst) {
let handle = ncursesw::initscr()?;
COLOR_STARTED.store(false, Ordering::SeqCst);
INITSCR_CALLED.store(true, Ordering::SeqCst);
Ok(Self { handle })
} else {
Err(NCurseswError::AlreadyInitialized)
}
}
pub fn initial_window(&self) -> Window {
Window::from(self.handle, true)
}
}
impl Drop for NCurses {
fn drop(&mut self) {
match ncursesw::endwin() {
Err(e) => panic!(e.to_string()),
_ => {
COLOR_STARTED.store(false, Ordering::SeqCst);
INITSCR_CALLED.store(false, Ordering::SeqCst);
}
}
}
}
pub fn ncursesw_init<F: FnOnce(&NCurses) -> R + UnwindSafe, R>(user_function: F) -> Result<R, Option<String>> {
let result = catch_unwind(|| {
let ncurses = match NCurses::initscr() {
Err(e) => {
panic!(match e {
NCurseswError::AlreadyInitialized => "NCurses already initialized!",
_ => "ncursesw::initscr() has failed!."
})
},
Ok(ptr) => ptr
};
user_function(&ncurses)
});
result.map_err(|e| match e.downcast_ref::<&str>() {
Some(andstr) => Some(andstr.to_string()),
None => match e.downcast_ref::<String>() {
Some(string) => Some(string.to_string()),
None => None
}
})
}