use std::collections::BTreeMap;
use super::namespace::Namespace;
use crate::defs::namespace::EMPTY_DICT;
use crate::haystack::defs::namespace::DefDict;
use crate::haystack::val::{Dict, HaystackDict, Symbol};
pub struct Reflection<'a> {
pub subject: Dict,
pub defs: Vec<&'a Dict>,
pub ns: &'a Namespace,
pub entity_type: &'a Dict,
}
impl<'a> Reflection<'a> {
pub fn make(subject: &Dict, defs: Vec<&'a Dict>, ns: &'a Namespace) -> Self {
let mut reflect = Reflection {
subject: subject.clone(),
defs,
ns,
entity_type: &EMPTY_DICT,
};
reflect.compute_entity_type();
reflect
}
pub fn fits(&self, base: &Symbol) -> bool {
self.defs.iter().any(|def| {
if let Some(def) = def.get_symbol("def") {
self.ns.fits(def, base)
} else {
false
}
})
}
fn compute_entity_type(&mut self) {
self.entity_type = match self.ns.get_by_name("entity") {
Some(entity) => {
let mut types_with_inheritance = BTreeMap::<&Dict, Vec<&Dict>>::new();
for def in &self.defs {
let inheritance = self.ns.inheritance(def.def_symbol());
if inheritance.contains(&entity) {
types_with_inheritance.insert(def, inheritance);
}
}
if types_with_inheritance.len() == 1 {
types_with_inheritance
.keys()
.next()
.map_or(&EMPTY_DICT, |def| def)
} else {
let all_defs = types_with_inheritance.keys();
all_defs
.into_iter()
.find(|def| {
!types_with_inheritance
.iter()
.any(|(inner_def, inheritance)| {
inner_def != *def && inheritance.contains(def)
})
})
.map_or(&EMPTY_DICT, |def| def)
}
}
None => &EMPTY_DICT,
}
}
}