use std::fmt::{Error, Write as _};
use crate::fp::{FlightPlanning, FuelPlanning, RunwayAnalysis};
use crate::measurements::LengthUnit;
use crate::nd::*;
use crate::route::Route;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
pub struct Printer {
pub(super) line_length: usize,
}
impl Printer {
pub fn print(
&self,
route: &Route,
flight_planning: Option<&FlightPlanning>,
) -> Result<String, Error> {
let mut buffer = String::new();
self.write_route(&mut buffer, route)?;
if let Some(flight_planning) = flight_planning {
if let Some(fuel_planning) = flight_planning.fuel_planning() {
self.write_fuel(&mut buffer, fuel_planning)?;
}
self.write_mb(&mut buffer, flight_planning)?;
if let Some(rwy_analysis) = flight_planning.takeoff_rwy_analysis() {
self.write_takeoff_landing_rwy_analysis(&mut buffer, "TAKEOFF RWY", rwy_analysis)?;
}
if let Some(rwy_analysis) = flight_planning.landing_rwy_analysis() {
self.write_takeoff_landing_rwy_analysis(&mut buffer, "LANDING RWY", rwy_analysis)?;
}
}
Ok(buffer)
}
fn write_section(&self, buffer: &mut String, title: &str) -> Result<(), Error> {
writeln!(buffer, "{}", "-".repeat(self.line_length))?;
writeln!(buffer, "-- {title}")?;
writeln!(buffer, "{}", "-".repeat(self.line_length))?;
writeln!(buffer)?;
Ok(())
}
fn write_route(&self, buffer: &mut String, route: &Route) -> Result<(), Error> {
self.write_section(buffer, "ROUTE")?;
for leg in route.legs() {
let space = (self.line_length - 23) / 3;
let is_heading = leg.mh().is_some();
writeln!(
buffer,
"{:<6}{:space$}{:^6}{:space$}{:>8}{:space$}{:^5}",
"TO",
"",
if is_heading { "HDG" } else { "TRK" },
"",
"DIST",
"",
"ETE"
)?;
writeln!(
buffer,
"{:<6}{:space$}{:^6.0}{:space$}{:>8.1}{:space$}{:^5}",
leg.to().ident(),
"",
leg.mh().unwrap_or(leg.mc()),
"",
leg.dist().convert_to(LengthUnit::NauticalMiles),
"",
leg.ete().map(|d| d.to_string()).unwrap_or("-".to_string()),
)?;
writeln!(buffer)?;
}
if let Some(totals) = route.totals(None) {
writeln!(buffer, "DIST {:>1$.1}", totals.dist(), self.line_length - 5)?;
if let Some(ete) = totals.ete() {
writeln!(buffer, "ETE {:>1$}", ete, self.line_length - 4)?;
}
}
writeln!(buffer)?;
Ok(())
}
fn write_fuel(&self, buffer: &mut String, fuel_planning: &FuelPlanning) -> Result<(), Error> {
self.write_section(buffer, "FUEL")?;
writeln!(
buffer,
"TRIP {:>1$.0}",
fuel_planning.trip(),
self.line_length - 5
)?;
writeln!(
buffer,
"TAXI {:>1$.0}",
fuel_planning.taxi(),
self.line_length - 5
)?;
if let Some(alternate) = fuel_planning.alternate() {
writeln!(
buffer,
"ALTERNATE {:>1$.0}",
alternate,
self.line_length - 10
)?;
}
writeln!(
buffer,
"RESERVE {:>1$.0}",
fuel_planning.reserve(),
self.line_length - 8
)?;
writeln!(
buffer,
"MINIMUM {:>1$.0}",
fuel_planning.min(),
self.line_length - 8
)?;
if let Some(extra) = fuel_planning.extra() {
writeln!(buffer, "EXTRA {:>1$.0}", extra, self.line_length - 6)?;
}
writeln!(
buffer,
"TOTAL {:>1$.0}",
fuel_planning.total(),
self.line_length - 6
)?;
writeln!(buffer)?;
Ok(())
}
fn write_mb(&self, buffer: &mut String, flight_planning: &FlightPlanning) -> Result<(), Error> {
self.write_section(buffer, "MASS & BALANCE")?;
if let Some(mb) = flight_planning.mb() {
let column_length = (self.line_length - 15) / 2;
writeln!(
buffer,
" {:^column_length$} {:^column_length$}",
"MASS", "BALANCE"
)?;
writeln!(
buffer,
" ON RAMP {:^column_length$.0} {:^column_length$.1}",
mb.mass_on_ramp(),
mb.balance_on_ramp()
)?;
writeln!(
buffer,
"AFTER LANDING {:^column_length$.0} {:^column_length$.1}",
mb.mass_after_landing(),
mb.balance_on_ramp()
)?;
}
let balanced = match flight_planning.is_balanced() {
Some(true) => "YES",
Some(false) => "NO",
None => "N/A",
};
writeln!(buffer)?;
writeln!(buffer, "BALANCED {:>1$}", balanced, self.line_length - 9)?;
writeln!(buffer)?;
Ok(())
}
fn write_takeoff_landing_rwy_analysis(
&self,
buffer: &mut String,
section: &str,
rwy_analysis: &RunwayAnalysis,
) -> Result<(), Error> {
self.write_section(buffer, section)?;
writeln!(
buffer,
"HEADWIND {:>1$.0}",
rwy_analysis.headwind(),
self.line_length - 9
)?;
writeln!(
buffer,
"CROSSWIND {:>1$.0}",
rwy_analysis.crosswind(),
self.line_length - 10
)?;
writeln!(
buffer,
"GROUND ROLL {:>1$.0}",
rwy_analysis.ground_roll(),
self.line_length - 12
)?;
writeln!(
buffer,
"MARGIN {:>1$.0}",
rwy_analysis.margin(),
self.line_length - 7
)?;
writeln!(
buffer,
"MARGIN in % {:>1$.2}",
rwy_analysis.pct_margin(),
self.line_length - 12
)?;
writeln!(buffer)?;
Ok(())
}
}