use alloc::string::ToString;
use alloc::vec::Vec;
use super::entry::EopEntry;
use super::error::EopParseError;
pub struct Finals2000A;
impl Finals2000A {
pub fn parse(text: &str) -> Result<Vec<EopEntry>, EopParseError> {
let mut entries = Vec::new();
let mut prev_mjd: Option<f64> = None;
for (line_idx, line) in text.lines().enumerate() {
let line_num = line_idx + 1;
if line.len() < 68 {
continue;
}
let mjd_str = &line[7..15];
let mjd: f64 = match mjd_str.trim().parse() {
Ok(v) => v,
Err(_) => continue, };
if let Some(prev) = prev_mjd.filter(|&p| mjd <= p) {
return Err(EopParseError::NonMonotonicMjd {
line: line_num,
previous: prev,
current: mjd,
});
}
let xp_a = parse_col(line, 17, 27, "xp_A", line_num)?;
let yp_a = parse_col(line, 36, 46, "yp_A", line_num)?;
let dut1_a = parse_col(line, 58, 68, "dut1_A", line_num)?;
let lod_a = parse_col_opt(line, 78, 86);
let dx_a = if line.len() >= 106 {
parse_col_opt(line, 97, 106)
} else {
None
};
let dy_a = if line.len() >= 125 {
parse_col_opt(line, 116, 125)
} else {
None
};
let xp_b = if line.len() >= 144 {
parse_col_opt(line, 134, 144)
} else {
None
};
let yp_b = if line.len() >= 154 {
parse_col_opt(line, 144, 154)
} else {
None
};
let dut1_b = if line.len() >= 165 {
parse_col_opt(line, 154, 165)
} else {
None
};
let dx_b = if line.len() >= 175 {
parse_col_opt(line, 165, 175)
} else {
None
};
let dy_b = if line.len() >= 185 {
parse_col_opt(line, 175, 185)
} else {
None
};
let xp = xp_b.unwrap_or(xp_a);
let yp = yp_b.unwrap_or(yp_a);
let dut1 = dut1_b.unwrap_or(dut1_a);
let dx = dx_b.or(dx_a);
let dy = dy_b.or(dy_a);
let lod = lod_a.map(|ms| ms * 1e-3);
entries.push(EopEntry {
mjd,
xp,
yp,
dut1,
lod,
dx,
dy,
});
prev_mjd = Some(mjd);
}
if entries.is_empty() {
return Err(EopParseError::Empty);
}
Ok(entries)
}
}
fn parse_col(
line: &str,
start: usize,
end: usize,
column: &'static str,
line_num: usize,
) -> Result<f64, EopParseError> {
let end = end.min(line.len());
let s = &line[start..end];
s.trim()
.parse::<f64>()
.map_err(|_| EopParseError::InvalidNumber {
line: line_num,
column,
value: s.trim().to_string(),
})
}
fn parse_col_opt(line: &str, start: usize, end: usize) -> Option<f64> {
if start >= line.len() {
return None;
}
let end = end.min(line.len());
let s = line[start..end].trim();
if s.is_empty() {
return None;
}
s.parse::<f64>().ok()
}