/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Namaste

Copyright (C) 2019, 2021-2025  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2021-2025".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

//! # Namaste on Linux

#![cfg(any(target_os="android", target_os="l4re", target_os="linux"))]
#![doc(cfg(any(target_os="android", target_os="l4re", target_os="linux")))]

use {
    core::sync::atomic::AtomicBool,
    alloc::sync::Arc,
    std::os::unix::net::{SocketAddr, UnixListener},
    crate::Result,
    self::either::Either,
};

#[cfg(not(target_os="android"))]
use std::os::linux::net::SocketAddrExt;

#[cfg(target_os="android")]
use std::os::android::net::SocketAddrExt;

mod cmd;
mod either;
mod server_proc;

pub (crate) use self::cmd::*;

/// # Stream ID
pub (crate) const STREAM_ID: &[u8] = &[
    0x1e, 0x64, 0x83, 0x1b, 0xfb, 0x9a, 0x2d, 0x3d, 0x58, 0x80, 0x8c, 0xc2, 0xfd, 0xd3, 0x92, 0x23, 0x48, 0x5f, 0xe1, 0x8d, 0xdb, 0x80, 0x62,
    0x16, 0xe7, 0xd7, 0xa7, 0x3b, 0x9a, 0x27, 0x0c, 0xdd, 0xfe, 0x4b, 0x51, 0x92, 0xd0, 0xb2, 0x0c, 0xb5, 0xb8, 0x58, 0x95, 0x24, 0x3b, 0xec,
    0x75, 0xb5, 0x08, 0x1e, 0x27, 0x85, 0x0b, 0xd7, 0xcb, 0xb4, 0x0c, 0xbd, 0x30, 0x6d, 0x62, 0x5e, 0x0c, 0xcc,
];

/// # Namaste on Linux
#[derive(Debug)]
pub struct Namaste {
    data: Either<UnixListener, Arc<AtomicBool>>,
}

impl Namaste {

    /// # Makes new instance using abstract Linux socket
    pub (crate) fn make<B>(id: B, clonable: Option<bool>) -> Result<Self> where B: AsRef<[u8]> {
        Self::make_from_unix_listener(UnixListener::bind_addr(&SocketAddr::from_abstract_name(&id)?)?, clonable)
    }

    /// # Makes new instance using `UnixListener`
    pub (crate) fn make_from_unix_listener(unix_listener: UnixListener, clonable: Option<bool>) -> Result<Self> {
        match clonable {
            None => Ok(Self {
                data: Either::Some(unix_listener),
            }),
            Some(clonable) => {
                let stop_flag = Arc::new(AtomicBool::new(false));
                server_proc::add(unix_listener, clonable, stop_flag.clone())?;
                Ok(Self {
                    data: Either::Other(stop_flag),
                })
            },
        }
    }

}

impl Drop for Namaste {

    fn drop(&mut self) {
        if let Either::Other(stop_flag) = &self.data {
            stop_flag.store(true, server_proc::ATOMIC_ORDERING);
        }
    }

}
