mod parsing;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{
fmt_ionex,
linspace::Linspace,
prelude::{
BiasSource, Comments, Duration, Epoch, FormattingError, Grid, MappingFunction,
ReferenceSystem, Version,
},
};
use std::io::{BufWriter, Write};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Header {
pub version: Version,
pub program: Option<String>,
pub run_by: Option<String>,
pub date: Option<String>,
pub license: Option<String>,
pub doi: Option<String>,
pub number_of_maps: usize,
pub epoch_of_first_map: Epoch,
pub epoch_of_last_map: Epoch,
pub reference_system: ReferenceSystem,
pub description: Option<String>,
pub mapf: MappingFunction,
pub map_dimension: u8,
pub base_radius_km: f32,
pub sampling_period: Duration,
pub grid: Grid,
pub elevation_cutoff: f32,
exponent: i8,
pub comments: Comments,
}
impl Default for Header {
fn default() -> Self {
Self {
exponent: -1,
number_of_maps: 0,
map_dimension: 2,
mapf: Default::default(),
comments: Default::default(),
description: Default::default(),
elevation_cutoff: 0.0,
base_radius_km: 6371.0,
grid: Grid::default(),
epoch_of_last_map: Epoch::default(),
epoch_of_first_map: Epoch::default(),
sampling_period: Duration::from_hours(1.0),
reference_system: ReferenceSystem::default(),
version: Default::default(),
program: Default::default(),
run_by: Default::default(),
date: Default::default(),
license: Default::default(),
doi: Default::default(),
}
}
}
impl Header {
pub(crate) fn format<W: Write>(&self, w: &mut BufWriter<W>) -> Result<(), FormattingError> {
writeln!(
w,
"{}",
fmt_ionex(&format!("{:6}", self.map_dimension), "MAP DIMENSION")
)?;
let (start, end, spacing) = (
self.grid.altitude.start,
self.grid.altitude.end,
self.grid.altitude.spacing,
);
writeln!(
w,
"{}",
fmt_ionex(
&format!("{} {} {}", start, end, spacing),
"HGT1 / HGT2 / DHGT"
)
)?;
let (start, end, spacing) = (
self.grid.latitude.start,
self.grid.latitude.end,
self.grid.latitude.spacing,
);
writeln!(
w,
"{}",
fmt_ionex(
&format!("{} {} {}", start, end, spacing),
"LAT1 / LAT2 / DLAT"
)
)?;
let (start, end, spacing) = (
self.grid.longitude.start,
self.grid.longitude.end,
self.grid.longitude.spacing,
);
writeln!(
w,
"{}",
fmt_ionex(
&format!("{} {} {}", start, end, spacing),
"LON1 / LON2 / DLON"
)
)?;
writeln!(
w,
"{}",
fmt_ionex(&format!("{}", self.elevation_cutoff), "ELEVATION CUTOFF")
)?;
writeln!(
w,
"{}",
fmt_ionex(&format!("{}", self.mapf), "MAPPING FUNCTION")
)?;
writeln!(w, "{}", fmt_ionex("TODO", "EPOCH OF FIRST MAP"))?;
writeln!(w, "{}", fmt_ionex("TODO", "EPOCH OF LAST MAP"))?;
Ok(())
}
pub fn with_number_of_maps(&self, num: usize) -> Self {
let mut s = self.clone();
s.number_of_maps = num;
s
}
pub fn with_epoch_of_first_map(&self, t: Epoch) -> Self {
let mut s = self.clone();
s.epoch_of_first_map = t;
s
}
pub fn with_epoch_of_last_map(&self, t: Epoch) -> Self {
let mut s = self.clone();
s.epoch_of_last_map = t;
s
}
pub fn with_reference_system(&self, reference: ReferenceSystem) -> Self {
let mut s = self.clone();
s.reference_system = reference;
s
}
pub fn with_exponent(&self, e: i8) -> Self {
let mut s = self.clone();
s.exponent = e;
s
}
pub fn with_description(&self, desc: &str) -> Self {
let mut s = self.clone();
if let Some(ref mut d) = s.description {
d.push(' ');
d.push_str(desc)
} else {
s.description = Some(desc.to_string())
}
s
}
pub fn with_mapping_function(&self, mapf: MappingFunction) -> Self {
let mut s = self.clone();
s.mapf = mapf;
s
}
pub fn with_elevation_cutoff(&self, e: f32) -> Self {
let mut s = self.clone();
s.elevation_cutoff = e;
s
}
pub fn with_base_radius_km(&self, base_radius_km: f32) -> Self {
let mut s = self.clone();
s.base_radius_km = base_radius_km;
s
}
pub fn with_map_dimension(&self, dim: u8) -> Self {
let mut s = self.clone();
s.map_dimension = dim;
s
}
pub fn with_latitude_grid(&self, grid: Linspace) -> Self {
let mut s = self.clone();
s.grid.latitude = grid;
s
}
pub fn with_longitude_grid(&self, grid: Linspace) -> Self {
let mut s = self.clone();
s.grid.longitude = grid;
s
}
pub fn with_altitude_grid(&self, grid: Linspace) -> Self {
let mut s = self.clone();
s.grid.altitude = grid;
s
}
}