use crate::document::DataBlock;
use molframe_core::diagnostic::{Code, Diagnostic, Diagnostics};
use molframe_core::structure::StructureData;
use molframe_core::topology::PolymerKind;
pub(super) fn classify(block: &DataBlock, data: &mut StructureData, findings: &mut Diagnostics) {
let Some(polymers) = block.category("entity_poly") else {
return;
};
let mut declared = Vec::with_capacity(polymers.row_count());
for row in 0..polymers.row_count() {
let (Some(entity_id), Some(kind)) = (
polymers.identifier("entity_id", row),
polymers.text("type", row).and_then(polymer_kind),
) else {
continue;
};
let Some(symbol) = data.dictionary.get(&entity_id) else {
continue;
};
if let Some(entity) = data.topology.entities.find_by_id(symbol) {
declared.push((entity, kind));
}
}
if declared.is_empty() {
return;
}
let chains: Vec<_> = data.topology.chains.iter().collect();
for chain in chains {
if data.topology.chains.polymer_kind(chain) != Some(PolymerKind::Other) {
continue;
}
let Some(entity) = data.topology.chains.entity(chain) else {
continue;
};
let Some(&(_, kind)) = declared.iter().find(|(declared, _)| *declared == entity) else {
continue;
};
if data.topology.chains.set_polymer_kind(chain, kind).is_err() {
findings.push(Diagnostic::new(Code::E3001));
}
}
}
fn polymer_kind(declared: &str) -> Option<PolymerKind> {
let declared = declared.trim();
let is = |name: &str| declared.eq_ignore_ascii_case(name);
if is("polypeptide(L)") || is("polypeptide(D)") {
Some(PolymerKind::Protein)
} else if is("polydeoxyribonucleotide") {
Some(PolymerKind::Dna)
} else if is("polyribonucleotide") {
Some(PolymerKind::Rna)
} else if is("polydeoxyribonucleotide/polyribonucleotide hybrid") {
Some(PolymerKind::NucleicHybrid)
} else if is("polysaccharide(D)") || is("polysaccharide(L)") {
Some(PolymerKind::Saccharide)
} else {
None
}
}
#[cfg(test)]
#[path = "polymer_tests.rs"]
mod tests;