use std::{path::Path, str::FromStr};
use nom::{IResult, Parser, character::char, sequence::separated_pair};
use rustc_hash::FxHashMap;
use crate::{
error::{HResult, HrdfError},
models::{InformationText, Language},
parsing::{
error::PResult,
helpers::{i32_from_n_digits_parser, read_lines, string_till_eol_parser},
},
storage::ResourceStorage,
};
fn parse_infotext_row(input: &str) -> IResult<&str, (i32, String)> {
separated_pair(
i32_from_n_digits_parser(9),
char(' '),
string_till_eol_parser,
)
.parse(input)
}
fn parse_line(
line: &str,
infotextmap: &mut FxHashMap<i32, InformationText>,
current_language: &str,
) -> PResult<()> {
let current_language = Language::from_str(current_language)?;
let (_, (id, infotext)) = parse_infotext_row(line)?;
if let Some(mut info) = infotextmap.remove(&id) {
info.set_content(current_language, &infotext);
infotextmap.insert(id, info);
} else {
let mut info = InformationText::new(id);
info.set_content(current_language, &infotext);
infotextmap.insert(id, info);
}
Ok(())
}
pub fn parse(path: &Path) -> HResult<ResourceStorage<InformationText>> {
let mut infotextmap: FxHashMap<i32, InformationText> = FxHashMap::default();
let languages = ["DE", "EN", "FR", "IT"];
for language in languages {
log::info!("Parsing INFOTEXT_{language}...");
let file = path.join(format!("INFOTEXT_{language}"));
let lines = read_lines(&file, 0)?;
lines
.into_iter()
.enumerate()
.filter(|(_, line)| !line.trim().is_empty())
.try_for_each(|(line_number, line)| {
parse_line(&line, &mut infotextmap, language).map_err(|e| HrdfError::Parsing {
error: e,
file: String::from(file.to_string_lossy()),
line,
line_number,
})
})?;
}
Ok(ResourceStorage::new(infotextmap))
}
#[cfg(test)]
mod tests {
use crate::parsing::tests::get_json_values;
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn infotext_row_parser1() {
let input = "000001921 ch:1:sjyid:100001:3995-001";
let (_, (id, infotext)) = parse_infotext_row(input).unwrap();
assert_eq!(1921, id);
assert_eq!("ch:1:sjyid:100001:3995-001", &infotext);
}
#[test]
fn infotext_row_parser2() {
let input = "000003459 2518 ";
let (_, (id, infotext)) = parse_infotext_row(input).unwrap();
assert_eq!(3459, id);
assert_eq!("2518", &infotext);
}
#[test]
fn parse_and_transform_infotext() {
let input = "000001921 ch:1:sjyid:100001:3995-001";
let mut infotext_map = FxHashMap::default();
parse_line(input, &mut infotext_map, "DE").unwrap();
parse_line(input, &mut infotext_map, "FR").unwrap();
parse_line(input, &mut infotext_map, "IT").unwrap();
parse_line(input, &mut infotext_map, "EN").unwrap();
println!("{infotext_map:?}");
let reference = r#"
{
"id": 1921,
"content": {
"French": "ch:1:sjyid:100001:3995-001",
"Italian": "ch:1:sjyid:100001:3995-001",
"German": "ch:1:sjyid:100001:3995-001",
"English": "ch:1:sjyid:100001:3995-001"
}
}"#;
let (attribute, reference) =
get_json_values(infotext_map.get(&1921).unwrap(), reference).unwrap();
assert_eq!(attribute, reference);
}
}