1use crate::errors::{InvalidFieldFormatError, ParseError};
7use crate::traits::SwiftField;
8use std::collections::HashSet;
9
10use super::field_extractor::extract_field_content;
11
12#[derive(Debug)]
14pub struct MessageParser<'a> {
15 input: &'a str,
17 position: usize,
19 fields_seen: HashSet<String>,
21 message_type: String,
23 allow_duplicates: bool,
25}
26
27impl<'a> MessageParser<'a> {
28 pub fn new(input: &'a str, message_type: &str) -> Self {
30 Self {
31 input,
32 position: 0,
33 fields_seen: HashSet::new(),
34 message_type: message_type.to_string(),
35 allow_duplicates: false,
36 }
37 }
38
39 pub fn with_duplicates(mut self, allow: bool) -> Self {
41 self.allow_duplicates = allow;
42 self
43 }
44
45 pub fn parse_field<T: SwiftField>(&mut self, tag: &str) -> Result<T, ParseError> {
47 let field_content = self.extract_field(tag, false)?;
48
49 T::parse(&field_content).map_err(|e| {
51 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
52 field_tag: tag.to_string(),
53 component_name: "field".to_string(),
54 value: field_content,
55 format_spec: "field format".to_string(),
56 position: Some(self.position),
57 inner_error: e.to_string(),
58 }))
59 })
60 }
61
62 pub fn parse_optional_field<T: SwiftField>(
64 &mut self,
65 tag: &str,
66 ) -> Result<Option<T>, ParseError> {
67 if !self.detect_field(tag) {
70 return Ok(None);
71 }
72
73 match self.extract_field(tag, true) {
75 Ok(content) => {
76 let parsed = T::parse(&content).map_err(|e| {
77 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
78 field_tag: tag.to_string(),
79 component_name: "field".to_string(),
80 value: content,
81 format_spec: "field format".to_string(),
82 position: Some(self.position),
83 inner_error: e.to_string(),
84 }))
85 })?;
86 Ok(Some(parsed))
87 }
88 Err(_) => Ok(None), }
90 }
91
92 pub fn parse_repeated_field<T: SwiftField>(&mut self, tag: &str) -> Result<Vec<T>, ParseError> {
94 let mut results = Vec::new();
95
96 while let Ok(content) = self.extract_field(tag, true) {
98 let parsed = T::parse(&content).map_err(|e| {
99 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
100 field_tag: tag.to_string(),
101 component_name: "field".to_string(),
102 value: content,
103 format_spec: "field format".to_string(),
104 position: Some(self.position),
105 inner_error: e.to_string(),
106 }))
107 })?;
108 results.push(parsed);
109 }
110
111 Ok(results)
112 }
113
114 pub fn parse_variant_field<T: SwiftField>(&mut self, base_tag: &str) -> Result<T, ParseError> {
116 let variant = self.detect_variant(base_tag)?;
118 let full_tag = format!("{}{}", base_tag, variant);
119 let field_content = self.extract_field(&full_tag, false)?;
120
121 T::parse_with_variant(&field_content, Some(&variant), Some(base_tag)).map_err(|e| {
123 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
124 field_tag: full_tag,
125 component_name: "field".to_string(),
126 value: field_content,
127 format_spec: "field format".to_string(),
128 position: Some(self.position),
129 inner_error: e.to_string(),
130 }))
131 })
132 }
133
134 pub fn parse_optional_variant_field<T: SwiftField>(
136 &mut self,
137 base_tag: &str,
138 ) -> Result<Option<T>, ParseError> {
139 match self.detect_variant_optional(base_tag) {
140 Some(variant) => {
141 let full_tag = format!("{}{}", base_tag, variant);
142 if let Ok(content) = self.extract_field(&full_tag, true) {
143 let parsed = T::parse_with_variant(&content, Some(&variant), Some(base_tag))
144 .map_err(|e| {
145 ParseError::InvalidFieldFormat(Box::new(InvalidFieldFormatError {
146 field_tag: full_tag,
147 component_name: "field".to_string(),
148 value: content,
149 format_spec: "field format".to_string(),
150 position: Some(self.position),
151 inner_error: e.to_string(),
152 }))
153 })?;
154 Ok(Some(parsed))
155 } else {
156 Ok(None)
157 }
158 }
159 None => Ok(None), }
161 }
162
163 fn extract_field(&mut self, tag: &str, optional: bool) -> Result<String, ParseError> {
165 if !self.allow_duplicates && self.fields_seen.contains(tag) && !optional {
167 return Err(ParseError::InvalidFormat {
168 message: format!("Duplicate field: {}", tag),
169 });
170 }
171
172 #[cfg(debug_assertions)]
173 {
174 if tag.starts_with("21")
175 || tag.starts_with("32")
176 || tag.starts_with("57")
177 || tag.starts_with("59")
178 {
179 eprintln!(
180 "DEBUG extract_field('{}') at position {} (allow_duplicates={})",
181 tag, self.position, self.allow_duplicates
182 );
183 eprintln!(
184 " -> input slice (first 100 chars): {:?}",
185 &self.input[self.position..]
186 .chars()
187 .take(100)
188 .collect::<String>()
189 );
190 }
191 }
192
193 let extract_result = extract_field_content(&self.input[self.position..], tag);
195
196 #[cfg(debug_assertions)]
197 {
198 if tag.starts_with("21")
199 || tag.starts_with("32")
200 || tag.starts_with("57")
201 || tag.starts_with("59")
202 {
203 eprintln!(
204 " -> extract_field_content returned: {:?}",
205 extract_result
206 .as_ref()
207 .map(|(c, consumed)| (c.len(), *consumed))
208 );
209 }
210 }
211
212 match extract_result {
213 Some((content, consumed)) => {
214 #[cfg(debug_assertions)]
215 {
216 if tag.starts_with("21")
217 || tag.starts_with("32")
218 || tag.starts_with("57")
219 || tag.starts_with("59")
220 {
221 eprintln!(
222 " -> extracted content length={}, consumed={}, new position={}",
223 content.len(),
224 consumed,
225 self.position + consumed
226 );
227 eprintln!(
228 " -> content (first 40 chars): {:?}",
229 &content.chars().take(40).collect::<String>()
230 );
231 }
232 }
233 self.position += consumed;
234 if !self.allow_duplicates {
236 self.fields_seen.insert(tag.to_string());
237 }
238 Ok(content)
239 }
240 None => {
241 #[cfg(debug_assertions)]
242 {
243 if tag.starts_with("21")
244 || tag.starts_with("32")
245 || tag.starts_with("57")
246 || tag.starts_with("59")
247 {
248 eprintln!(" -> NOT FOUND");
249 }
250 }
251 if optional {
252 Err(ParseError::InvalidFormat {
254 message: format!("Optional field {} not found", tag),
255 })
256 } else {
257 Err(ParseError::MissingRequiredField {
258 field_tag: tag.to_string(),
259 field_name: tag.to_string(),
260 message_type: self.message_type.clone(),
261 position_in_block4: Some(self.position),
262 })
263 }
264 }
265 }
266 }
267
268 fn detect_variant(&self, base_tag: &str) -> Result<String, ParseError> {
270 let common_variants = vec!["A", "B", "C", "D", "F", "K", "L"];
272
273 let remaining = &self.input[self.position..];
275
276 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
278
279 #[cfg(debug_assertions)]
280 {
281 if base_tag == "59" {
282 eprintln!(
283 "DEBUG detect_variant('{}') at position {}",
284 base_tag, self.position
285 );
286 eprintln!(
287 " remaining (first 80 chars): {:?}",
288 &remaining.chars().take(80).collect::<String>()
289 );
290 eprintln!(
291 " trimmed (first 80 chars): {:?}",
292 &trimmed.chars().take(80).collect::<String>()
293 );
294 }
295 }
296
297 for variant in common_variants {
298 let full_tag = format!("{}{}", base_tag, variant);
299 if trimmed.starts_with(&format!(":{}:", full_tag)) {
300 #[cfg(debug_assertions)]
301 {
302 if base_tag == "59" {
303 eprintln!(" -> Found variant '{}'", variant);
304 }
305 }
306 return Ok(variant.to_string());
307 }
308 }
309
310 if trimmed.starts_with(&format!(":{}:", base_tag)) {
312 #[cfg(debug_assertions)]
313 {
314 if base_tag == "59" {
315 eprintln!(" -> Found no-variant (base tag only)");
316 }
317 }
318 return Ok(String::new());
319 }
320
321 #[cfg(debug_assertions)]
322 {
323 if base_tag == "59" {
324 eprintln!(" -> NOT FOUND - returning error");
325 }
326 }
327
328 Err(ParseError::MissingRequiredField {
329 field_tag: base_tag.to_string(),
330 field_name: base_tag.to_string(),
331 message_type: self.message_type.clone(),
332 position_in_block4: Some(self.position),
333 })
334 }
335
336 pub fn detect_variant_optional(&self, base_tag: &str) -> Option<String> {
338 let common_variants = vec!["A", "B", "C", "D", "F", "K", "L"];
340
341 let remaining = &self.input[self.position..];
343
344 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
346
347 for variant in common_variants {
349 let full_tag = format!("{}{}", base_tag, variant);
350 if trimmed.starts_with(&format!(":{}:", full_tag)) {
351 return Some(variant.to_string());
352 }
353 }
354
355 if trimmed.starts_with(&format!(":{}:", base_tag)) {
357 return Some(String::new());
358 }
359
360 None
361 }
362
363 pub fn position(&self) -> usize {
365 self.position
366 }
367
368 pub fn remaining(&self) -> &str {
370 &self.input[self.position..]
371 }
372
373 pub fn is_complete(&self) -> bool {
375 self.position >= self.input.len()
376 || self.remaining().trim().is_empty()
377 || self.remaining().trim() == "-"
378 }
379
380 pub fn detect_field(&self, tag: &str) -> bool {
382 let remaining = self.remaining();
383 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
384 trimmed.starts_with(&format!(":{}:", tag))
385 }
386
387 pub fn peek_field_variant(&self, base_tag: &str) -> Option<String> {
390 let remaining = self.remaining();
391 let trimmed = remaining.trim_start_matches(|c: char| c.is_whitespace());
392
393 for variant in [
395 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
396 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
397 ] {
398 let search_pattern = format!(":{}{}:", base_tag, variant);
399 if trimmed.starts_with(&search_pattern) {
400 return Some(variant.to_string());
401 }
402 }
403
404 let search_pattern = format!(":{}:", base_tag);
406 if trimmed.starts_with(&search_pattern) {
407 return Some("".to_string()); }
409
410 None
411 }
412}