pub mod fs;
pub mod i2c;
pub mod mem;
pub mod path;
pub mod pid;
pub mod pipe;
pub mod poll;
pub mod pty;
pub mod serial;
pub mod socket;
pub mod spi;
pub mod term;
pub mod time;
pub mod timer;

use runtime::rt::process::Signal;
use std::{
    io,
    os::{
        fd::RawFd,
        yggdrasil::{
            process::CommandExt,
            signal::{SignalHandler, set_signal_handler},
        },
    },
    process::Command,
    sync::atomic::{AtomicUsize, Ordering},
};

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

use crate::process::CommandSpawnExt;

pub fn set_sigint_handler(handler: fn()) {
    static HANDLER: AtomicUsize = AtomicUsize::new(0);

    fn handler_stub(_signal: Signal) {
        let handler = HANDLER.load(Ordering::Acquire);

        if handler != 0 {
            let handler: fn() = unsafe { core::mem::transmute(handler) };
            handler();
        }
    }

    HANDLER.store(handler as usize, Ordering::Release);

    let _ = set_signal_handler(Signal::Interrupted, SignalHandler::Function(handler_stub));
}

pub fn send_kill(pid: u32) -> io::Result<()> {
    use runtime::rt::{
        process::{ProcessId, Signal},
        sys as syscall,
    };

    let target = unsafe { ProcessId::from_raw(pid) };
    unsafe { syscall::send_signal(target, Signal::Killed) }.map_err(io::Error::from)?;
    Ok(())
}

pub fn clone_fd(fd: RawFd) -> io::Result<RawFd> {
    let fd = unsafe { runtime::rt::sys::clone_fd(fd, None) }?;
    Ok(fd)
}

impl CommandSpawnExt for Command {
    fn create_process_group(&mut self) -> io::Result<&mut Self> {
        let group = unsafe { runtime::rt::sys::create_process_group() };
        Ok(self.process_group(group))
    }

    fn create_session(&mut self) -> io::Result<&mut Self> {
        Ok(unsafe { self.gain_terminal(0) })
    }
}
