use crate::reference::Reference;
use crate::sort_support::{TextCollator, author_sort_key_opt, title_sort_key};
use citum_schema::grouping::NameSortOrder;
use citum_schema::locale::Locale;
use citum_schema::options::{Config, SortKey};
fn compare_optional_years(
a_year: Option<i32>,
b_year: Option<i32>,
ascending: bool,
) -> std::cmp::Ordering {
let cmp = match (a_year, b_year) {
(Some(a), Some(b)) => a.cmp(&b),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => std::cmp::Ordering::Equal,
};
if ascending { cmp } else { cmp.reverse() }
}
pub struct Sorter<'a> {
config: &'a Config,
locale: &'a Locale,
text_collator: TextCollator,
}
impl<'a> Sorter<'a> {
#[must_use]
pub fn new(config: &'a Config, locale: &'a Locale) -> Self {
Self {
config,
locale,
text_collator: TextCollator::new(locale),
}
}
#[must_use]
pub fn sort_references<'b>(&self, references: Vec<&'b Reference>) -> Vec<&'b Reference> {
let mut refs = references;
let processing = self.config.processing.clone().unwrap_or_default();
let proc_config = processing.config();
if let Some(sort_config) = &proc_config.sort {
let resolved = sort_config.resolve();
refs.sort_by(|a, b| {
for sort in &resolved.template {
let cmp = match sort.key {
SortKey::Author => {
let a_sort_key = author_sort_key_opt(
a,
NameSortOrder::FamilyGiven,
self.locale,
true,
)
.unwrap_or_default();
let b_sort_key = author_sort_key_opt(
b,
NameSortOrder::FamilyGiven,
self.locale,
true,
)
.unwrap_or_default();
if sort.ascending {
self.text_collator.compare(&a_sort_key, &b_sort_key)
} else {
self.text_collator.compare(&b_sort_key, &a_sort_key)
}
}
SortKey::Year => {
let a_year = a
.csl_issued_date()
.and_then(|d| d.year().parse::<i32>().ok())
.filter(|year| *year != 0);
let b_year = b
.csl_issued_date()
.and_then(|d| d.year().parse::<i32>().ok())
.filter(|year| *year != 0);
compare_optional_years(a_year, b_year, sort.ascending)
}
SortKey::Title => {
let a_title = title_sort_key(a, self.locale);
let b_title = title_sort_key(b, self.locale);
if sort.ascending {
self.text_collator.compare(&a_title, &b_title)
} else {
self.text_collator.compare(&b_title, &a_title)
}
}
SortKey::CitationNumber => std::cmp::Ordering::Equal,
_ => std::cmp::Ordering::Equal,
};
if cmp != std::cmp::Ordering::Equal {
return cmp;
}
}
match (a.id(), b.id()) {
(Some(a_id), Some(b_id)) => a_id.0.as_str().cmp(b_id.0.as_str()),
(Some(_), None) => std::cmp::Ordering::Less,
(None, Some(_)) => std::cmp::Ordering::Greater,
(None, None) => std::cmp::Ordering::Equal,
}
});
}
refs
}
}