use std::borrow::Cow;
use bumpalo::Bump;
use crate::{AttributeValue, Author, DocumentAttributes, Header};
use super::{ParserState, document::document_parser};
fn build_author_full_name(author: &Author) -> String {
let mut name = author.first_name.to_string();
if let Some(middle) = &author.middle_name {
name.push(' ');
name.push_str(middle);
}
if !author.last_name.is_empty() {
name.push(' ');
name.push_str(author.last_name);
}
name
}
pub(crate) fn derive_author_attrs<'a>(
arena: &'a Bump,
header: &mut Header<'a>,
attrs: &mut DocumentAttributes<'a>,
) {
ingest_author_attribute(arena, header, attrs);
if header.authors.is_empty() {
return;
}
set_aggregate_author_attrs(header, attrs);
set_per_author_attrs(header, attrs);
}
fn ingest_author_attribute<'a>(
arena: &'a Bump,
header: &mut Header<'a>,
attrs: &DocumentAttributes<'a>,
) {
let Some(author) = attrs.get_string("author") else {
return;
};
if author.is_empty() {
return;
}
let scratch = Bump::new();
let mut temp_state = ParserState::new(&author, &scratch);
let Ok(parsed) = document_parser::authors(&author, &mut temp_state) else {
return;
};
let mut authors: Vec<Author<'a>> = parsed
.into_iter()
.map(|a| Author {
first_name: arena.alloc_str(a.first_name),
middle_name: a.middle_name.map(|m| &*arena.alloc_str(m)),
last_name: arena.alloc_str(a.last_name),
initials: arena.alloc_str(a.initials),
email: a.email.map(|e| &*arena.alloc_str(e)),
})
.collect();
if let Some(first) = authors.first_mut()
&& first.email.is_none()
&& let Some(email) = attrs.get_string("email")
{
first.email = Some(arena.alloc_str(&email));
}
header.authors = authors;
}
fn set_aggregate_author_attrs<'a>(header: &Header<'a>, attrs: &mut DocumentAttributes<'a>) {
let all_names: Vec<String> = header.authors.iter().map(build_author_full_name).collect();
attrs.insert(
"authors".into(),
AttributeValue::String(all_names.join(", ").into()),
);
attrs.insert(
"authorcount".into(),
AttributeValue::String(header.authors.len().to_string().into()),
);
}
fn set_per_author_attrs<'a>(header: &Header<'a>, attrs: &mut DocumentAttributes<'a>) {
for (i, author) in header.authors.iter().enumerate() {
let suffix = if i == 0 {
String::new()
} else {
format!("_{}", i + 1)
};
attrs.insert(
format!("author{suffix}").into(),
AttributeValue::String(build_author_full_name(author).into()),
);
attrs.insert(
format!("firstname{suffix}").into(),
AttributeValue::String(Cow::Borrowed(author.first_name)),
);
if let Some(middle) = author.middle_name {
attrs.insert(
format!("middlename{suffix}").into(),
AttributeValue::String(Cow::Borrowed(middle)),
);
}
attrs.insert(
format!("lastname{suffix}").into(),
AttributeValue::String(Cow::Borrowed(author.last_name)),
);
attrs.insert(
format!("authorinitials{suffix}").into(),
AttributeValue::String(Cow::Borrowed(author.initials)),
);
if let Some(email) = author.email {
attrs.insert(
format!("email{suffix}").into(),
AttributeValue::String(Cow::Borrowed(email)),
);
}
}
}