1use std::collections::HashMap;
4use std::sync::Mutex;
5
6use mig_assembly::ConversionService;
7use mig_bo4e::engine::DataBundle;
8use mig_bo4e::MappingEngine;
9
10use crate::data_dir::DataDir;
11use crate::error::MapperError;
12
13pub struct Bo4eResult {
15 pub pid: String,
17 pub message_type: String,
19 pub variant: String,
21 pub bo4e: serde_json::Value,
23}
24
25pub struct Mapper {
43 data_dir: DataDir,
44 bundles: Mutex<HashMap<String, DataBundle>>,
45}
46
47impl Mapper {
48 pub fn from_data_dir(data_dir: DataDir) -> Result<Self, MapperError> {
53 let mapper = Self {
54 data_dir,
55 bundles: Mutex::new(HashMap::new()),
56 };
57 let eager_fvs: Vec<String> = mapper.data_dir.eager_fvs().to_vec();
58 for fv in &eager_fvs {
59 mapper.ensure_bundle_loaded(fv)?;
60 }
61 Ok(mapper)
62 }
63
64 fn ensure_bundle_loaded(&self, fv: &str) -> Result<(), MapperError> {
66 let mut bundles = self.bundles.lock().unwrap();
67 if bundles.contains_key(fv) {
68 return Ok(());
69 }
70 let path = self.data_dir.bundle_path(fv);
71 if !path.exists() {
72 return Err(MapperError::BundleNotFound { fv: fv.to_string() });
73 }
74 let bundle = DataBundle::load(&path)?;
75 bundles.insert(fv.to_string(), bundle);
76 Ok(())
77 }
78
79 pub fn conversion_service(
83 &self,
84 fv: &str,
85 variant: &str,
86 ) -> Result<ConversionService, MapperError> {
87 self.ensure_bundle_loaded(fv)?;
88 let bundles = self.bundles.lock().unwrap();
89 let bundle = bundles.get(fv).unwrap();
90 let vc = bundle
91 .variant(variant)
92 .ok_or_else(|| MapperError::VariantNotFound {
93 fv: fv.to_string(),
94 variant: variant.to_string(),
95 })?;
96 let mig = vc
97 .mig_schema
98 .as_ref()
99 .ok_or_else(|| MapperError::VariantNotFound {
100 fv: fv.to_string(),
101 variant: format!("{variant} (no MIG schema in bundle)"),
102 })?;
103 Ok(ConversionService::from_mig(mig.clone()))
104 }
105
106 pub fn engine(&self, fv: &str, variant: &str, pid: &str) -> Result<MappingEngine, MapperError> {
110 self.ensure_bundle_loaded(fv)?;
111 let bundles = self.bundles.lock().unwrap();
112 let bundle = bundles.get(fv).unwrap();
113 let vc = bundle
114 .variant(variant)
115 .ok_or_else(|| MapperError::VariantNotFound {
116 fv: fv.to_string(),
117 variant: variant.to_string(),
118 })?;
119 let pid_key = format!("pid_{pid}");
120 let defs = vc
121 .combined_defs
122 .get(&pid_key)
123 .ok_or_else(|| MapperError::PidNotFound {
124 fv: fv.to_string(),
125 variant: variant.to_string(),
126 pid: pid.to_string(),
127 })?;
128 Ok(MappingEngine::from_definitions(defs.clone()))
129 }
130
131 pub fn validate_pid(
136 &self,
137 json: &serde_json::Value,
138 fv: &str,
139 variant: &str,
140 pid: &str,
141 ) -> Result<Vec<mig_bo4e::PidValidationError>, MapperError> {
142 self.ensure_bundle_loaded(fv)?;
143 let bundles = self.bundles.lock().unwrap();
144 let bundle = bundles.get(fv).unwrap();
145 let vc = bundle
146 .variant(variant)
147 .ok_or_else(|| MapperError::VariantNotFound {
148 fv: fv.to_string(),
149 variant: variant.to_string(),
150 })?;
151 let pid_key = format!("pid_{pid}");
152 let requirements =
153 vc.pid_requirements
154 .get(&pid_key)
155 .ok_or_else(|| MapperError::PidNotFound {
156 fv: fv.to_string(),
157 variant: variant.to_string(),
158 pid: pid.to_string(),
159 })?;
160
161 Ok(mig_bo4e::pid_validation::validate_pid_json(
162 json,
163 requirements,
164 ))
165 }
166
167 pub fn validate_pid_struct(
179 &self,
180 value: &impl serde::Serialize,
181 fv: &str,
182 variant: &str,
183 pid: &str,
184 ) -> Result<Vec<mig_bo4e::PidValidationError>, MapperError> {
185 let json = serde_json::to_value(value).map_err(|e| {
186 MapperError::Mapping(mig_bo4e::MappingError::TypeConversion(e.to_string()))
187 })?;
188 self.validate_pid(&json, fv, variant, pid)
189 }
190
191 pub fn validate_pid_with_conditions(
199 &self,
200 json: &serde_json::Value,
201 fv: &str,
202 variant: &str,
203 pid: &str,
204 ) -> Result<Vec<mig_bo4e::PidValidationError>, MapperError> {
205 self.ensure_bundle_loaded(fv)?;
206 let bundles = self.bundles.lock().unwrap();
207 let bundle = bundles.get(fv).unwrap();
208 let vc = bundle
209 .variant(variant)
210 .ok_or_else(|| MapperError::VariantNotFound {
211 fv: fv.to_string(),
212 variant: variant.to_string(),
213 })?;
214 let pid_key = format!("pid_{pid}");
215
216 let requirements =
217 vc.pid_requirements
218 .get(&pid_key)
219 .ok_or_else(|| MapperError::PidNotFound {
220 fv: fv.to_string(),
221 variant: variant.to_string(),
222 pid: pid.to_string(),
223 })?;
224
225 let evaluator = crate::evaluator_factory::create_evaluator(variant, fv);
227
228 if let Some(evaluator) = evaluator {
229 let defs = vc
231 .combined_defs
232 .get(&pid_key)
233 .ok_or_else(|| MapperError::PidNotFound {
234 fv: fv.to_string(),
235 variant: variant.to_string(),
236 pid: pid.to_string(),
237 })?;
238 let engine = MappingEngine::from_definitions(defs.clone());
239 let tree = engine.map_all_reverse(json, None);
240
241 let segments = crate::tree_to_segments::tree_to_owned_segments(&tree);
243
244 Ok(crate::evaluator_factory::validate_with_boxed_evaluator(
246 evaluator.as_ref(),
247 json,
248 requirements,
249 pid,
250 &segments,
251 ))
252 } else {
253 Ok(mig_bo4e::pid_validation::validate_pid_json(
255 json,
256 requirements,
257 ))
258 }
259 }
260
261 pub fn loaded_format_versions(&self) -> Vec<String> {
263 self.bundles.lock().unwrap().keys().cloned().collect()
264 }
265
266 pub fn variants(&self, fv: &str) -> Result<Vec<String>, MapperError> {
270 self.ensure_bundle_loaded(fv)?;
271 let bundles = self.bundles.lock().unwrap();
272 let bundle = bundles.get(fv).unwrap();
273 Ok(bundle.variants.keys().cloned().collect())
274 }
275}