sct_reader/loaders/ese/
reader.rs

1use std::str::FromStr;
2use std::io::BufRead;
3use crate::loaders::euroscope::error::Error;
4use crate::loaders::euroscope::SectorResult;
5
6use super::partial::PartialEse;
7use super::Ese;
8
9
10#[derive(Debug)]
11enum FileSection {
12    FreeText,
13    SidsStars,
14    Positions,
15    Airspace,
16    Radar,
17    Ground,
18}
19
20impl FromStr for FileSection {
21    type Err = Error;
22    fn from_str(s: &str) -> Result<Self, Self::Err> {
23        let new_section = match s.to_uppercase().as_str() {
24            "[FREETEXT]" => Self::FreeText,
25            "[SIDSSTARS]" => Self::SidsStars,
26            "[POSITIONS]" => Self::Positions,
27            "[AIRSPACE]" => Self::Airspace,
28            "[RADAR]" => Self::Radar,
29            "[GROUND]" => Self::Ground,
30            _ => return Err(Error::InvalidFileSection),
31        };
32        Ok(new_section)
33    }
34}
35
36pub struct EseReader<R: BufRead> {
37    source: R,
38    current_section: FileSection,
39    partial_ese: PartialEse,
40    errors: Vec<(usize, String, Error)>,
41}
42
43impl<R: BufRead> EseReader<R> {
44    pub fn new(source: R) -> Self {
45        Self {
46            source,
47            current_section: FileSection::FreeText,
48            partial_ese: PartialEse::default(),
49            errors: vec![],
50        }
51    }
52
53    pub fn try_read(mut self) -> SectorResult<Ese> {
54        for (mut line_number, line) in self.source.lines().enumerate() {
55            if let Ok(line) = line {
56                let mut line = line.trim_end();
57                line_number += 1;
58
59                if line.is_empty() || line.starts_with(';') {
60                    continue;
61                }
62                if line.contains(';') {
63                    let mut line_split = line.split(';');
64                    line = line_split.next().unwrap().trim_end();
65                }
66                if line.starts_with('[') {
67                    match FileSection::from_str(line) {
68                        Ok(new_section) => self.current_section = new_section,
69                        Err(e) => self.errors.push((line_number + 1, line.to_owned(), e)),
70                    }
71                    continue;
72                }
73                if line.starts_with("OFFSET") {
74                    if let Err(e) = self.partial_ese.parse_offset(line) {
75                        self.errors.push((line_number, line.to_owned(), e));
76                    }
77                    continue;
78                }
79                if line.starts_with("#define") {
80                    if let Err(e) = self.partial_ese.parse_colour_line(line) {
81                        self.errors.push((line_number, line.to_owned(), e));
82                    }
83                    continue;
84                }
85
86                let result = match self.current_section {
87                    FileSection::FreeText => self.partial_ese.parse_freetext_line(line),
88                    FileSection::SidsStars => self.partial_ese.parse_sids_stars_line(line),
89                    FileSection::Positions => self.partial_ese.parse_atc_position_line(line),
90                    // FileSection::Airspace => todo!(),
91                    // FileSection::Radar => todo!(),
92                    // FileSection::Ground => todo!(),
93                    _ => continue,
94                };
95                if let Err(e) = result {
96                    self.errors.push((line_number, line.to_owned(), e));
97                }
98            }
99        }
100
101        let mut ese: Ese = self.partial_ese.try_into()?;
102        ese.non_critical_errors = self.errors;
103        Ok(ese)
104    }
105}