use std::io::{self, Write};
use crate::{Verification, centroid_first_interior_point, interior_point, verify_interior_point};
use super::args::{help_text, parse_cli_args};
use super::io::{OutputRecord, read_input, serialize, write_output};
const VERIFICATION_OUTCOMES: [Verification; 4] = [
Verification::Interior,
Verification::OnGeometry,
Verification::OffGeometry,
Verification::Unverifiable,
];
fn verify_summary(verifications: &[Verification]) -> String {
let mut line = format!("verify: {} records", verifications.len());
for outcome in VERIFICATION_OUTCOMES {
let count = verifications.iter().filter(|v| **v == outcome).count();
if count > 0 {
line.push_str(&format!(", {count} {outcome}"));
}
}
line
}
pub fn run(
argv: &[String],
out: &mut dyn Write,
err: &mut dyn Write,
read_stdin: &mut dyn FnMut() -> io::Result<String>,
) -> i32 {
let options = match parse_cli_args(argv) {
Ok(options) => options,
Err(e) => {
let message = e.to_string();
let first_paragraph = message.split("\n\n").next().unwrap_or(&message);
let _ = writeln!(err, "{first_paragraph}\n\n{}", help_text());
return 1;
}
};
if options.help {
let _ = write!(out, "{}", help_text());
return 0;
}
let input = match read_input(options.input.as_deref(), read_stdin) {
Ok(input) => input,
Err(e) => {
let _ = writeln!(err, "{e}");
return 1;
}
};
let compute_point: fn(&geo_types::Geometry<f64>) -> Option<geo_types::Coord<f64>> =
if options.centroid_first {
centroid_first_interior_point
} else {
interior_point
};
let mut verifications: Vec<Verification> = Vec::new();
let results: Vec<OutputRecord> = input
.records
.into_iter()
.map(|record| {
let point = record.geometry.as_ref().and_then(compute_point);
if options.verify {
verifications.push(verify_interior_point(point, record.geometry.as_ref()));
}
OutputRecord {
point,
meta: record.meta,
}
})
.collect();
if !options.quiet {
let text = serialize(input.kind, results, options.format);
if let Err(e) = write_output(&text, options.output.as_deref(), out) {
let _ = writeln!(err, "{e}");
return 1;
}
}
if options.verify {
if !options.quiet {
let _ = writeln!(err, "{}", verify_summary(&verifications));
}
for (index, verification) in verifications.iter().enumerate() {
if *verification == Verification::OffGeometry {
let _ = writeln!(err, "verify: record {}: {verification}", index + 1);
}
}
if verifications.contains(&Verification::OffGeometry) {
return 2;
}
}
0
}