use crate::binding::interfaces::{BindingDirection, BindingHookChanges, IPropertyBindingHook};
use ferroui_splat::AppLocator;
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
ferroui_system::ferro_thread_local! {
static HOOKS: RefCell<Option<Rc<[Rc<dyn IPropertyBindingHook>]>>> = const { RefCell::new(None) };
}
pub struct BindingHooks;
impl BindingHooks {
pub fn any() -> bool {
!Self::resolve().is_empty()
}
pub fn refresh() {
let previous = HOOKS.with(|hooks| hooks.borrow_mut().take());
drop(previous);
}
pub fn should_bind(
source: Option<&Rc<dyn Any>>,
target: &Rc<dyn Any>,
get_source_properties: &dyn Fn() -> BindingHookChanges,
get_target_properties: &dyn Fn() -> BindingHookChanges,
direction: BindingDirection,
) -> bool {
Self::resolve()
.iter()
.all(|hook| hook.execute_hook(source, target, get_source_properties, get_target_properties, direction))
}
fn resolve() -> Rc<[Rc<dyn IPropertyBindingHook>]> {
if let Some(resolved) = HOOKS.with(|hooks| hooks.borrow().clone()) {
return resolved;
}
let resolved: Rc<[Rc<dyn IPropertyBindingHook>]> = Rc::from(AppLocator::get_services::<dyn IPropertyBindingHook>());
HOOKS.with(|hooks| hooks.borrow_mut().get_or_insert_with(|| resolved.clone()).clone())
}
}