use std::{
any::{Any, TypeId},
cell::RefCell,
collections::{BTreeMap, HashMap},
fmt,
rc::Rc,
};
use crate::{
foundation::patterns::observer::BaseObserver,
prelude::{
Interest, Mediator, MediatorRegistry, Notification, NotifyContext, Observer, Singleton,
View,
},
};
pub struct BaseView<Body>
where
Body: fmt::Debug + 'static,
{
mediator_map: RefCell<BTreeMap<TypeId, Rc<dyn Any>>>,
observer_map: RefCell<HashMap<Interest, Vec<Rc<dyn Observer<Body>>>>>,
}
unsafe impl<Body> std::marker::Send for BaseView<Body> where Body: fmt::Debug + 'static {}
unsafe impl<Body> std::marker::Sync for BaseView<Body> where Body: fmt::Debug + 'static {}
impl<Body> BaseView<Body>
where
Body: fmt::Debug + 'static,
{
pub fn new() -> Self {
Self {
mediator_map: RefCell::new(BTreeMap::new()),
observer_map: RefCell::new(HashMap::new()),
}
}
}
impl<Body> Singleton for BaseView<Body>
where
Body: fmt::Debug + 'static,
{
fn global() -> &'static Self {
todo!("you have to reimplement the view for your purposes")
}
}
impl<Body> View<Body> for BaseView<Body>
where
Body: fmt::Debug + 'static,
{
fn notify(&self, note: Rc<dyn Notification<Body>>) {
let observers = self.observer_map.borrow().get(¬e.interest()).cloned();
if let Some(observers) = observers {
for observer in observers.iter() {
log::info!("Notify observer {:?} for {:?}", observer, note.interest());
observer.notify(note.clone());
}
}
}
fn register_observer(&self, interest: Interest, observer: Rc<dyn Observer<Body>>) {
let mut observer_map = self.observer_map.borrow_mut();
observer_map.entry(interest).or_insert_with(Vec::new);
if let Some(observers) = observer_map.get_mut(&interest) {
observers.push(observer)
}
}
fn remove_observer(&self, interest: &Interest, context: &Rc<dyn NotifyContext>) {
let mut observer_map = self.observer_map.borrow_mut();
if let Some(observers) = observer_map.remove(interest).as_mut() {
for (idx, observer) in observers.iter().enumerate() {
if observer.compare_context(context) {
observers.remove(idx);
break;
}
}
}
}
}
impl<Body> MediatorRegistry<Body> for BaseView<Body>
where
Body: fmt::Debug + 'static,
{
fn register_mediator<M: Mediator<Body>>(&self, mediator: Rc<M>) {
log::info!("Register Mediator [BaseView] {:?}", mediator);
let mut mediator_map = self.mediator_map.borrow_mut();
let type_id = TypeId::of::<M>();
if mediator_map.contains_key(&type_id) {
return;
}
mediator_map.insert(type_id, mediator.clone());
let interests = mediator.list_notification_interests();
if !interests.is_empty() {
let mediator = mediator.clone();
let context = mediator.clone();
let observer = Rc::new(BaseObserver::new(
Box::new(move |notification| {
log::info!("Observer notify {:?}", notification);
mediator.handle_notification(notification.clone())
}),
context,
));
for interest in interests.iter() {
self.register_observer(*interest, observer.clone());
}
}
mediator.on_register();
}
fn retrieve_mediator<M: Mediator<Body>>(&self) -> Option<Rc<M>> {
let type_id = TypeId::of::<M>();
match self.mediator_map.borrow().get(&type_id) {
Some(item) => match item.clone().downcast::<M>() {
Ok(mediator) => Some(mediator),
Err(_) => {
log::error!("Something wrong with proxy storage");
None
}
},
None => None,
}
}
fn remove_mediator<M: Mediator<Body>>(&self) -> Option<Rc<M>> {
let type_id = TypeId::of::<M>();
self.mediator_map
.borrow_mut()
.remove(&type_id)
.map(|mediator| {
match mediator.downcast::<M>() {
Ok(mediator) => {
let interests = mediator.list_notification_interests();
for interest in interests.iter() {
let mut observer_map = self.observer_map.borrow_mut();
let context = mediator.id();
if let Some(observers) = observer_map.remove(interest).as_mut() {
for (idx, observer) in observers.iter().enumerate() {
if observer.context().id() == context {
observers.remove(idx);
break;
}
}
}
}
mediator.on_remove();
mediator
}
Err(_) => {
panic!("Something wrong with mediator storage");
}
}
})
}
fn has_mediator<M: Mediator<Body>>(&self) -> bool {
let type_id = TypeId::of::<M>();
self.mediator_map.borrow().contains_key(&type_id)
}
}