use std::sync::Arc;
use indexmap::{IndexMap, IndexSet};
use crate::context::IEngineContext;
use crate::expression::TemplateValue;
use crate::inline::IInliner;
use crate::model::IModel;
use crate::templateboundaries::ITemplateBoundariesStructureHandler;
use crate::util::{Utf16String, Validate, ValidateError};
pub(crate) struct TemplateBoundariesStructureHandler {
pub(crate) insert_text: bool,
pub(crate) insert_text_value: Option<Utf16String>,
pub(crate) insert_text_processable: bool,
pub(crate) insert_model: bool,
pub(crate) insert_model_value: Option<Arc<dyn IModel>>,
pub(crate) insert_model_processable: bool,
pub(crate) set_local_variable: bool,
pub(crate) added_local_variables: IndexMap<Option<Utf16String>, Option<Arc<TemplateValue>>>,
pub(crate) remove_local_variable: bool,
pub(crate) removed_local_variable_names: IndexSet<Option<Utf16String>>,
pub(crate) set_selection_target: bool,
pub(crate) selection_target_object: Option<Arc<TemplateValue>>,
pub(crate) set_inliner: bool,
pub(crate) set_inliner_value: Option<Arc<dyn IInliner>>,
}
impl TemplateBoundariesStructureHandler {
pub(crate) fn new() -> Self {
let mut handler = Self {
insert_text: false,
insert_text_value: None,
insert_text_processable: false,
insert_model: false,
insert_model_value: None,
insert_model_processable: false,
set_local_variable: false,
added_local_variables: IndexMap::new(),
remove_local_variable: false,
removed_local_variable_names: IndexSet::new(),
set_selection_target: false,
selection_target_object: None,
set_inliner: false,
set_inliner_value: None,
};
handler.reset();
handler
}
fn reset_all_but_local_variables(&mut self) {
self.insert_text = false;
self.insert_text_value = None;
self.insert_text_processable = false;
self.insert_model = false;
self.insert_model_value = None;
self.insert_model_processable = false;
}
pub(crate) fn apply_context_modifications(&self, engine_context: &dyn IEngineContext) {
self.apply_context_modifications_with(
|variables| engine_context.set_variables(variables),
|variable_name| engine_context.remove_variable(variable_name),
|selection_target| engine_context.set_selection_target(selection_target),
|inliner| engine_context.set_inliner(inliner),
);
}
pub(super) fn apply_context_modifications_with(
&self,
mut set_variables: impl FnMut(&IndexMap<Option<Utf16String>, Option<Arc<TemplateValue>>>),
mut remove_variable: impl FnMut(Option<&Utf16String>),
mut set_selection_target: impl FnMut(Option<Arc<TemplateValue>>),
mut set_inliner: impl FnMut(Option<Arc<dyn IInliner>>),
) {
if self.set_local_variable {
set_variables(&self.added_local_variables);
}
if self.remove_local_variable {
for variable_name in &self.removed_local_variable_names {
remove_variable(variable_name.as_ref());
}
}
if self.set_selection_target {
set_selection_target(self.selection_target_object.clone());
}
if self.set_inliner {
set_inliner(self.set_inliner_value.clone());
}
}
pub(crate) fn insert_text_nullable(
&mut self,
text: Option<Utf16String>,
processable: bool,
) -> Result<(), ValidateError> {
self.reset_all_but_local_variables();
Validate::not_null(text.as_ref(), Some("Text cannot be null"))?;
self.insert_text = true;
self.insert_text_value = text;
self.insert_text_processable = processable;
Ok(())
}
pub(crate) fn insert_model_nullable(
&mut self,
model: Option<Arc<dyn IModel>>,
processable: bool,
) -> Result<(), ValidateError> {
self.reset_all_but_local_variables();
Validate::not_null(model.as_deref(), Some("Model cannot be null"))?;
self.insert_model = true;
self.insert_model_value = model;
self.insert_model_processable = processable;
Ok(())
}
}
impl ITemplateBoundariesStructureHandler for TemplateBoundariesStructureHandler {
fn reset(&mut self) {
self.reset_all_but_local_variables();
self.set_local_variable = false;
self.added_local_variables.clear();
self.remove_local_variable = false;
self.removed_local_variable_names.clear();
self.set_selection_target = false;
self.selection_target_object = None;
self.set_inliner = false;
self.set_inliner_value = None;
}
fn set_local_variable(&mut self, name: Option<Utf16String>, value: Option<Arc<TemplateValue>>) {
self.set_local_variable = true;
self.added_local_variables.insert(name, value);
}
fn remove_local_variable(&mut self, name: Option<Utf16String>) {
self.remove_local_variable = true;
self.removed_local_variable_names.insert(name);
}
fn set_selection_target(&mut self, selection_target: Option<Arc<TemplateValue>>) {
self.set_selection_target = true;
self.selection_target_object = selection_target;
}
fn set_inliner(&mut self, inliner: Option<Arc<dyn IInliner>>) {
self.set_inliner = true;
self.set_inliner_value = inliner;
}
fn insert_text(&mut self, text: Utf16String, processable: bool) {
self.insert_text_nullable(Some(text), processable)
.expect("Rust non-null text boundary must satisfy Java validation");
}
fn insert_model(&mut self, model: Arc<dyn IModel>, processable: bool) {
self.insert_model_nullable(Some(model), processable)
.expect("Rust non-null model boundary must satisfy Java validation");
}
}