use ahash::{AHashMap, HashMap};
use iri_string::types::{IriStr, IriString};
use std::fmt::Debug;
use crate::function::{self, Function};
use crate::{error::Error, interpreter::Program};
use crate::{interpreter, sequence};
use super::{DocumentsRef, StaticContext};
pub type Variables = AHashMap<xot::xmlname::OwnedName, sequence::Sequence>;
#[derive(Debug)]
pub struct DynamicContext<'a> {
program: &'a Program,
context_item: Option<sequence::Item>,
documents: DocumentsRef,
variables: Variables,
current_datetime: chrono::DateTime<chrono::offset::FixedOffset>,
default_collection: Option<sequence::Sequence>,
collections: HashMap<IriString, sequence::Sequence>,
default_uri_collection: Option<sequence::Sequence>,
uri_collections: HashMap<IriString, sequence::Sequence>,
environment_variables: HashMap<String, String>,
}
impl<'a> DynamicContext<'a> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
program: &'a Program,
context_item: Option<sequence::Item>,
documents: DocumentsRef,
variables: Variables,
current_datetime: chrono::DateTime<chrono::offset::FixedOffset>,
default_collection: Option<sequence::Sequence>,
collections: HashMap<IriString, sequence::Sequence>,
default_uri_collection: Option<sequence::Sequence>,
uri_collections: HashMap<IriString, sequence::Sequence>,
environment_variables: HashMap<String, String>,
) -> Self {
Self {
program,
context_item,
documents,
variables,
current_datetime,
default_collection,
collections,
default_uri_collection,
uri_collections,
environment_variables,
}
}
pub fn static_context(&self) -> &StaticContext {
self.program.static_context()
}
pub fn context_item(&self) -> Option<&sequence::Item> {
self.context_item.as_ref()
}
pub fn documents(&self) -> DocumentsRef {
self.documents.clone()
}
pub fn variables(&self) -> &Variables {
&self.variables
}
pub fn default_collection(&self) -> Option<&sequence::Sequence> {
self.default_collection.as_ref()
}
pub fn collection(&self, uri: &IriStr) -> Option<&sequence::Sequence> {
self.collections.get(uri)
}
pub fn default_uri_collection(&self) -> Option<&sequence::Sequence> {
self.default_uri_collection.as_ref()
}
pub fn uri_collection(&self, uri: &IriStr) -> Option<&sequence::Sequence> {
self.uri_collections.get(uri)
}
pub fn environment_variable(&self, name: &str) -> Option<&str> {
self.environment_variables.get(name).map(String::as_str)
}
pub fn environment_variable_names(&self) -> impl Iterator<Item = &str> {
self.environment_variables.keys().map(String::as_str)
}
pub(crate) fn arguments(&self) -> Result<Vec<sequence::Sequence>, Error> {
let mut arguments = Vec::new();
for variable_name in self.static_context().variable_names() {
let items = self.variables.get(variable_name).ok_or(Error::XPDY0002)?;
arguments.push(items.clone());
}
Ok(arguments)
}
fn create_current_datetime() -> chrono::DateTime<chrono::offset::FixedOffset> {
chrono::offset::Local::now().into()
}
pub(crate) fn current_datetime(&self) -> chrono::DateTime<chrono::offset::FixedOffset> {
self.current_datetime
}
pub fn implicit_timezone(&self) -> chrono::FixedOffset {
self.current_datetime.timezone()
}
pub fn function_info<'b>(&self, function: &'b Function) -> interpreter::FunctionInfo<'a, 'b> {
self.program.function_info(function)
}
pub(crate) fn static_function_by_id(
&self,
id: function::StaticFunctionId,
) -> &function::StaticFunction {
self.program.static_context().function_by_id(id)
}
pub(crate) fn inline_function_by_id(
&self,
id: function::InlineFunctionId,
) -> &function::InlineFunction {
self.program.inline_function(id)
}
}