1#![allow(clippy::style, clippy::complexity)]
9
10#[allow(unused_imports)]
11use crate::eval::format_validators::*;
12use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
13use crate::generated::fv2504::UtilmdStromConditionEvaluatorFV2504;
14
15pub struct UtilmdStromConditionEvaluatorFV2510 {
20 fallback: UtilmdStromConditionEvaluatorFV2504,
21}
22
23impl Default for UtilmdStromConditionEvaluatorFV2510 {
24 fn default() -> Self {
25 Self {
26 fallback: UtilmdStromConditionEvaluatorFV2504::default(),
27 }
28 }
29}
30
31const FV2510_OVERRIDES: &[u32] = &[
33 2, 3, 20, 28, 29, 79, 136, 139, 157, 158, 168, 169, 242, 253, 258, 263, 297, 312, 313, 326,
34 328, 346, 413, 414, 415, 416, 461, 534, 557, 560, 561, 562, 564, 565, 578, 681, 686, 2000,
35 2016, 2121,
36];
37
38const FV2510_EXTERNAL: &[u32] = &[3, 326, 328];
40
41impl ConditionEvaluator for UtilmdStromConditionEvaluatorFV2510 {
42 fn message_type(&self) -> &str {
43 "UTILMD_Strom"
44 }
45
46 fn format_version(&self) -> &str {
47 "FV2510"
48 }
49
50 fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
51 match condition {
52 2 => self.evaluate_2(ctx),
53 3 => self.evaluate_3(ctx),
54 20 => self.evaluate_20(ctx),
55 28 => self.evaluate_28(ctx),
56 29 => self.evaluate_29(ctx),
57 79 => self.evaluate_79(ctx),
58 136 => self.evaluate_136(ctx),
59 139 => self.evaluate_139(ctx),
60 157 => self.evaluate_157(ctx),
61 158 => self.evaluate_158(ctx),
62 168 => self.evaluate_168(ctx),
63 169 => self.evaluate_169(ctx),
64 242 => self.evaluate_242(ctx),
65 253 => self.evaluate_253(ctx),
66 258 => self.evaluate_258(ctx),
67 263 => self.evaluate_263(ctx),
68 297 => self.evaluate_297(ctx),
69 312 => self.evaluate_312(ctx),
70 313 => self.evaluate_313(ctx),
71 326 => self.evaluate_326(ctx),
72 328 => self.evaluate_328(ctx),
73 346 => self.evaluate_346(ctx),
74 413 => self.evaluate_413(ctx),
75 414 => self.evaluate_414(ctx),
76 415 => self.evaluate_415(ctx),
77 416 => self.evaluate_416(ctx),
78 461 => self.evaluate_461(ctx),
79 534 => self.evaluate_534(ctx),
80 557 => self.evaluate_557(ctx),
81 560 => self.evaluate_560(ctx),
82 561 => self.evaluate_561(ctx),
83 562 => self.evaluate_562(ctx),
84 564 => self.evaluate_564(ctx),
85 565 => self.evaluate_565(ctx),
86 578 => self.evaluate_578(ctx),
87 681 => self.evaluate_681(ctx),
88 686 => self.evaluate_686(ctx),
89 2000 => self.evaluate_2000(ctx),
90 2016 => self.evaluate_2016(ctx),
91 2121 => self.evaluate_2121(ctx),
92 other => self.fallback.evaluate(other, ctx),
93 }
94 }
95
96 fn is_external(&self, condition: u32) -> bool {
97 if FV2510_OVERRIDES.contains(&condition) {
98 FV2510_EXTERNAL.contains(&condition)
99 } else {
100 self.fallback.is_external(condition)
101 }
102 }
103
104 fn is_known(&self, condition: u32) -> bool {
105 FV2510_OVERRIDES.contains(&condition) || self.fallback.is_known(condition)
106 }
107}
108
109impl UtilmdStromConditionEvaluatorFV2510 {
110 fn evaluate_2(&self, ctx: &EvaluationContext) -> ConditionResult {
112 ctx.has_segment_matching("UNH", &[(3, 0, "1")])
113 }
114
115 fn evaluate_3(&self, ctx: &EvaluationContext) -> ConditionResult {
118 ctx.external.evaluate("is_highest_sequence_in_split")
119 }
120
121 fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
123 let nav = match ctx.navigator() {
124 Some(n) => n,
125 None => return ctx.has_qualified_value("CCI", 0, "Z30", 2, 0, &["Z07"]),
126 };
127 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
128 for i in 0..sg8_count {
129 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
130 let has_z01 = seq_segs.iter().any(|s| {
131 s.elements
132 .first()
133 .and_then(|e| e.first())
134 .is_some_and(|v| v == "Z01")
135 });
136 if !has_z01 {
137 continue;
138 }
139 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
140 for j in 0..sg10_count {
141 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
142 if ccis.iter().any(|s| {
143 s.elements
144 .first()
145 .and_then(|e| e.first())
146 .is_some_and(|v| v == "Z30")
147 && s.elements
148 .get(2)
149 .and_then(|e| e.first())
150 .is_some_and(|v| v == "Z07")
151 }) {
152 return ConditionResult::True;
153 }
154 }
155 }
156 ConditionResult::False
157 }
158
159 fn evaluate_28(&self, ctx: &EvaluationContext) -> ConditionResult {
162 let nav = match ctx.navigator() {
163 Some(n) => n,
164 None => {
165 let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
166 let found = sts_segs.iter().any(|s| {
167 let code = s
168 .elements
169 .get(2)
170 .and_then(|e| e.first())
171 .map(|v| v.as_str());
172 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
173 (code == Some("A04") && list == Some("E_0017"))
174 || (code == Some("A03") && list == Some("E_0052"))
175 });
176 return ConditionResult::from(!found);
177 }
178 };
179 let sg4_count = nav.group_instance_count(&["SG4"]);
180 for i in 0..sg4_count {
181 let ide_segs = nav.find_segments_in_group("IDE", &["SG4"], i);
182 let has_ide_24 = ide_segs.iter().any(|s| {
183 s.elements
184 .first()
185 .and_then(|e| e.first())
186 .is_some_and(|v| v == "24")
187 });
188 if !has_ide_24 {
189 continue;
190 }
191 let sts_segs = nav.find_segments_in_group("STS", &["SG4"], i);
192 let found = sts_segs.iter().any(|s| {
193 let qual = s
194 .elements
195 .first()
196 .and_then(|e| e.first())
197 .map(|v| v.as_str());
198 let code = s
199 .elements
200 .get(2)
201 .and_then(|e| e.first())
202 .map(|v| v.as_str());
203 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
204 qual == Some("E01")
205 && ((code == Some("A04") && list == Some("E_0017"))
206 || (code == Some("A03") && list == Some("E_0052")))
207 });
208 if !found {
209 return ConditionResult::True;
210 }
211 }
212 ConditionResult::False
213 }
214
215 fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
218 let nav = match ctx.navigator() {
219 Some(n) => n,
220 None => {
221 let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
222 let found = sts_segs.iter().any(|s| {
223 let code = s
224 .elements
225 .get(2)
226 .and_then(|e| e.first())
227 .map(|v| v.as_str());
228 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
229 (code == Some("A06") && list == Some("E_0017"))
230 || (code == Some("A05") && list == Some("E_0052"))
231 });
232 return ConditionResult::from(!found);
233 }
234 };
235 let sg4_count = nav.group_instance_count(&["SG4"]);
236 for i in 0..sg4_count {
237 let ide_segs = nav.find_segments_in_group("IDE", &["SG4"], i);
238 let has_ide_24 = ide_segs.iter().any(|s| {
239 s.elements
240 .first()
241 .and_then(|e| e.first())
242 .is_some_and(|v| v == "24")
243 });
244 if !has_ide_24 {
245 continue;
246 }
247 let sts_segs = nav.find_segments_in_group("STS", &["SG4"], i);
248 let found = sts_segs.iter().any(|s| {
249 let qual = s
250 .elements
251 .first()
252 .and_then(|e| e.first())
253 .map(|v| v.as_str());
254 let code = s
255 .elements
256 .get(2)
257 .and_then(|e| e.first())
258 .map(|v| v.as_str());
259 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
260 qual == Some("E01")
261 && ((code == Some("A06") && list == Some("E_0017"))
262 || (code == Some("A05") && list == Some("E_0052")))
263 });
264 if !found {
265 return ConditionResult::True;
266 }
267 }
268 ConditionResult::False
269 }
270
271 fn evaluate_79(&self, ctx: &EvaluationContext) -> ConditionResult {
273 ctx.has_segment_matching("STS", &[(0, 0, "7"), (2, 0, "Z33")])
276 }
277
278 fn evaluate_136(&self, ctx: &EvaluationContext) -> ConditionResult {
280 let nav = match ctx.navigator() {
281 Some(n) => n,
282 None => return ctx.has_qualified_value("CAV", 0, "EHZ", 0, 0, &["EHZ"]),
283 };
284 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
285 for i in 0..sg8_count {
286 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
287 for j in 0..sg10_count {
288 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
289 let has_cci_e13 = ccis.iter().any(|s| {
290 s.elements
291 .get(2)
292 .and_then(|e| e.first())
293 .is_some_and(|v| v == "E13")
294 });
295 if has_cci_e13 {
296 let cavs =
297 nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
298 if cavs.iter().any(|s| {
299 s.elements
300 .first()
301 .and_then(|e| e.first())
302 .is_some_and(|v| v == "EHZ")
303 }) {
304 return ConditionResult::True;
305 }
306 }
307 }
308 }
309 ConditionResult::False
310 }
311
312 fn evaluate_139(&self, ctx: &EvaluationContext) -> ConditionResult {
315 let nav = match ctx.navigator() {
316 Some(n) => n,
317 None => return ctx.lacks_qualifier("CAV", 0, "IVA"),
318 };
319 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
320 for i in 0..sg8_count {
321 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
322 for j in 0..sg10_count {
323 let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
324 if cavs.iter().any(|s| {
325 s.elements
326 .first()
327 .and_then(|e| e.first())
328 .is_some_and(|v| v == "IVA")
329 }) {
330 return ConditionResult::False;
331 }
332 }
333 }
334 ConditionResult::True
335 }
336
337 fn evaluate_157(&self, ctx: &EvaluationContext) -> ConditionResult {
339 let result = ctx.has_segment_matching("STS", &[(0, 0, "7"), (2, 0, "Z33"), (3, 0, "ZZB")]);
340 match result {
341 ConditionResult::True => ConditionResult::False,
342 ConditionResult::False => ConditionResult::True,
343 ConditionResult::Unknown => ConditionResult::Unknown,
344 }
345 }
346
347 fn evaluate_158(&self, ctx: &EvaluationContext) -> ConditionResult {
349 ConditionResult::from(ctx.self_segment_value_equals("DTM", 0, 2, "106"))
350 }
351
352 fn evaluate_168(&self, ctx: &EvaluationContext) -> ConditionResult {
354 ctx.this_group_has_qualified_value(
356 "PIA",
357 0,
358 "Z02",
359 1,
360 0,
361 &["1-02-0-002", "1-02-0-003", "1-02-0-004"],
362 &["SG4", "SG8"],
363 )
364 }
365
366 fn evaluate_169(&self, ctx: &EvaluationContext) -> ConditionResult {
369 let nav = match ctx.navigator() {
370 Some(n) => n,
371 None => return ConditionResult::Unknown,
372 };
373 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
374 let mut sg8_data: Vec<(String, String)> = Vec::new();
375 for i in 0..sg8_count {
376 let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
377 let zeitraum_id = seqs
378 .iter()
379 .find(|s| {
380 s.elements
381 .first()
382 .and_then(|e| e.first())
383 .is_some_and(|v| v == "Z45")
384 })
385 .and_then(|s| s.elements.get(1))
386 .and_then(|e| e.first())
387 .filter(|v| !v.is_empty())
388 .cloned();
389 if let Some(zid) = zeitraum_id {
390 let pias = nav.find_segments_in_group("PIA", &["SG4", "SG8"], i);
391 let article_id = pias
392 .iter()
393 .find(|s| {
394 s.elements
395 .first()
396 .and_then(|e| e.first())
397 .is_some_and(|v| v == "Z02")
398 })
399 .and_then(|s| s.elements.get(1))
400 .and_then(|e| e.first())
401 .cloned()
402 .unwrap_or_default();
403 sg8_data.push((zid, article_id));
404 }
405 }
406 for i in 0..sg8_data.len() {
407 for j in (i + 1)..sg8_data.len() {
408 if sg8_data[i].0 == sg8_data[j].0 {
409 let (id_i, id_j) = (&sg8_data[i].1, &sg8_data[j].1);
410 let i_is_002 = id_i == "1-02-0-002";
411 let j_is_002 = id_j == "1-02-0-002";
412 let i_is_003_004 = id_i == "1-02-0-003" || id_i == "1-02-0-004";
413 let j_is_003_004 = id_j == "1-02-0-003" || id_j == "1-02-0-004";
414 if (i_is_002 && j_is_003_004) || (j_is_002 && i_is_003_004) {
415 return ConditionResult::True;
416 }
417 }
418 }
419 }
420 if sg8_data.is_empty() {
421 ConditionResult::Unknown
422 } else {
423 ConditionResult::False
424 }
425 }
426
427 fn evaluate_242(&self, ctx: &EvaluationContext) -> ConditionResult {
429 let nav = match ctx.navigator() {
430 Some(n) => n,
431 None => return ConditionResult::Unknown,
432 };
433 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
434 let mut ids: Vec<String> = Vec::new();
435 for i in 0..sg8_count {
436 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
437 for seq in &seq_segs {
438 let qual = seq
439 .elements
440 .first()
441 .and_then(|e| e.first())
442 .map(|s| s.as_str());
443 if matches!(qual, Some("Z78") | Some("ZC7") | Some("ZC8") | Some("ZD5")) {
444 if let Some(id) = seq.elements.get(1).and_then(|e| e.first()) {
445 if !id.is_empty() {
446 ids.push(id.clone());
447 }
448 }
449 }
450 }
451 }
452 if ids.is_empty() {
453 return ConditionResult::Unknown;
454 }
455 let mut seen = std::collections::HashSet::new();
456 ConditionResult::from(ids.iter().any(|id| !seen.insert(id.as_str())))
457 }
458
459 fn evaluate_253(&self, ctx: &EvaluationContext) -> ConditionResult {
461 match ctx.has_segment_matching("STS", &[(0, 0, "E01"), (2, 0, "ZC9")]) {
462 ConditionResult::True => ConditionResult::False,
463 ConditionResult::False => ConditionResult::True,
464 ConditionResult::Unknown => ConditionResult::Unknown,
465 }
466 }
467
468 fn evaluate_258(&self, ctx: &EvaluationContext) -> ConditionResult {
470 if let (Some(sg8), Some(nav)) = (ctx.enclosing_scope("SG8"), ctx.navigator()) {
473 let is_z01 = nav
474 .find_segments_in_instance("SEQ", sg8)
475 .iter()
476 .any(|s| s.get_element(0) == "Z01");
477 let verbrauch = nav
478 .find_segments_in_subtree("CCI", sg8)
479 .iter()
480 .any(|s| s.get_element(0) == "Z30" && s.get_component(2, 0) == "Z07");
481 return ConditionResult::from(is_z01 && verbrauch);
482 }
483 let nav = match ctx.navigator() {
484 Some(n) => n,
485 None => return ctx.has_qualified_value("CCI", 0, "Z30", 2, 0, &["Z07"]),
486 };
487 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
488 for i in 0..sg8_count {
489 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
490 let has_z01 = seq_segs.iter().any(|s| {
491 s.elements
492 .first()
493 .and_then(|e| e.first())
494 .is_some_and(|v| v == "Z01")
495 });
496 if has_z01 {
497 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
498 for j in 0..sg10_count {
499 let ccis =
500 nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
501 if ccis.iter().any(|s| {
502 s.elements
503 .first()
504 .and_then(|e| e.first())
505 .is_some_and(|v| v == "Z30")
506 && s.elements
507 .get(2)
508 .and_then(|e| e.first())
509 .is_some_and(|v| v == "Z07")
510 }) {
511 return ConditionResult::True;
512 }
513 }
514 }
515 }
516 ConditionResult::False
517 }
518
519 fn evaluate_263(&self, ctx: &EvaluationContext) -> ConditionResult {
522 let nav = match ctx.navigator() {
523 Some(n) => n,
524 None => return ctx.has_qualified_value("CCI", 0, "Z30", 2, 0, &["Z07"]),
525 };
526 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
527 for i in 0..sg8_count {
528 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
529 let has_z01 = seq_segs.iter().any(|s| {
530 s.elements
531 .first()
532 .and_then(|e| e.first())
533 .is_some_and(|v| v == "Z01")
534 });
535 if !has_z01 {
536 continue;
537 }
538 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
539 for j in 0..sg10_count {
540 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
541 if ccis.iter().any(|s| {
542 s.elements
543 .first()
544 .and_then(|e| e.first())
545 .is_some_and(|v| v == "Z30")
546 && s.elements
547 .get(2)
548 .and_then(|e| e.first())
549 .is_some_and(|v| v == "Z07")
550 }) {
551 return ConditionResult::True;
552 }
553 }
554 }
555 ConditionResult::False
556 }
557
558 fn evaluate_297(&self, ctx: &EvaluationContext) -> ConditionResult {
561 let nav = match ctx.navigator() {
562 Some(n) => n,
563 None => return ConditionResult::Unknown,
564 };
565 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
566 let mut keys: Vec<(String, String)> = Vec::new();
568 for i in 0..sg8_count {
569 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
570 for seq in &seq_segs {
571 let qual = seq
572 .elements
573 .first()
574 .and_then(|e| e.first())
575 .map(|s| s.as_str());
576 if matches!(qual, Some("Z02") | Some("ZE3")) {
577 let pia_segs = nav.find_segments_in_group("PIA", &["SG4", "SG8"], i);
578 let has_pia5 = pia_segs.iter().any(|s| {
579 s.elements
580 .first()
581 .and_then(|e| e.first())
582 .is_some_and(|v| v == "5")
583 });
584 if has_pia5 {
585 let zeitraum_id = seq
586 .elements
587 .get(1)
588 .and_then(|e| e.first())
589 .cloned()
590 .unwrap_or_default();
591 if !zeitraum_id.is_empty() {
592 keys.push((qual.unwrap_or_default().to_string(), zeitraum_id));
593 }
594 }
595 }
596 }
597 }
598 if keys.is_empty() {
599 return ConditionResult::Unknown;
600 }
601 let mut seen = std::collections::HashSet::new();
602 ConditionResult::from(keys.iter().any(|k| !seen.insert(k)))
603 }
604
605 fn evaluate_312(&self, ctx: &EvaluationContext) -> ConditionResult {
607 ctx.dtm_lt("137", "202603312200+00")
608 }
609
610 fn evaluate_313(&self, ctx: &EvaluationContext) -> ConditionResult {
612 ctx.dtm_ge("137", "202603312200+00")
613 }
614
615 fn evaluate_326(&self, ctx: &EvaluationContext) -> ConditionResult {
618 ctx.external.evaluate("market_location_not_decommissioned")
619 }
620
621 fn evaluate_328(&self, ctx: &EvaluationContext) -> ConditionResult {
624 ctx.external.evaluate("market_location_decommissioned")
625 }
626
627 fn evaluate_346(&self, ctx: &EvaluationContext) -> ConditionResult {
629 let nav = match ctx.navigator() {
630 Some(n) => n,
631 None => {
632 let has_cci = ctx.has_qualifier("CCI", 2, "E13");
634 let has_cav = ctx.has_qualifier("CAV", 0, "MME");
635 return match (has_cci, has_cav) {
636 (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
637 (ConditionResult::False, _) | (_, ConditionResult::False) => {
638 ConditionResult::False
639 }
640 _ => ConditionResult::Unknown,
641 };
642 }
643 };
644 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
645 for i in 0..sg8_count {
646 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
647 for j in 0..sg10_count {
648 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
649 let has_cci_e13 = ccis.iter().any(|s| {
650 s.elements
651 .get(2)
652 .and_then(|e| e.first())
653 .is_some_and(|v| v == "E13")
654 });
655 if has_cci_e13 {
656 let cavs =
657 nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
658 if cavs.iter().any(|s| {
659 s.elements
660 .first()
661 .and_then(|e| e.first())
662 .is_some_and(|v| v == "MME")
663 }) {
664 return ConditionResult::True;
665 }
666 }
667 }
668 }
669 ConditionResult::False
670 }
671
672 fn evaluate_413(&self, ctx: &EvaluationContext) -> ConditionResult {
674 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_kumuliert) >= 1)
678 }
679
680 fn evaluate_414(&self, ctx: &EvaluationContext) -> ConditionResult {
682 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_kumuliert) == 0)
684 }
685
686 fn evaluate_415(&self, ctx: &EvaluationContext) -> ConditionResult {
688 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_quarter_hour) >= 2)
691 }
692
693 fn evaluate_416(&self, ctx: &EvaluationContext) -> ConditionResult {
695 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_quarter_hour) == 0)
698 }
699
700 fn evaluate_461(&self, ctx: &EvaluationContext) -> ConditionResult {
702 ctx.this_group_has_qualifier("CAV", 0, "ZG8", &["SG4", "SG8", "SG10"])
707 }
708
709 fn evaluate_534(&self, _ctx: &EvaluationContext) -> ConditionResult {
711 ConditionResult::True
715 }
716
717 fn evaluate_557(&self, _ctx: &EvaluationContext) -> ConditionResult {
719 ConditionResult::True
723 }
724
725 fn evaluate_560(&self, _ctx: &EvaluationContext) -> ConditionResult {
727 ConditionResult::True
729 }
730
731 fn evaluate_561(&self, _ctx: &EvaluationContext) -> ConditionResult {
733 ConditionResult::True
735 }
736
737 fn evaluate_562(&self, _ctx: &EvaluationContext) -> ConditionResult {
739 ConditionResult::True
741 }
742
743 fn evaluate_564(&self, _ctx: &EvaluationContext) -> ConditionResult {
745 ConditionResult::True
747 }
748
749 fn evaluate_565(&self, _ctx: &EvaluationContext) -> ConditionResult {
751 ConditionResult::True
753 }
754
755 fn evaluate_578(&self, _ctx: &EvaluationContext) -> ConditionResult {
757 ConditionResult::True
759 }
760
761 fn evaluate_681(&self, _ctx: &EvaluationContext) -> ConditionResult {
763 ConditionResult::True
765 }
766
767 fn evaluate_686(&self, _ctx: &EvaluationContext) -> ConditionResult {
769 ConditionResult::True
771 }
772
773 fn evaluate_2000(&self, ctx: &EvaluationContext) -> ConditionResult {
776 let nav = match ctx.navigator() {
779 Some(n) => n,
780 None => {
781 let count = ctx.count_qualified_in_group("LOC", 0, "Z16", &["SG4", "SG5"]);
782 return ConditionResult::from(count == 1);
783 }
784 };
785 let sg4_count = nav.group_instance_count(&["SG4"]);
786 if sg4_count == 0 {
787 return ConditionResult::Unknown;
788 }
789 for i in 0..sg4_count {
790 let sg5_count = nav.child_group_instance_count(&["SG4"], i, "SG5");
791 let mut loc_z16_count = 0usize;
792 for j in 0..sg5_count {
793 let locs = nav.find_segments_in_child_group("LOC", &["SG4"], i, "SG5", j);
794 for loc in &locs {
795 if loc
796 .elements
797 .first()
798 .and_then(|e| e.first())
799 .is_some_and(|v| v == "Z16")
800 {
801 loc_z16_count += 1;
802 }
803 }
804 }
805 if loc_z16_count != 1 {
806 return ConditionResult::False;
807 }
808 }
809 ConditionResult::True
810 }
811
812 fn evaluate_2016(&self, ctx: &EvaluationContext) -> ConditionResult {
815 let nav = match ctx.navigator() {
819 Some(n) => n,
820 None => return ConditionResult::Unknown,
821 };
822 let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
823 let mut required_ids: std::collections::HashSet<String> = std::collections::HashSet::new();
824 for i in 0..sg6_count {
825 let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
826 for rff in &rffs {
827 let qual = rff
828 .elements
829 .first()
830 .and_then(|e| e.first())
831 .map(|s| s.as_str());
832 if matches!(qual, Some("Z49") | Some("Z53")) {
833 if let Some(zeitraum_id) = rff.elements.first().and_then(|e| e.get(2)) {
834 if !zeitraum_id.is_empty() {
835 required_ids.insert(zeitraum_id.clone());
836 }
837 }
838 }
839 }
840 }
841 if required_ids.is_empty() {
842 return ConditionResult::Unknown;
843 }
844 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
846 let mut found_ids: std::collections::HashSet<String> = std::collections::HashSet::new();
847 for i in 0..sg8_count {
848 let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
849 for seq in &seqs {
850 if let Some(ref_id) = seq.elements.get(1).and_then(|e| e.first()) {
851 if !ref_id.is_empty() {
852 found_ids.insert(ref_id.clone());
853 }
854 }
855 }
856 }
857 ConditionResult::from(required_ids.iter().all(|id| found_ids.contains(id)))
858 }
859
860 fn evaluate_2121(&self, ctx: &EvaluationContext) -> ConditionResult {
863 ctx.any_group_has_any_qualifier("SEQ", 0, &["Z01", "Z80", "Z81"], &["SG4", "SG8"])
866 }
867}