sct_reader/loaders/euroscope/
loader.rs

1use std::{collections::HashMap, fs::File, io::{BufRead, BufReader}, path::{Path, PathBuf}, str::FromStr};
2use std::fs::read_dir;
3use anyhow::Context;
4use directories::UserDirs;
5
6use crate::loaders::ese::{self, reader::EseReader, Ese};
7
8use super::{colour::Colour, reader::SctReader, sector::Sector, symbology::{SymbologyAttribute, SymbologyInfo, SymbologyItem}, EsAsr};
9
10#[derive(Debug, Default)]
11pub struct EuroScopeResultProfile {
12    pub prf_name: String,
13    pub prf_file: String,
14    pub default_sector_id: String,
15    pub symbology: SymbologyInfo,
16    pub asrs: HashMap<String, EsAsr>
17}
18
19#[derive(Debug, Default)]
20pub struct EuroScopeResult {
21    pub profiles: Vec<EuroScopeResultProfile>,
22    pub sectors: HashMap<String, (Sector, Option<Ese>)>,
23}
24
25#[derive(Debug)]
26pub struct EuroScopeLoader {
27    pub prfs: Vec<EuroScopeLoaderPrf>
28}
29
30#[derive(Debug)]
31pub struct EuroScopeLoaderPrf {
32    pub prf_file: String,
33    pub symbology_file: String,
34    pub sector_file: String,
35    pub asr_files: Vec<(String, String)>
36}
37
38impl EuroScopeLoaderPrf {
39    pub fn try_new_from_prf(prf_file: impl AsRef<Path>) -> anyhow::Result<EuroScopeLoaderPrf> {
40        // Vars
41        let mut symbology_file = "".to_string();
42        let mut sector_file = "".to_string();
43        let mut asrs: Vec<(String, String)> = Vec::new();
44
45        // Read PRF File
46        let reader = BufReader::new(File::open(&prf_file)?);
47
48        for line in reader.lines() {
49            if let Ok(ln) = line {
50                let items = ln.split("\t").collect::<Vec<&str>>();
51                if items.len() > 0 {
52                    match items[0].to_lowercase().as_str() {
53                        "settings" => {
54                            if items.len() >= 3 {
55                                match items[1].to_lowercase().as_str() {
56                                    "settingsfilesymbology" => {
57                                        symbology_file =
58                                            EuroScopeLoader::try_convert_es_path(&prf_file, items[2])?
59                                                .canonicalize()?
60                                                .to_str()
61                                                .unwrap()
62                                                .to_owned();
63                                    }
64                                    "sector" => {
65                                        sector_file =
66                                            EuroScopeLoader::try_convert_es_path(&prf_file, items[2])?
67                                                .canonicalize().context(format!("Error opening sector file {:?}!", items[2]))?
68                                                .to_str()
69                                                .unwrap()
70                                                .to_owned();
71                                    }
72                                    &_ => {}
73                                }
74                            }
75                        }
76                        "asrfastkeys" => {
77                            let asr_path = EuroScopeLoader::try_convert_es_path(&prf_file, items[2]);
78                            if let Ok(asr_path_res) = asr_path {
79                                let canon_path = asr_path_res.canonicalize();
80                                if let Ok(canon_res) = canon_path {
81                                    asrs.push((items[1].to_owned(), canon_res.to_str().unwrap().to_owned()));
82                                }
83                            }
84                        },
85                        &_ => {}
86                    }
87                }
88            }
89        }
90
91        Ok(EuroScopeLoaderPrf {
92            prf_file: prf_file
93                .as_ref()
94                .canonicalize()?
95                .to_str()
96                .unwrap()
97                .to_string(),
98            symbology_file: symbology_file.to_string(),
99            sector_file: sector_file.to_string(),
100            asr_files: asrs
101        })
102    }
103}
104
105impl EuroScopeLoader {
106    pub fn try_new_from_dir(package_dir: impl AsRef<Path>) -> anyhow::Result<EuroScopeLoader> {
107        let mut results = Vec::new();
108        if package_dir.as_ref().is_dir() {
109            for entry in read_dir(package_dir)? {
110                let entry = entry?;
111                let path = entry.path();
112                if path.is_dir() {
113                    results.append(&mut Self::try_new_from_dir(&path)?.prfs);
114                } else if entry.file_name().to_str().unwrap().contains(".prf"){
115                    if let Ok(result) = EuroScopeLoaderPrf::try_new_from_prf(&path) {
116                        results.push(result);
117                    }
118                }
119            }
120        }
121
122        Ok(EuroScopeLoader {
123            prfs: results
124        })
125    }
126
127    pub fn try_read(&mut self) -> anyhow::Result<EuroScopeResult> {
128        let mut ret_val = EuroScopeResult::default();
129
130        for prf in &self.prfs {
131            let mut res_prf = EuroScopeResultProfile::default();
132
133            res_prf.prf_file = prf.prf_file.to_string();
134            res_prf.prf_name = Path::new(&prf.prf_file).file_stem().unwrap_or_default().to_str().unwrap().to_string();
135
136            // Load symbology
137            res_prf.symbology = SymbologyInfo::try_from_file(&prf.symbology_file)?;
138
139            res_prf.default_sector_id = prf.sector_file.to_string();
140
141            // Load Main Sector File
142            if (!ret_val.sectors.contains_key(&prf.sector_file)){
143                let sct_reader = SctReader::new(BufReader::new(File::open(&prf.sector_file)?));
144                let sct_result = sct_reader.try_read()?;
145                let ese_file = prf.sector_file.replace(".sct", ".ese");
146                let sct_ese_result = match std::fs::exists(&ese_file) {
147                    Ok(true) => {
148                        if let Ok(file) = File::open(&ese_file) {
149                            let reader = EseReader::new(BufReader::new(file));
150                            reader.try_read().ok()
151                        } else{
152                            None
153                        }
154                    },
155                    _ => None
156                };
157
158                ret_val.sectors.insert(prf.sector_file.to_string(), (sct_result, sct_ese_result));
159            }
160
161            // Load ASRs
162            for asr_source in &prf.asr_files {
163                let mut asr = EsAsr::try_from_asr_file(&asr_source.1)?;
164                if !asr.1.is_empty() {
165                    if let Ok(asr_sector_pbuf) = Self::try_convert_es_path(&prf.prf_file, &asr.1)?.canonicalize() {
166                        let asr_sector_path = asr_sector_pbuf.as_os_str().to_str().unwrap_or_default().to_string();
167                        if !ret_val.sectors.contains_key(&asr_sector_path) {
168                            let asr_sct_reader = SctReader::new(BufReader::new(File::open(&asr_sector_path)?));
169                            let asr_sct_result = asr_sct_reader.try_read()?;
170    
171                            let asr_ese_file = asr_sector_path.replace(".sct", ".ese");
172                            let asr_sct_ese_result = match std::fs::exists(&asr_ese_file) {
173                                Ok(true) => {
174                                    if let Ok(file) = File::open(&asr_ese_file) {
175                                        let reader = EseReader::new(BufReader::new(file));
176                                        reader.try_read().ok()
177                                    } else {
178                                        None
179                                    }
180                                },
181                                _ => None
182                            };
183                            ret_val.sectors.insert(asr_sector_path.to_string(), (asr_sct_result, asr_sct_ese_result));
184                        }
185                        asr.0.sector_file_id = Some(asr_sector_path.to_string());
186                    } else {
187                        asr.0.sector_file_id = Some(res_prf.default_sector_id.clone());
188                    }                 
189                } else {
190                    asr.0.sector_file_id = Some(res_prf.default_sector_id.clone());
191                }
192                asr.0.name = Path::new(&asr_source.1).file_stem().unwrap_or_default().to_str().unwrap().to_string();
193
194                res_prf.asrs.insert(asr_source.0.to_string(), asr.0);
195            }
196
197            ret_val.profiles.push(res_prf);
198        }
199
200        Ok(ret_val)
201    }
202
203    pub fn try_convert_es_path(
204        prf_file_path: impl AsRef<Path>,
205        es_path: &str,
206    ) -> anyhow::Result<PathBuf> {
207        let split_es_path = es_path.split("\\").collect::<Vec<&str>>();
208        let mut new_es_path = PathBuf::from("");
209        for item in &split_es_path {
210            new_es_path.push(item);
211        }
212
213        // Relative to PRF folder
214        if split_es_path.len() > 0 && split_es_path[0] == "" {
215            return Ok(prf_file_path
216                .as_ref()
217                .parent()
218                .context("Could not get parent dir of prf file!")?
219                .join(new_es_path));
220        }
221
222        let path = 
223        directories::BaseDirs::new()
224        .context("Failed to get User Directories")?
225        .config_dir()
226        .join("EuroScope")
227        .join(new_es_path.clone());
228
229
230        if path.exists() {
231            return Ok(path);
232        }
233
234        Ok(UserDirs::new()
235            .context("Failed to get User Directories")?
236            .document_dir()
237            .context("Could not get Documents dir!")?
238            .join("EuroScope")
239            .join(new_es_path))
240    }
241}