use std::collections::BTreeMap;
use crate::expr::{ConditionExpr, ConditionParser};
use crate::{AhbCodeRule, AhbFieldRule, AhbWorkflow};
pub fn ahb_workflow_from_pid_schema(schema: &serde_json::Value) -> Option<AhbWorkflow> {
let pid = schema.get("pid")?.as_str()?;
let beschreibung = schema.get("beschreibung")?.as_str().unwrap_or("");
let kommunikation_von = schema
.get("kommunikation_von")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let mut fields = Vec::new();
if let Some(groups) = schema.get("fields").and_then(|v| v.as_object()) {
for (_group_name, group) in groups {
let source_group = group
.get("source_group")
.and_then(|v| v.as_str())
.unwrap_or("");
let group_ahb_status = group
.get("ahb_status")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
collect_fields_from_group(&mut fields, group, source_group, &group_ahb_status);
}
}
if let Some(root_segs) = schema.get("root_segments").and_then(|v| v.as_array()) {
for seg in root_segs {
collect_fields_from_segment(&mut fields, seg, "", &None);
}
}
let ub_definitions: BTreeMap<String, ConditionExpr> = schema
.get("ub_definitions")
.and_then(|v| v.as_object())
.map(|obj| {
obj.iter()
.filter_map(|(k, v)| {
let expr_str = v.as_str()?;
ConditionParser::parse(expr_str)
.ok()
.flatten()
.map(|expr| (k.clone(), expr))
})
.collect()
})
.unwrap_or_default();
fields.retain(|f| !f.segment_path.split('/').all(|p| p.starts_with("SG")));
Some(AhbWorkflow {
pruefidentifikator: pid.to_string(),
description: beschreibung.to_string(),
communication_direction: kommunikation_von,
fields,
ub_definitions,
})
}
fn collect_fields_from_group(
fields: &mut Vec<AhbFieldRule>,
group: &serde_json::Value,
group_path: &str,
parent_group_ahb_status: &Option<String>,
) {
if let Some(segments) = group.get("segments").and_then(|v| v.as_array()) {
for seg in segments {
collect_fields_from_segment(fields, seg, group_path, parent_group_ahb_status);
}
}
if let Some(children) = group.get("children").and_then(|v| v.as_object()) {
for (_child_name, child) in children {
let child_source = child
.get("source_group")
.and_then(|v| v.as_str())
.unwrap_or("");
let child_path = if group_path.is_empty() {
child_source.to_string()
} else {
format!("{}/{}", group_path, child_source)
};
let child_group_status = child
.get("ahb_status")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
collect_fields_from_group(fields, child, &child_path, &child_group_status);
}
}
}
fn collect_fields_from_segment(
fields: &mut Vec<AhbFieldRule>,
seg: &serde_json::Value,
group_path: &str,
parent_group_ahb_status: &Option<String>,
) {
let seg_id = seg.get("id").and_then(|v| v.as_str()).unwrap_or("");
let seg_mig_number = seg
.get("mig_number")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let seg_ahb_status = seg
.get("ahb_status")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
if let Some(elements) = seg.get("elements").and_then(|v| v.as_array()) {
for el in elements {
if el.get("composite").is_none() {
if let Some(de_id) = el.get("id").and_then(|v| v.as_str()) {
if let Some(ahb_status) = el.get("ahb_status").and_then(|v| v.as_str()) {
let segment_path = if group_path.is_empty() {
format!("{}/{}", seg_id, de_id)
} else {
format!("{}/{}/{}", group_path, seg_id, de_id)
};
let el_parent_status = el
.get("parent_group_ahb_status")
.and_then(|v| v.as_str())
.filter(|s| s.contains('['))
.map(|s| s.to_string())
.or_else(|| parent_group_ahb_status.clone());
let name = el
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let codes = collect_code_rules(el);
let element_index =
el.get("index").and_then(|v| v.as_u64()).map(|v| v as usize);
fields.push(AhbFieldRule {
segment_path,
name,
ahb_status: ahb_status.to_string(),
codes,
parent_group_ahb_status: el_parent_status,
segment_ahb_status: seg_ahb_status.clone(),
element_index,
component_index: None,
mig_number: seg_mig_number.clone(),
});
}
}
}
if let Some(composite_id) = el.get("composite").and_then(|v| v.as_str()) {
if let Some(components) = el.get("components").and_then(|v| v.as_array()) {
for comp in components {
let comp_id = comp.get("id").and_then(|v| v.as_str()).unwrap_or("");
if let Some(ahb_status) = comp.get("ahb_status").and_then(|v| v.as_str()) {
let segment_path = if group_path.is_empty() {
format!("{}/{}/{}", seg_id, composite_id, comp_id)
} else {
format!("{}/{}/{}/{}", group_path, seg_id, composite_id, comp_id)
};
let comp_parent_status = comp
.get("parent_group_ahb_status")
.and_then(|v| v.as_str())
.filter(|s| s.contains('['))
.map(|s| s.to_string())
.or_else(|| parent_group_ahb_status.clone());
let name = comp
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let codes = collect_code_rules(comp);
let element_index =
el.get("index").and_then(|v| v.as_u64()).map(|v| v as usize);
let component_index = comp
.get("sub_index")
.and_then(|v| v.as_u64())
.map(|v| v as usize);
fields.push(AhbFieldRule {
segment_path,
name,
ahb_status: ahb_status.to_string(),
codes,
parent_group_ahb_status: comp_parent_status,
segment_ahb_status: seg_ahb_status.clone(),
element_index,
component_index,
mig_number: seg_mig_number.clone(),
});
}
}
}
}
}
}
}
fn collect_code_rules(el: &serde_json::Value) -> Vec<AhbCodeRule> {
let Some(codes) = el.get("codes").and_then(|v| v.as_array()) else {
return Vec::new();
};
codes
.iter()
.map(|c| AhbCodeRule {
value: c
.get("value")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string(),
description: c
.get("name")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string(),
ahb_status: c
.get("ahb_status")
.and_then(|v| v.as_str())
.unwrap_or("X")
.to_string(),
})
.collect()
}