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::{AttributeNameError, AttributeNameValue};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum AttributeDefinitionKind {
Html,
Xml,
Text,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum AttributeDefinitionError {
NullAttributeName,
NullAssociatedProcessors,
NullAssociatedProcessor,
AttributeName(AttributeNameError),
}
impl AttributeDefinitionError {
#[must_use]
pub const fn class_name(&self) -> &'static str {
match self {
Self::NullAttributeName | Self::NullAssociatedProcessors => {
"java.lang.IllegalArgumentException"
}
Self::NullAssociatedProcessor => "java.lang.NullPointerException",
Self::AttributeName(error) => error.class_name(),
}
}
}
impl Display for AttributeDefinitionError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::NullAttributeName => formatter.write_str("Attribute name cannot be null"),
Self::NullAssociatedProcessors => {
formatter.write_str("Associated processors cannot be null")
}
Self::NullAssociatedProcessor => {
formatter.write_str("processor comparator received null")
}
Self::AttributeName(error) => Display::fmt(error, formatter),
}
}
}
impl Error for AttributeDefinitionError {}
pub struct AttributeDefinition {
kind: AttributeDefinitionKind,
attribute_name: AttributeNameValue,
associated_processors_set: UnmodifiableElementProcessorSet,
associated_processors: Vec<Arc<dyn IElementProcessor>>,
has_associated_processors: bool,
}
impl AttributeDefinition {
pub(super) fn new(
kind: AttributeDefinitionKind,
attribute_name: Option<AttributeNameValue>,
associated_processors: Option<Arc<RwLock<ElementProcessorSet>>>,
) -> Result<Self, AttributeDefinitionError> {
let attribute_name = attribute_name.ok_or(AttributeDefinitionError::NullAttributeName)?;
let associated_processors =
associated_processors.ok_or(AttributeDefinitionError::NullAssociatedProcessors)?;
let mut sorted = crate::element::read_set(&associated_processors)
.iter()
.map(|value| {
value
.cloned()
.ok_or(AttributeDefinitionError::NullAssociatedProcessor)
})
.collect::<Result<Vec<_>, _>>()?;
sorted.sort_by(compare_processors);
let has_associated_processors = !sorted.is_empty();
Ok(Self {
kind,
attribute_name,
associated_processors_set: UnmodifiableElementProcessorSet::new(associated_processors),
associated_processors: sorted,
has_associated_processors,
})
}
#[must_use]
pub const fn get_attribute_name(&self) -> &AttributeNameValue {
&self.attribute_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
}
pub fn equals_java(&self, other: &Self) -> Result<bool, AttributeDefinitionError> {
if std::ptr::eq(self, other) {
return Ok(true);
}
if self.kind != other.kind {
return Ok(false);
}
self.attribute_name
.as_attribute_name()
.equals_java(other.attribute_name.as_attribute_name())
.map_err(AttributeDefinitionError::AttributeName)
}
#[must_use]
pub fn hash_code(&self) -> i32 {
self.attribute_name.as_attribute_name().hash_code()
}
pub fn to_utf16_string(&self) -> Result<Utf16String, AttributeDefinitionError> {
self.attribute_name
.as_attribute_name()
.to_utf16_string()
.map_err(AttributeDefinitionError::AttributeName)
}
}
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())
}