1mod formatting;
2mod parsing;
3
4mod antenna;
5mod receiver;
6mod version;
7
8use itertools::Itertools;
9use std::collections::HashMap;
10
11use crate::{
12 prelude::{Duration, Epoch, GroundStation, Observable, COSPAR},
13 Comments,
14};
15
16#[cfg(doc)]
17use crate::prelude::Record;
18
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22pub use antenna::Antenna;
23pub use receiver::Receiver;
24pub use version::Version;
25
26#[derive(Clone, Debug, PartialEq, Default)]
28#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29pub struct Header {
30 pub version: Version,
32
33 pub comments: Comments,
35
36 pub satellite: String,
38
39 pub program: Option<String>,
41
42 pub run_by: Option<String>,
44
45 pub date: Option<String>,
47
48 pub observer: Option<String>,
50
51 pub agency: Option<String>,
53
54 pub cospar: Option<COSPAR>,
56
57 pub receiver: Option<Receiver>,
59
60 pub antenna: Option<Antenna>,
62
63 pub license: Option<String>,
65
66 pub doi: Option<String>,
68
69 pub l1_l2_date_offset: Duration,
71
72 pub observables: Vec<Observable>,
74
75 pub scaling_factors: HashMap<Observable, f64>,
77
78 pub ground_stations: Vec<GroundStation>,
80
81 pub time_of_first_observation: Option<Epoch>,
83
84 pub time_of_last_observation: Option<Epoch>,
86}
87
88impl Header {
89 pub fn ground_station(&self, station_code: u16) -> Option<GroundStation> {
92 self.ground_stations
93 .iter()
94 .filter(|station| station.code == station_code)
95 .reduce(|k, _| k)
96 .cloned()
97 }
98
99 pub(crate) fn format_pkg_version(version: &str) -> String {
102 version
103 .split('.')
104 .enumerate()
105 .filter_map(|(nth, v)| {
106 if nth < 2 {
107 Some(v.to_string())
108 } else if nth == 2 {
109 Some(
110 v.split('-')
111 .filter_map(|v| {
112 if v == "rc" {
113 Some("rc".to_string())
114 } else {
115 let mut s = String::new();
116 s.push_str(&v[0..1]);
117 Some(s)
118 }
119 })
120 .join(""),
121 )
122 } else {
123 None
124 }
125 })
126 .join(".")
127 }
128
129 pub(crate) fn merge_comment(pkg_version: &str, timestamp: Epoch) -> String {
131 let formatted_version = Self::format_pkg_version(pkg_version);
132
133 let (y, m, d, hh, mm, ss, _) = timestamp.to_gregorian_utc();
134
135 format!(
136 "doris-rs v{} {:>width$} {}{:02}{:02} {:02}{:02}{:02} {:x}",
137 formatted_version,
138 "FILE MERGE",
139 y,
140 m,
141 d,
142 hh,
143 mm,
144 ss,
145 timestamp.time_scale,
146 width = 19 - formatted_version.len(),
147 )
148 }
149
150 pub fn with_version(&self, version: Version) -> Self {
152 let mut s = self.clone();
153 s.version = version;
154 s
155 }
156
157 pub fn with_run_by(&self, run_by: &str) -> Self {
159 let mut s = self.clone();
160 s.run_by = Some(run_by.to_string());
161 s
162 }
163
164 pub fn with_receiver(&self, receiver: Receiver) -> Self {
166 let mut s = self.clone();
167 s.receiver = Some(receiver);
168 s
169 }
170
171 pub fn push_comment(&mut self, comment: &str) {
173 self.comments.push(comment.to_string());
174 }
175
176 pub fn with_comment(&self, comment: &str) -> Self {
178 let mut s = self.clone();
179 s.comments.push(comment.to_string());
180 s
181 }
182}