use crate::item::{Node, Sequence};
use crate::transform::Transform;
use crate::transform::context::{Context, ContextBuilder, StaticContext};
use crate::xdmerror::Error;
use crate::{Item, SequenceTrait};
use std::collections::HashMap;
use url::Url;
pub(crate) fn populate_key_values<
N: Node,
F: FnMut(&str) -> Result<(), Error>,
G: FnMut(&str) -> Result<N, Error>,
H: FnMut(&Url) -> Result<String, Error>,
>(
ctxt: &mut Context<N>,
stctxt: &mut StaticContext<N, F, G, H>,
sd: N,
) -> Result<(), Error> {
for n in sd.owner_document().descend_iter() {
for (name, d) in &ctxt.keys {
for (m, u) in d {
if m.matches(ctxt, stctxt, &Item::Node(n.clone())) {
let newctxt = ContextBuilder::from(&*ctxt)
.context(vec![Item::Node(n.clone())])
.build();
let values = newctxt.dispatch(stctxt, u)?;
values.iter().for_each(|v| {
if let Some(kv) = ctxt.key_values.get_mut(name) {
if let Some(vv) = kv.get_mut(&v.to_string()) {
vv.push(n.clone());
} else {
kv.insert(v.to_string(), vec![n.clone()]);
}
} else {
let mut new = HashMap::new();
new.insert(v.to_string(), vec![n.clone()]);
ctxt.key_values.insert(name.clone(), new);
}
})
}
}
}
}
Ok(())
}
pub fn key<
N: Node,
F: FnMut(&str) -> Result<(), Error>,
G: FnMut(&str) -> Result<N, Error>,
H: FnMut(&Url) -> Result<String, Error>,
>(
ctxt: &Context<N>,
stctxt: &mut StaticContext<N, F, G, H>,
name: &Box<Transform<N>>,
v: &Box<Transform<N>>,
) -> Result<Sequence<N>, Error> {
let keyname = ctxt.dispatch(stctxt, name)?.to_string();
Ok(ctxt.dispatch(stctxt, v)?.iter().fold(vec![], |mut acc, s| {
if let Some(u) = ctxt.key_values.get(&keyname) {
if let Some(a) = u.get(&s.to_string()) {
let mut b: Sequence<N> = a.iter().map(|n| Item::Node(n.clone())).collect();
acc.append(&mut b);
acc
} else {
acc
}
} else {
acc
}
}))
}