use openehr_am::v2_4::aom2::constraint_model::c_complex_object::CComplexObjectData;
use openehr_am::v2_4::aom2::constraint_model::{c_attribute, c_complex_object, c_object};
use openehr_its::opt14::types::{
CAttribute, CComplexObject, CObject, CSingleAttribute, Intervalofinteger,
};
use super::inputs;
const INTERVAL_PARTS: [&str; 2] = ["lower", "upper"];
fn interval_parameter(rm_type: &str) -> Option<&str> {
rm_type.strip_prefix("DV_INTERVAL<")?.strip_suffix('>')
}
pub(super) fn attribute_existence(attr: &CAttribute) -> &Intervalofinteger {
match attr {
CAttribute::CSingleAttribute(s) => &s.existence,
CAttribute::CMultipleAttribute(m) => &m.existence,
}
}
fn optional() -> Intervalofinteger {
Intervalofinteger {
lower_included: Some(true),
upper_included: Some(true),
lower_unbounded: false,
upper_unbounded: false,
lower: Some(0),
upper: Some(1),
}
}
fn open_object(rm_type: &str, occurrences: Intervalofinteger) -> CObject {
CObject::CComplexObject(CComplexObject {
rm_type_name: rm_type.to_owned(),
occurrences,
node_id: String::new(),
attributes: Vec::new(),
})
}
const ANY_ELEMENT_VALUE_TYPES: [&str; 17] = [
"DV_TEXT",
"DV_CODED_TEXT",
"DV_MULTIMEDIA",
"DV_PARSABLE",
"DV_BOOLEAN",
"DV_IDENTIFIER",
"DV_URI",
"DV_EHR_URI",
"DV_DURATION",
"DV_QUANTITY",
"DV_COUNT",
"DV_PROPORTION",
"DV_DATE_TIME",
"DV_TIME",
"DV_ORDINAL",
"DV_SCALE",
"DV_DATE",
];
pub(super) fn any_element_value(co: &CObject, rm_type: &str) -> Option<CAttribute> {
if rm_type != "ELEMENT" {
return None;
}
let declared = inputs::attributes(co)
.iter()
.find(|a| inputs::attribute_name(a) == "value");
let existence = match declared {
None => optional(),
Some(attr) if inputs::attribute_children(attr).is_empty() => {
let existence = attribute_existence(attr);
if !existence.upper_unbounded && existence.upper == Some(0) {
return None;
}
existence.clone()
}
Some(_) => return None,
};
let children = ANY_ELEMENT_VALUE_TYPES
.iter()
.map(|rm| {
let occurrences = Intervalofinteger {
lower: Some(0),
..existence.clone()
};
open_object(rm, occurrences)
})
.collect();
Some(CAttribute::CSingleAttribute(CSingleAttribute {
rm_attribute_name: "value".to_owned(),
existence,
children,
}))
}
pub(super) fn interval_parts_v1_4(co: &CObject, rm_type: &str) -> Vec<CAttribute> {
let Some(parameter) = interval_parameter(rm_type) else {
return Vec::new();
};
INTERVAL_PARTS
.into_iter()
.filter(|part| {
inputs::attributes(co)
.iter()
.find(|a| inputs::attribute_name(a) == *part)
.is_none_or(|attr| {
let existence = attribute_existence(attr);
inputs::attribute_children(attr).is_empty()
&& (existence.upper_unbounded || existence.upper != Some(0))
})
})
.map(|part| {
CAttribute::CSingleAttribute(CSingleAttribute {
rm_attribute_name: part.to_owned(),
existence: optional(),
children: vec![open_object(parameter, optional())],
})
})
.collect()
}
pub(super) fn interval_parts_v2_4(
rm_type: &str,
declared: &[c_attribute::CAttribute],
) -> Vec<c_attribute::CAttribute> {
let Some(parameter) = interval_parameter(rm_type) else {
return Vec::new();
};
INTERVAL_PARTS
.into_iter()
.filter(|part| {
declared
.iter()
.find(|a| a.rm_attribute_name == *part)
.is_none_or(|attr| {
attr.children.as_deref().unwrap_or_default().is_empty()
&& attr
.existence
.as_ref()
.is_none_or(|e| e.upper_unbounded || e.upper != Some(0))
})
})
.map(|part| c_attribute::CAttribute {
parent: None,
soc_parent: None,
rm_attribute_name: part.to_owned(),
existence: None,
children: Some(vec![c_object::CObject::CComplexObject(
c_complex_object::CComplexObject::CComplexObject(CComplexObjectData {
parent: None,
soc_parent: None,
rm_type_name: parameter.to_owned(),
occurrences: None,
node_id: String::new(),
alternative_ids: None,
is_deprecated: None,
sibling_order: None,
default_value: None,
attributes: None,
attribute_tuples: None,
}),
)]),
differential_path: None,
cardinality: None,
is_multiple: false,
})
.collect()
}