1#[derive(Default, Debug)]
2pub struct Fd<'a> {
3 pub org: Option<&'a str>,
4 pub dst: Option<&'a str>,
5 pub query_time: Option<&'a str>,
6 pub airline: Option<&'a str>,
7 pub command: Option<&'a str>,
8 pub currency: Option<&'a str>,
9 pub tpm: Option<&'a str>,
10 pub items: Option<Vec<FdItem<'a>>>,
11 pub raw_text: &'a str,
12}
13
14impl<'a> Fd<'a> {
15 pub fn parse(text: &'a str) -> anyhow::Result<Self> {
16 if text.is_empty() {
17 return Err(anyhow::Error::msg(
18 "fd parameter shouldn't be empty.".to_owned(),
19 ));
20 }
21 let lines = text.split(&['\r', '\n']);
22
23 let mut fdinfo = Self {
24 raw_text: text,
25 ..Default::default()
26 };
27 for line in lines {
28 if line.starts_with(">") {
29 continue;
30 } else if line.starts_with("PAGE") {
31 continue;
32 } else if line.trim().is_empty() {
33 continue;
34 } else if line.starts_with("FD:") {
35 match regex::Regex::captures(
36 ®ex::Regex::new(
37 r"(FD(?<COMMAND>.*)?)\s+/(?<CURRENCY>[^/]*)/TPM\s*(?<TPM>\d+)?",
38 )?,
39 line,
40 ) {
41 Some(caps) => match (
42 caps.name("COMMAND"),
43 caps.name("CURRENCY"),
44 caps.name("TPM"),
45 ) {
46 (Some(command), Some(currency), tpm) => {
47 fdinfo.command = Some(command.as_str());
48 fdinfo.currency = Some(currency.as_str());
49 fdinfo.tpm =tpm.and_then(|x| Some(x.as_str().trim()));match regex::Regex::captures(
52 ®ex::Regex::new(
53 r"(?<ORG>[A-Z]{3})(?<DST>[A-Z]{3})/(?<QUERYTIME>\d{2}\w{3}(?:\d{2})?)(?:/(?<AIRLINE>\w{2}))?",
54 )?,
55 command.as_str(),
56 ) {
57 Some(ccaps) => match (
58 ccaps.name("ORG"),
59 ccaps.name("DST"),
60 ccaps.name("QUERYTIME"),
61 ccaps.name("AIRLINE"),
62 ) {
63 (Some(org), Some(dst), Some(querytime), airline) => {
64 fdinfo.org = Some(org.as_str());
65 fdinfo.dst = Some(dst.as_str());
66 fdinfo.query_time = Some(querytime.as_str());
67 fdinfo.airline = airline.and_then(|x| Some(x.as_str().trim()));}
69 _ => {}
70 },
71 _ => {}
72 }
73 }
74 _ => {}
75 },
76 _ => {}
77 }
78 } else {
79 let mut item = FdItem {
80 ..Default::default()
81 };
82 let mut arr = line.split('/');
83 let index_airline = arr.next();
84 item.index = index_airline.and_then(|x| x[0..3].parse::<u8>().ok());
85 item.carrier = index_airline.and_then(|x| Some(x[3..5].trim()));
86 item.ticket_type = arr.next().and_then(|x| Some(x.trim()));
87 if let Some(ow_rt_price) = arr.next() {
88 let mut ow_rt_price = ow_rt_price.split('=');
89 item.ow_price_raw = ow_rt_price.next().and_then(|x| Some(x.trim()));
90 item.rt_price_raw = ow_rt_price.next().and_then(|x| Some(x.trim()));
91 }
92 item.cabin = arr.next().and_then(|x| Some(x.trim()));
93 item.class = arr.next().and_then(|x| Some(x.trim()));
94 arr.next();
95 item.begin_date = arr.next().and_then(|x| {
96 if x == "." {
97 fdinfo.query_time
98 } else {
99 Some(x)
100 }
101 });
102 item.end_date = arr.next().and_then(|x| Some(x.trim()));
103 item.policy_no = arr.next().and_then(|x| Some(x[0..6].trim()));
104
105 if item.index == Some(0u8) {
106 continue;
107 }
108 match &item.ow_price_raw {
109 Some(ow_price_raw) => {
110 if ow_price_raw.contains('%') {
111 if let Some(yfd) = fdinfo.items.as_ref().and_then(|x| {
112 x.iter().find_map(|n| {
113 if n.carrier == item.carrier
114 && n.cabin == Some("Y")
115 && n.ow_price.is_some()
116 {
117 n.ow_price
118 } else {
119 None
120 }
121 })
122 }) {
123 item.ow_price = Some(
124 yfd * ow_price_raw
125 .trim_end_matches('%')
126 .parse::<f32>()
127 .unwrap()
128 / 100.0,
129 );
130 }
131 } else {
132 item.ow_price = ow_price_raw.parse::<f32>().ok();
133 }
134 }
135 _ => {}
136 }
137 match &item.rt_price_raw {
138 Some(rt_price_raw) => {
139 if rt_price_raw.contains('%') {
140 if let Some(yfd) = fdinfo.items.as_ref().and_then(|x| {
141 x.iter().find_map(|n| {
142 if n.carrier == item.carrier
143 && n.cabin == Some("Y")
144 && n.rt_price.is_some()
145 {
146 n.rt_price
147 } else {
148 None
149 }
150 })
151 }) {
152 item.rt_price = Some(
153 yfd * rt_price_raw
154 .trim_end_matches('%')
155 .parse::<f32>()
156 .unwrap()
157 / 100.0,
158 );
159 }
160 } else {
161 item.rt_price = rt_price_raw.parse::<f32>().ok();
162 }
163 }
164 _ => {}
165 }
166 fdinfo
167 .items
168 .as_mut()
169 .get_or_insert(&mut Vec::new())
170 .push(item);
171 }
172 }
173
174 Ok(fdinfo)
175 }
176}
177
178#[derive(Default, Debug)]
179pub struct FdItem<'a> {
180 pub index: Option<u8>,
181 pub carrier: Option<&'a str>,
182 pub ticket_type: Option<&'a str>,
183 pub ow_price_raw: Option<&'a str>,
184 pub ow_price: Option<f32>,
185 pub rt_price_raw: Option<&'a str>,
186 pub rt_price: Option<f32>,
187 pub cabin: Option<&'a str>,
188 pub class: Option<&'a str>,
189 pub begin_date: Option<&'a str>,
190 pub end_date: Option<&'a str>,
191 pub policy_no: Option<&'a str>,
192}