doris_rs/record/
formatting.rs

1use crate::{
2    error::FormattingError,
3    prelude::{EpochFlag, Header, Record},
4};
5
6use itertools::Itertools;
7
8use std::io::{BufWriter, Write};
9
10impl Record {
11    /// Format this DORIS [Record] according to the standard specifications,
12    /// into [W]ritable interface.
13    pub fn format<W: Write>(
14        &self,
15        writer: &mut BufWriter<W>,
16        header: &Header,
17    ) -> Result<(), FormattingError> {
18        let num_observables = header.observables.len();
19
20        // browse in chronological order
21        for (key, measurement) in self.measurements.iter() {
22            let (year, month, day, hours, mins, secs, nanos) =
23                key.epoch.to_gregorian(key.epoch.time_scale);
24
25            write!(
26                writer,
27                "> {:04} {:02} {:02} {:02} {:02} {:02}.{:09}  {}",
28                year, month, day, hours, mins, secs, nanos, key.flag
29            )?;
30
31            // number of station at this epoch
32            let num_stations = measurement
33                .observations
34                .keys()
35                .map(|k| k.station.code)
36                .unique()
37                .count();
38
39            write!(writer, "{:3}", num_stations)?;
40
41            // conclude line with clock offset
42            if let Some(clock_offset) = measurement.satellite_clock_offset {
43                write!(
44                    writer,
45                    "       {:.9} {}\n",
46                    clock_offset.offset.to_seconds(),
47                    clock_offset.extrapolated as u8
48                )?;
49            } else {
50                write!(writer, "\n")?;
51            }
52
53            match key.flag {
54                EpochFlag::OK | EpochFlag::PowerFailure => {
55                    for station_id in measurement
56                        .observations
57                        .keys()
58                        .map(|k| k.station.code)
59                        .unique()
60                        .sorted()
61                    {
62                        write!(writer, "D{:02}", station_id)?;
63
64                        // following header specs
65                        for (nth_observable, observable) in header.observables.iter().enumerate() {
66                            if let Some(observation) = measurement
67                                .observations
68                                .iter()
69                                .filter_map(|(k, v)| {
70                                    if k.station.code == station_id && k.observable == *observable {
71                                        Some(v)
72                                    } else {
73                                        None
74                                    }
75                                })
76                                .reduce(|k, _| k)
77                            {
78                                write!(writer, "{:14.3}  ", observation.value)?;
79                            } else {
80                                write!(writer, "                  ")?;
81                            }
82
83                            if nth_observable == num_observables - 1 {
84                                write!(writer, "\n")?;
85                            } else {
86                                if (nth_observable % 5) == 4 {
87                                    write!(writer, "\n   ")?;
88                                }
89                            }
90                        }
91                    }
92                },
93                _ => {
94                    // TODO: events: not supported yet
95                },
96            }
97        }
98
99        Ok(())
100    }
101}