use std::env;
use std::fmt;

/// Radio stations are used to manage signals for a specific channel
///
/// # Examples
/// ```
/// use radiowave::*;
///
/// #[derive(Debug)]
/// enum Channel {
///     AppEvents,
/// }
///
/// #[derive(Debug)]
/// enum Signal {
///     SayCow,
/// }
///
/// fn main() {
///     let station = RadioStation::new(&Channel::AppEvents);
///
///     if station.signal_exists(&Signal::SayCow) == false {
///         println!("Hmmmm... let us say moooooo!");
///
///         station.send_signal(&Signal::SayCow);
///     }
///
///     else {
///         println!("Cancelling signal!");
///
///         station.cancel_signal(&Signal::SayCow);
///     }
/// }
///
/// fn moo() {
///     let station = RadioStation::new(&Channel::AppEvents);
///
///     station.wait_for_signal(&Signal::SayCow);
///
///     println!("Mooooooo!!!");
/// }
/// ```
pub struct RadioStation<C: fmt::Debug> {
    channel: C,
}

impl<C: fmt::Debug> RadioStation<C> {
    /// Create a new radio station
    pub fn new(channel: C) -> Self {
        return Self {
            channel,
        };
    }

    // Private function for getting variable name.
    fn var_name<S: fmt::Debug>(&self, signal: &S) -> String {
        return format!("__SIGNAL_CHANNEL_{:?}_SIGNAL_{:?}__", self.channel, signal);
    }

    /// Broadcast a signal
    pub fn send_signal<S: fmt::Debug>(&self, signal: &S) {
        env::set_var(self.var_name(signal), "");
    }

    /// Pause the code, until the signal has been recieved
    pub fn wait_for_signal<S: fmt::Debug>(&self, signal: &S) {
        loop {
            if self.signal_exists(signal) {
                self.cancel_signal(signal);

                break;
            }
        }
    }

    /// Check to see if a signal is waiting to be listened to
    pub fn signal_exists<S: fmt::Debug>(&self, signal: &S) -> bool {
        return match env::var(self.var_name(signal)) {
            Ok(_) => true,
            Err(_) => false,
        };
    }

    /// Cancel a signal
    pub fn cancel_signal<S: fmt::Debug>(&self, signal: &S) {
        if self.signal_exists(signal) {
            env::remove_var(self.var_name(signal));
        }
    }
}
