use crate::fields::{BseElementReferences, BseReferenceEntry};
use crate::misc;
use crate::prelude::*;
use crate::refconverters::{bib, common, endnote, ris};
use crate::references::reference_text;
use itertools::Itertools;
use std::collections::HashMap;
use textwrap;
struct ConverterFormat {
display: &'static str,
extension: &'static str,
comment: &'static str,
}
fn converter_map() -> HashMap<&'static str, ConverterFormat> {
HashMap::from([
("txt", ConverterFormat { display: "Plain Text", extension: ".txt", comment: "" }),
("bib", ConverterFormat { display: "BibTeX", extension: ".bib", comment: "%" }),
("ris", ConverterFormat { display: "RIS", extension: ".RIS", comment: "#" }),
("endnote", ConverterFormat { display: "EndNote", extension: ".enw", comment: "#" }),
("json", ConverterFormat { display: "JSON", extension: ".json", comment: "" }),
])
}
pub fn get_reference_formats() -> HashMap<String, String> {
converter_map().into_iter().map(|(k, v)| (k.to_string(), v.display.to_string())).collect()
}
pub fn get_reference_format_extension(fmt: &str) -> Result<&'static str, BseError> {
let fmt = fmt.to_lowercase();
let map = converter_map();
if !map.contains_key(fmt.as_str()) {
bse_raise!(ValueError, "Unknown reference format '{}'", fmt)?;
}
Ok(map[fmt.as_str()].extension)
}
pub fn convert_references(
ref_data: &[BseElementReferences],
fmt: &str,
all_ref_data: &HashMap<String, BseReferenceEntry>,
) -> String {
convert_references_f(ref_data, fmt, all_ref_data).unwrap()
}
pub fn convert_references_f(
ref_data: &[BseElementReferences],
fmt: &str,
all_ref_data: &HashMap<String, BseReferenceEntry>,
) -> Result<String, BseError> {
let fmt = fmt.to_lowercase();
let map = converter_map();
if !map.contains_key(fmt.as_str()) {
bse_raise!(ValueError, "Unknown reference format '{}'", fmt)?;
}
if fmt == "json" {
return Ok(serde_json::to_string_pretty(ref_data)?);
}
let comment = map[fmt.as_str()].comment;
let comment_line = if comment.is_empty() { String::new() } else { format!("{}\n", comment.repeat(80)) };
let mut ref_str = String::new();
let (lib_citation_desc, lib_citations) = common::get_library_citation(all_ref_data);
if !comment.is_empty() {
ref_str += &comment_line;
ref_str += &textwrap::indent(&lib_citation_desc, &format!("{} ", comment));
ref_str += &comment_line;
for (k, r) in &lib_citations {
ref_str += &format_single_ref(k, r, &fmt)?;
ref_str += "\n\n";
}
ref_str += &comment_line;
ref_str += &format!("{} References for the basis set\n", comment);
ref_str += &comment_line;
}
let mut unique_refs: HashMap<String, BseReferenceEntry> = HashMap::new();
for ref_item in ref_data {
if !comment.is_empty() {
ref_str += &format!("{} {}\n", comment, misc::compact_elements(&ref_item.elements));
}
for ri in &ref_item.reference_info {
if !comment.is_empty() {
ref_str += &format!("{} {}\n", comment, ri.reference_description);
if ri.reference_data.is_empty() {
ref_str += &format!("{} (...no reference...)\n{}\n", comment, comment);
} else {
let rkeys: Vec<String> = ri.reference_data.iter().map(|(k, _)| k.clone()).collect();
ref_str += &format!("{} {}\n{}\n", comment, rkeys.join(" "), comment);
}
}
for (k, r) in &ri.reference_data {
unique_refs.insert(k.clone(), r.clone());
}
}
}
ref_str += "\n\n";
for (k, r) in unique_refs.iter().sorted_by_key(|(k, _)| k.as_str()) {
ref_str += &format_single_ref(k, r, &fmt)?;
ref_str += "\n\n";
}
Ok(ref_str)
}
fn format_single_ref(key: &str, ref_entry: &BseReferenceEntry, fmt: &str) -> Result<String, BseError> {
match fmt {
"bib" => Ok(bib::write_bib(key, ref_entry)),
"ris" => Ok(ris::write_ris(key, ref_entry)),
"endnote" => Ok(endnote::write_endnote(key, ref_entry)),
"txt" => Ok(reference_text(key, ref_entry)),
_ => bse_raise!(ValueError, "Unknown format: {}", fmt),
}
}