Documentation
use refs::{ToWeak, Weak};
use std::{
    cell::RefCell,
    fmt::{Debug, Formatter},
};

pub struct Event<T = ()> {
    #[allow(clippy::type_complexity)]
    subscriber: RefCell<Option<Box<dyn FnMut(T) + 'static>>>,
}

impl<T: 'static> Event<T> {
    pub fn sub(&self, mut action: impl FnMut() + 'static) {
        self.subscriber.replace(Some(Box::new(move |_| {
            action();
        })));
    }

    pub fn val(&self, action: impl FnMut(T) + 'static) {
        self.subscriber.replace(Some(Box::new(action)));
    }

    pub fn set<Obj: 'static>(&self, obj: &Obj, mut action: impl FnMut(Weak<Obj>, T) + 'static) {
        let weak = obj.weak();
        self.subscriber.replace(Some(Box::new(move |value| {
            action(weak, value);
        })));
    }

    pub fn trigger(&self, value: T) {
        let mut sub = self.subscriber.borrow_mut();
        if sub.is_none() {
            return;
        }
        (sub.as_mut().unwrap())(value);
    }

    pub fn remove_subscribers(&self) {
        self.subscriber.replace(Default::default());
    }
}

impl<T> Default for Event<T> {
    fn default() -> Self {
        Self {
            subscriber: Default::default(),
        }
    }
}

impl<T> Debug for Event<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "Event<{}>", std::any::type_name::<T>(),)
    }
}