1use chrono::NaiveDate;
6use serde::{Deserialize, Serialize};
7
8use super::common::*;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct HeaderRecord {
14 pub unique_system_identifier: i64,
16
17 pub uls_file_number: Option<String>,
19 pub ebf_number: Option<String>,
20 pub call_sign: Option<String>,
21 pub license_status: Option<char>,
22 pub radio_service_code: Option<String>,
23 pub grant_date: Option<NaiveDate>,
24 pub expired_date: Option<NaiveDate>,
25 pub cancellation_date: Option<NaiveDate>,
26 pub eligibility_rule_num: Option<String>,
27 pub applicant_type_code_reserved: Option<char>,
28 pub alien: Option<char>,
29 pub alien_government: Option<char>,
30 pub alien_corporation: Option<char>,
31 pub alien_officer: Option<char>,
32 pub alien_control: Option<char>,
33 pub revoked: Option<char>,
34 pub convicted: Option<char>,
35 pub adjudged: Option<char>,
36 pub involved_reserved: Option<char>,
37 pub common_carrier: Option<char>,
38 pub non_common_carrier: Option<char>,
39 pub private_comm: Option<char>,
40 pub fixed: Option<char>,
41 pub mobile: Option<char>,
42 pub radiolocation: Option<char>,
43 pub satellite: Option<char>,
44 pub developmental_or_sta: Option<char>,
45 pub interconnected_service: Option<char>,
46 pub certifier_first_name: Option<String>,
47 pub certifier_mi: Option<char>,
48 pub certifier_last_name: Option<String>,
49 pub certifier_suffix: Option<String>,
50 pub certifier_title: Option<String>,
51 pub sex: Option<char>,
52 pub african_american: Option<char>,
53 pub native_american: Option<char>,
54 pub hawaiian: Option<char>,
55 pub asian: Option<char>,
56 pub white: Option<char>,
57 pub ethnicity: Option<char>,
58 pub effective_date: Option<NaiveDate>,
59 pub last_action_date: Option<NaiveDate>,
60 pub auction_id: Option<i32>,
61 pub reg_stat_broad_serv: Option<char>,
62 pub band_manager: Option<char>,
63 pub type_serv_broad_serv: Option<char>,
64 pub alien_ruling: Option<char>,
65 pub licensee_name_change: Option<char>,
66 pub whitespace_ind: Option<char>,
67 pub additional_cert_choice: Option<char>,
68 pub additional_cert_answer: Option<char>,
69 pub discontinuation_ind: Option<char>,
70 pub regulatory_compliance_ind: Option<char>,
71 pub eligibility_cert_900: Option<char>,
72 pub transition_plan_cert_900: Option<char>,
73 pub return_spectrum_cert_900: Option<char>,
74 pub payment_cert_900: Option<char>,
75}
76
77impl HeaderRecord {
78 pub fn from_fields(fields: &[&str]) -> Self {
80 Self {
81 unique_system_identifier: parse_i64_or_default(fields.get(1).unwrap_or(&"")),
82 uls_file_number: parse_opt_string(fields.get(2).unwrap_or(&"")),
83 ebf_number: parse_opt_string(fields.get(3).unwrap_or(&"")),
84 call_sign: parse_opt_string(fields.get(4).unwrap_or(&"")),
85 license_status: parse_opt_char(fields.get(5).unwrap_or(&"")),
86 radio_service_code: parse_opt_string(fields.get(6).unwrap_or(&"")),
87 grant_date: parse_uls_date(fields.get(7).unwrap_or(&"")),
88 expired_date: parse_uls_date(fields.get(8).unwrap_or(&"")),
89 cancellation_date: parse_uls_date(fields.get(9).unwrap_or(&"")),
90 eligibility_rule_num: parse_opt_string(fields.get(10).unwrap_or(&"")),
91 applicant_type_code_reserved: parse_opt_char(fields.get(11).unwrap_or(&"")),
92 alien: parse_opt_char(fields.get(12).unwrap_or(&"")),
93 alien_government: parse_opt_char(fields.get(13).unwrap_or(&"")),
94 alien_corporation: parse_opt_char(fields.get(14).unwrap_or(&"")),
95 alien_officer: parse_opt_char(fields.get(15).unwrap_or(&"")),
96 alien_control: parse_opt_char(fields.get(16).unwrap_or(&"")),
97 revoked: parse_opt_char(fields.get(17).unwrap_or(&"")),
98 convicted: parse_opt_char(fields.get(18).unwrap_or(&"")),
99 adjudged: parse_opt_char(fields.get(19).unwrap_or(&"")),
100 involved_reserved: parse_opt_char(fields.get(20).unwrap_or(&"")),
101 common_carrier: parse_opt_char(fields.get(21).unwrap_or(&"")),
102 non_common_carrier: parse_opt_char(fields.get(22).unwrap_or(&"")),
103 private_comm: parse_opt_char(fields.get(23).unwrap_or(&"")),
104 fixed: parse_opt_char(fields.get(24).unwrap_or(&"")),
105 mobile: parse_opt_char(fields.get(25).unwrap_or(&"")),
106 radiolocation: parse_opt_char(fields.get(26).unwrap_or(&"")),
107 satellite: parse_opt_char(fields.get(27).unwrap_or(&"")),
108 developmental_or_sta: parse_opt_char(fields.get(28).unwrap_or(&"")),
109 interconnected_service: parse_opt_char(fields.get(29).unwrap_or(&"")),
110 certifier_first_name: parse_opt_string(fields.get(30).unwrap_or(&"")),
111 certifier_mi: parse_opt_char(fields.get(31).unwrap_or(&"")),
112 certifier_last_name: parse_opt_string(fields.get(32).unwrap_or(&"")),
113 certifier_suffix: parse_opt_string(fields.get(33).unwrap_or(&"")),
114 certifier_title: parse_opt_string(fields.get(34).unwrap_or(&"")),
115 sex: parse_opt_char(fields.get(35).unwrap_or(&"")),
116 african_american: parse_opt_char(fields.get(36).unwrap_or(&"")),
117 native_american: parse_opt_char(fields.get(37).unwrap_or(&"")),
118 hawaiian: parse_opt_char(fields.get(38).unwrap_or(&"")),
119 asian: parse_opt_char(fields.get(39).unwrap_or(&"")),
120 white: parse_opt_char(fields.get(40).unwrap_or(&"")),
121 ethnicity: parse_opt_char(fields.get(41).unwrap_or(&"")),
122 effective_date: parse_uls_date(fields.get(42).unwrap_or(&"")),
123 last_action_date: parse_uls_date(fields.get(43).unwrap_or(&"")),
124 auction_id: parse_opt_i32(fields.get(44).unwrap_or(&"")),
125 reg_stat_broad_serv: parse_opt_char(fields.get(45).unwrap_or(&"")),
126 band_manager: parse_opt_char(fields.get(46).unwrap_or(&"")),
127 type_serv_broad_serv: parse_opt_char(fields.get(47).unwrap_or(&"")),
128 alien_ruling: parse_opt_char(fields.get(48).unwrap_or(&"")),
129 licensee_name_change: parse_opt_char(fields.get(49).unwrap_or(&"")),
130 whitespace_ind: parse_opt_char(fields.get(50).unwrap_or(&"")),
131 additional_cert_choice: parse_opt_char(fields.get(51).unwrap_or(&"")),
132 additional_cert_answer: parse_opt_char(fields.get(52).unwrap_or(&"")),
133 discontinuation_ind: parse_opt_char(fields.get(53).unwrap_or(&"")),
134 regulatory_compliance_ind: parse_opt_char(fields.get(54).unwrap_or(&"")),
135 eligibility_cert_900: parse_opt_char(fields.get(55).unwrap_or(&"")),
136 transition_plan_cert_900: parse_opt_char(fields.get(56).unwrap_or(&"")),
137 return_spectrum_cert_900: parse_opt_char(fields.get(57).unwrap_or(&"")),
138 payment_cert_900: parse_opt_char(fields.get(58).unwrap_or(&"")),
139 }
140 }
141
142 pub fn is_active(&self) -> bool {
144 self.license_status == Some('A')
145 }
146
147 pub fn is_expired(&self) -> bool {
149 self.license_status == Some('E')
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_header_from_fields() {
159 let fields: Vec<&str> = vec![
160 "HD",
161 "123456789",
162 "0000123456",
163 "",
164 "W1AW",
165 "A",
166 "HA",
167 "01/01/2020",
168 "01/01/2030",
169 "",
170 "",
171 "",
172 "",
173 "",
174 "",
175 "",
176 "",
177 "",
178 "",
179 "",
180 "",
181 "",
182 "",
183 "",
184 "",
185 "",
186 "",
187 "",
188 "",
189 "",
190 "",
191 "",
192 "",
193 "",
194 "",
195 "",
196 "",
197 "",
198 "",
199 "",
200 "",
201 "01/01/2020",
202 "06/15/2024",
203 "",
204 "",
205 "",
206 "",
207 "",
208 "",
209 "",
210 "",
211 "",
212 "",
213 "",
214 "",
215 "",
216 ];
217 let record = HeaderRecord::from_fields(&fields);
218 assert_eq!(record.unique_system_identifier, 123456789);
219 assert_eq!(record.call_sign, Some("W1AW".to_string()));
220 assert_eq!(record.license_status, Some('A'));
221 assert_eq!(record.radio_service_code, Some("HA".to_string()));
222 assert!(record.is_active());
223 }
224
225 #[test]
226 fn test_header_empty_fields() {
227 let fields: Vec<&str> = vec!["HD", "", "", "", "", "", ""];
228 let record = HeaderRecord::from_fields(&fields);
229 assert_eq!(record.unique_system_identifier, 0);
230 assert_eq!(record.call_sign, None);
231 assert!(!record.is_active());
232 }
233}