use std::collections::HashMap;
use std::collections::HashSet;
use crate::specification::{A2lObjectName, Group, Module};
pub(crate) fn cleanup(module: &mut Module) {
remove_invalid_object_references(module);
delete_empty_groups(module);
}
fn remove_invalid_object_references(module: &mut Module) {
let refnames = build_refname_set(module);
for grp in &mut module.group {
if let Some(ref_characteristic) = &mut grp.ref_characteristic {
ref_characteristic
.identifier_list
.retain(|item| refnames.contains(item));
if ref_characteristic.identifier_list.is_empty() {
grp.ref_characteristic = None;
}
}
if let Some(ref_measurement) = &mut grp.ref_measurement {
ref_measurement
.identifier_list
.retain(|item| refnames.contains(item));
if ref_measurement.identifier_list.is_empty() {
grp.ref_measurement = None;
}
}
}
}
fn build_refname_set(module: &Module) -> HashSet<String> {
let mut refnames = HashSet::new();
for item in &module.characteristic {
refnames.insert(item.get_name().to_owned());
}
for item in &module.measurement {
refnames.insert(item.get_name().to_owned());
}
for item in &module.blob {
refnames.insert(item.get_name().to_owned());
}
for item in &module.instance {
refnames.insert(item.get_name().to_owned());
}
refnames
}
fn delete_empty_groups(module: &mut Module) {
let mut name2idx = HashMap::<String, usize>::new();
for (idx, grp) in module.group.iter().enumerate() {
name2idx.insert(grp.name.clone(), idx);
}
let used_groups = get_used_groups(module);
let mut user_of = vec![Vec::<usize>::new(); module.group.len()];
let mut delete_queue: Vec<usize> = vec![];
for (idx, grp) in module.group.iter_mut().enumerate() {
if let Some(sub_group) = &grp.sub_group {
for name in &sub_group.identifier_list {
if let Some(subidx) = name2idx.get(name) {
user_of[*subidx].push(idx);
}
}
}
if used_groups.get(&grp.name).is_none() && is_group_empty(grp) {
delete_queue.push(idx);
}
}
let mut to_delete = vec![false; module.group.len()];
while let Some(del_idx) = delete_queue.pop() {
let name = module.group[del_idx].name.clone();
to_delete[del_idx] = true;
for refidx in &user_of[del_idx] {
if let Some(sg) = &mut module.group[*refidx].sub_group {
sg.identifier_list.retain(|item| *item != name);
if sg.identifier_list.is_empty() {
module.group[*refidx].sub_group = None;
}
}
if used_groups.get(&module.group[*refidx].name).is_none()
&& is_group_empty(&module.group[*refidx])
{
delete_queue.push(*refidx);
}
}
}
let mut del_iter = to_delete.iter();
module.group.retain(|_| !del_iter.next().unwrap());
}
fn get_used_groups(module: &Module) -> HashSet<String> {
let mut used_groups = HashSet::<String>::new();
for user_rights in &module.user_rights {
for ref_group in &user_rights.ref_group {
for groupname in &ref_group.identifier_list {
used_groups.insert(groupname.to_owned());
}
}
}
used_groups
}
fn is_group_empty(group: &Group) -> bool {
let sub_group_empty = if let Some(sg) = &group.sub_group {
sg.identifier_list.is_empty()
} else {
true
};
let ref_measurement_empty = if let Some(rm) = &group.ref_measurement {
rm.identifier_list.is_empty()
} else {
true
};
let ref_characteristic_empty = if let Some(rc) = &group.ref_characteristic {
rc.identifier_list.is_empty()
} else {
true
};
sub_group_empty && ref_characteristic_empty && ref_measurement_empty
}