use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::hash_map;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;
use anymap2::any::CloneAny;
use anymap2::{AnyMap, Entry, Map};
use yew::callback::Callback;
use crate::any_state::AnyState;
use crate::states::artifact::ArtifactSlice;
use crate::states::atom::{Atom, AtomSlice};
use crate::states::input_selector::{InputSelector, InputSelectorsState};
use crate::states::selector::{Selector, UnitSelector};
use crate::states::slice::{Slice, SliceState};
use crate::utils::Id;
use crate::utils::Listener;
pub(crate) type StateMap = Map<dyn CloneAny>;
type AnyStateMap = HashMap<TypeId, Vec<Rc<dyn AnyState>>>;
#[derive(Clone)]
pub(crate) struct BounceRootState {
id: Id,
init_states: Rc<RefCell<AnyMap>>,
states: Rc<RefCell<StateMap>>,
notion_states: Rc<RefCell<AnyStateMap>>,
}
impl Default for BounceRootState {
fn default() -> Self {
Self::new(AnyMap::new())
}
}
impl BounceRootState {
#[inline]
pub fn new(init_states: AnyMap) -> Self {
Self {
id: Id::new(),
init_states: Rc::new(RefCell::new(init_states)),
states: Rc::default(),
notion_states: Rc::default(),
}
}
pub fn get_state<T>(&self) -> T
where
T: AnyState + Clone + Default + 'static,
{
let mut states = self.states.borrow_mut();
match states.entry::<T>() {
Entry::Occupied(m) => m.get().clone(),
Entry::Vacant(m) => {
let state = {
let mut init_states = self.init_states.borrow_mut();
T::create(&mut init_states)
};
m.insert(state.clone());
let mut notion_states = self.notion_states.borrow_mut();
for notion_id in state.notion_ids() {
match notion_states.entry(notion_id) {
hash_map::Entry::Occupied(mut m) => {
m.get_mut().push(Rc::new(state.clone()) as Rc<dyn AnyState>);
}
hash_map::Entry::Vacant(m) => {
m.insert(vec![Rc::new(state.clone()) as Rc<dyn AnyState>]);
}
}
}
state
}
}
}
pub fn apply_notion<T>(&self, notion: Rc<T>)
where
T: 'static,
{
let notion_state = self.notion_states.borrow().get(&TypeId::of::<T>()).cloned();
let notion = notion as Rc<dyn Any>;
if let Some(m) = notion_state {
for any_state in m.iter() {
any_state.apply(notion.clone());
}
}
}
pub fn states(&self) -> BounceStates {
BounceStates {
inner: self.clone(),
listeners: Rc::default(),
listener_callbacks: Rc::default(),
}
}
pub fn clear(&self) {
self.notion_states.borrow_mut().clear();
self.states.borrow_mut().clear();
}
}
impl PartialEq for BounceRootState {
fn eq(&self, rhs: &Self) -> bool {
self.id == rhs.id
}
}
pub struct BounceStates {
inner: BounceRootState,
listeners: Rc<RefCell<Vec<Listener>>>,
listener_callbacks: Rc<RefCell<Vec<Rc<Callback<()>>>>>,
}
impl BounceStates {
pub fn get_slice_value<T>(&self) -> Rc<T>
where
T: Slice + 'static,
{
let state = self.inner.get_state::<SliceState<T>>();
let listener_callbacks = self.listener_callbacks.borrow().clone();
let mut listeners = Vec::new();
for callback in listener_callbacks {
let listener = state.listen(Rc::new(Callback::from(move |_: Rc<T>| {
callback.emit(());
})));
listeners.push(listener);
}
self.listeners.borrow_mut().extend(listeners);
state.get()
}
pub fn get_atom_value<T>(&self) -> Rc<T>
where
T: Atom + 'static,
{
self.get_slice_value::<AtomSlice<T>>().inner.clone()
}
pub fn get_input_selector_value<T>(&self, input: Rc<T::Input>) -> Rc<T>
where
T: InputSelector + 'static,
{
let state = self
.inner
.get_state::<InputSelectorsState<T>>()
.get_state(input);
let listener_callbacks = self.listener_callbacks.borrow().clone();
let mut listeners = Vec::new();
for callback in listener_callbacks {
let listener = state.listen(Rc::new(Callback::from(move |_: Rc<T>| {
callback.emit(());
})));
listeners.push(listener);
}
self.listeners.borrow_mut().extend(listeners);
state.get(self.derived_clone())
}
pub fn get_selector_value<T>(&self) -> Rc<T>
where
T: Selector + 'static,
{
self.get_input_selector_value::<UnitSelector<T>>(Rc::new(()))
.inner
.clone()
}
pub fn get_artifacts<T>(&self) -> Vec<Rc<T>>
where
T: PartialEq + 'static,
{
self.get_slice_value::<ArtifactSlice<T>>().get()
}
pub(crate) fn add_listener_callback(&self, callback: Rc<Callback<()>>) {
let mut listener_callbacks = self.listener_callbacks.borrow_mut();
listener_callbacks.push(callback);
}
pub(crate) fn take_listeners(&self) -> Vec<Listener> {
let mut next_listeners = Vec::new();
let mut last_listeners = self.listeners.borrow_mut();
std::mem::swap(&mut next_listeners, &mut last_listeners);
let mut listener_callbacks = self.listener_callbacks.borrow_mut();
listener_callbacks.clear();
next_listeners
}
fn derived_clone(&self) -> Self {
Self {
inner: self.inner.clone(),
listeners: Rc::default(),
listener_callbacks: Rc::default(),
}
}
}
impl fmt::Debug for BounceStates {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BounceStates")
.field("inner", &"BounceRootState")
.finish()
}
}