pub mod fs;
pub mod mem;
pub mod pid;
pub mod pipe;
pub mod poll;
pub mod pty;
pub mod socket;
pub mod term;
pub mod time;
pub mod timer;

use std::{
    ffi::c_int,
    io,
    os::{fd::RawFd, unix::process::CommandExt},
    process::Command,
    sync::Mutex,
};

pub use mem::{FileMappingImpl, SharedMemoryImpl};
pub use pid::PidFdImpl;
pub use pipe::PipeImpl;
pub use poll::PollImpl;
pub use pty::{open as open_pty, PtyMasterImpl, PtySlaveImpl, TerminalOptionsImpl};
pub use socket::{BorrowedAddressImpl, LocalPacketSocketImpl, OwnedAddressImpl};
pub use term::RawStdinImpl;
pub use timer::TimerFdImpl;

use crate::process::CommandSpawnExt;

fn dummy_sigint() {}

static SIGINT_HANDLER: Mutex<fn()> = Mutex::new(dummy_sigint);

extern "C" fn sigint_proxy(_: c_int) {
    let handler = *SIGINT_HANDLER.lock().unwrap();
    handler();
}

pub fn set_sigint_handler(handler: fn()) {
    *SIGINT_HANDLER.lock().unwrap() = handler;
    unsafe { libc::signal(libc::SIGINT, sigint_proxy as usize) };
}

pub fn send_kill(pid: u32) -> io::Result<()> {
    let res = unsafe { libc::kill(pid as c_int, libc::SIGKILL) };
    if res == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    }
}

pub fn clone_fd(fd: RawFd) -> io::Result<RawFd> {
    let res = unsafe { libc::dup(fd) };
    if res >= 0 {
        Ok(res)
    } else {
        Err(io::Error::last_os_error())
    }
}

impl CommandSpawnExt for Command {
    fn create_process_group(&mut self) -> io::Result<&mut Self> {
        Ok(self.process_group(0))
    }

    fn create_session(&mut self) -> io::Result<&mut Self> {
        // TODO
        Ok(self)
    }
}
