use crate::foundation::{GeoError, Result};
use std::path::Path;
#[derive(Debug, Clone)]
pub struct TopRecord {
pub name: String,
pub md: f64,
}
pub fn load(path: &Path, name_col: &str, md_col: &str) -> Result<Vec<TopRecord>> {
let bytes = std::fs::read(path)?;
let text = crate::io::decode_latin1(&bytes);
let mut rdr = csv::Reader::from_reader(std::io::Cursor::new(text.into_bytes()));
let headers = rdr
.headers()
.map_err(|e| crate::io::csv_error("tops CSV: bad header", e))?;
let find = |col: &str| {
headers
.iter()
.position(|h| h == col)
.ok_or_else(|| GeoError::NotFound(format!("tops CSV: column '{col}'")))
};
let (ni, mi) = (find(name_col)?, find(md_col)?);
let mut out = Vec::new();
for (row, rec) in rdr.records().enumerate() {
let rec = rec.map_err(|e| crate::io::csv_error(&format!("tops CSV: row {row}"), e))?;
let name = rec
.get(ni)
.ok_or_else(|| GeoError::Parse(format!("tops CSV: row {row}: missing name")))?
.to_string();
let md_s = rec
.get(mi)
.ok_or_else(|| GeoError::Parse(format!("tops CSV: row {row}: missing md")))?;
let md = md_s
.trim()
.parse::<f64>()
.map_err(|e| GeoError::Parse(format!("tops CSV: row {row}: bad md '{md_s}': {e}")))?;
out.push(TopRecord { name, md });
}
Ok(out)
}
#[cfg(test)]
mod latin1_tests {
use super::*;
use std::io::Write;
#[test]
fn decodes_latin1_marker_names() {
let mut body: Vec<u8> = b"name,md\n".to_vec();
body.extend_from_slice(b"Bl");
body.push(0xE5); body.extend_from_slice(b"b");
body.push(0xE6); body.extend_from_slice(b"r,2531.79\n");
let p = std::env::temp_dir().join("petekio_latin1_tops_csv.csv");
std::fs::File::create(&p).unwrap().write_all(&body).unwrap();
let recs = load(&p, "name", "md").unwrap();
assert_eq!(recs.len(), 1);
assert_eq!(recs[0].name, "Blåbær");
assert!((recs[0].md - 2531.79).abs() < 1e-9);
}
}