use super::Processor;
use crate::reference::{Citation, CitationItem};
use citum_schema::citation::Position;
fn effective_locator_string(item: &CitationItem) -> Option<String> {
item.locator
.as_ref()
.map(citum_schema::citation::CitationLocator::canonical_string)
}
impl Processor {
pub(crate) fn annotate_positions(&self, citations: &mut [Citation]) {
let mut seen_items: std::collections::HashMap<String, Option<String>> =
std::collections::HashMap::new();
let mut previous_items: Option<Vec<(String, Option<String>)>> = None;
for citation in citations.iter_mut() {
if citation.position.is_some() {
let current_items: Vec<(String, Option<String>)> = citation
.items
.iter()
.map(|item| (item.id.clone(), effective_locator_string(item)))
.collect();
previous_items = Some(current_items);
for item in &citation.items {
seen_items.insert(item.id.clone(), effective_locator_string(item));
}
continue;
}
if citation.items.len() == 1 {
#[allow(clippy::indexing_slicing, reason = "citation.items.len() == 1")]
let current_id = &citation.items[0].id;
#[allow(clippy::indexing_slicing, reason = "citation.items.len() == 1")]
let current_locator = effective_locator_string(&citation.items[0]);
if let Some(previous) = previous_items.as_ref()
&& previous.len() == 1
&& let Some(prev_item) = previous.first()
&& prev_item.0 == *current_id
{
let previous_locator = &prev_item.1;
citation.position = Some(if previous_locator == ¤t_locator {
Position::Ibid
} else {
Position::IbidWithLocator
});
}
if citation.position.is_none() {
citation.position = Some(if seen_items.contains_key(current_id) {
Position::Subsequent
} else {
Position::First
});
}
seen_items.insert(current_id.clone(), current_locator);
} else {
let all_seen = citation
.items
.iter()
.all(|item| seen_items.contains_key(&item.id));
citation.position = Some(if all_seen {
Position::Subsequent
} else {
Position::First
});
for item in &citation.items {
seen_items.insert(item.id.clone(), effective_locator_string(item));
}
}
previous_items = Some(
citation
.items
.iter()
.map(|item| (item.id.clone(), effective_locator_string(item)))
.collect(),
);
}
}
pub fn normalize_note_context(&self, citations: &[Citation]) -> Vec<Citation> {
if !self.is_note_style() {
return citations.to_vec();
}
let mut next_note = 1_u32;
citations
.iter()
.cloned()
.map(|mut citation| {
if let Some(note_number) = citation.note_number {
if note_number >= next_note {
next_note = note_number.saturating_add(1);
}
} else {
citation.note_number = Some(next_note);
next_note = next_note.saturating_add(1);
}
citation
})
.collect()
}
}