use std::cmp::Ordering;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::sync::{Arc, RwLock};
use crate::element::{ElementProcessorSet, IElementProcessor, UnmodifiableElementProcessorSet};
use crate::util::Utf16String;
use super::{ElementNameError, ElementNameValue};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ElementDefinitionKind {
Html,
Xml,
Text,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ElementDefinitionError {
NullElementName,
NullAssociatedProcessors,
NullAssociatedProcessor,
ElementName(ElementNameError),
}
impl ElementDefinitionError {
#[must_use]
pub const fn class_name(&self) -> &'static str {
match self {
Self::NullElementName | Self::NullAssociatedProcessors => {
"java.lang.IllegalArgumentException"
}
Self::NullAssociatedProcessor => "java.lang.NullPointerException",
Self::ElementName(error) => error.class_name(),
}
}
}
impl Display for ElementDefinitionError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::NullElementName => formatter.write_str("Element name cannot be null"),
Self::NullAssociatedProcessors => {
formatter.write_str("Associated processors cannot be null")
}
Self::NullAssociatedProcessor => {
formatter.write_str("processor comparator received null")
}
Self::ElementName(error) => Display::fmt(error, formatter),
}
}
}
impl Error for ElementDefinitionError {}
pub struct ElementDefinition {
kind: ElementDefinitionKind,
element_name: ElementNameValue,
associated_processors_set: UnmodifiableElementProcessorSet,
associated_processors: Vec<Arc<dyn IElementProcessor>>,
has_associated_processors: bool,
}
impl ElementDefinition {
pub(super) fn new(
kind: ElementDefinitionKind,
element_name: Option<ElementNameValue>,
associated_processors: Option<Arc<RwLock<ElementProcessorSet>>>,
) -> Result<Self, ElementDefinitionError> {
let element_name = element_name.ok_or(ElementDefinitionError::NullElementName)?;
let associated_processors =
associated_processors.ok_or(ElementDefinitionError::NullAssociatedProcessors)?;
let mut sorted = crate::element::read_set(&associated_processors)
.iter()
.map(|value| {
value
.cloned()
.ok_or(ElementDefinitionError::NullAssociatedProcessor)
})
.collect::<Result<Vec<_>, _>>()?;
sorted.sort_by(compare_processors);
let has_associated_processors = !sorted.is_empty();
Ok(Self {
kind,
element_name,
associated_processors_set: UnmodifiableElementProcessorSet::new(associated_processors),
associated_processors: sorted,
has_associated_processors,
})
}
#[must_use]
pub const fn get_element_name(&self) -> &ElementNameValue {
&self.element_name
}
#[must_use]
pub const fn has_associated_processors(&self) -> bool {
self.has_associated_processors
}
#[must_use]
pub const fn get_associated_processors(&self) -> &UnmodifiableElementProcessorSet {
&self.associated_processors_set
}
#[must_use]
pub fn sorted_associated_processors(&self) -> &[Arc<dyn IElementProcessor>] {
&self.associated_processors
}
#[must_use]
pub fn equals_java(&self, other: &Self) -> bool {
std::ptr::eq(self, other)
|| (self.kind == other.kind
&& self.element_name.as_element_name() == other.element_name.as_element_name())
}
#[must_use]
pub fn hash_code(&self) -> i32 {
self.element_name.as_element_name().hash_code()
}
pub fn to_utf16_string(&self) -> Result<Utf16String, ElementDefinitionError> {
self.element_name
.as_element_name()
.to_utf16_string()
.map_err(ElementDefinitionError::ElementName)
}
}
fn compare_processors(
left: &Arc<dyn IElementProcessor>,
right: &Arc<dyn IElementProcessor>,
) -> Ordering {
if Arc::ptr_eq(left, right) {
return Ordering::Equal;
}
crate::util::ProcessorComparators::compare_processors(left.as_ref(), right.as_ref())
}