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 if let Some(scope) = ctx.enclosing_scope("SG4") {
165 let ide_24 = ctx
166 .find_segments_at(scope, "IDE")
167 .iter()
168 .any(|s| s.get_element(0) == "24");
169 let sts = ctx.find_segments_at(scope, "STS").iter().any(|s| {
170 s.get_element(0) == "E01"
171 && matches!(
172 (s.get_component(2, 0), s.get_component(2, 1)),
173 ("A04", "E_0017") | ("A03", "E_0052")
174 )
175 });
176 return ConditionResult::from(ide_24 && !sts);
177 }
178 let nav = match ctx.navigator() {
179 Some(n) => n,
180 None => {
181 let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
182 let found = sts_segs.iter().any(|s| {
183 let code = s
184 .elements
185 .get(2)
186 .and_then(|e| e.first())
187 .map(|v| v.as_str());
188 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
189 (code == Some("A04") && list == Some("E_0017"))
190 || (code == Some("A03") && list == Some("E_0052"))
191 });
192 return ConditionResult::from(!found);
193 }
194 };
195 let sg4_count = nav.group_instance_count(&["SG4"]);
196 for i in 0..sg4_count {
197 let ide_segs = nav.find_segments_in_group("IDE", &["SG4"], i);
198 let has_ide_24 = ide_segs.iter().any(|s| {
199 s.elements
200 .first()
201 .and_then(|e| e.first())
202 .is_some_and(|v| v == "24")
203 });
204 if !has_ide_24 {
205 continue;
206 }
207 let sts_segs = nav.find_segments_in_group("STS", &["SG4"], i);
208 let found = sts_segs.iter().any(|s| {
209 let qual = s
210 .elements
211 .first()
212 .and_then(|e| e.first())
213 .map(|v| v.as_str());
214 let code = s
215 .elements
216 .get(2)
217 .and_then(|e| e.first())
218 .map(|v| v.as_str());
219 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
220 qual == Some("E01")
221 && ((code == Some("A04") && list == Some("E_0017"))
222 || (code == Some("A03") && list == Some("E_0052")))
223 });
224 if !found {
225 return ConditionResult::True;
226 }
227 }
228 ConditionResult::False
229 }
230
231 fn evaluate_29(&self, ctx: &EvaluationContext) -> ConditionResult {
234 if let Some(scope) = ctx.enclosing_scope("SG4") {
237 let ide_24 = ctx
238 .find_segments_at(scope, "IDE")
239 .iter()
240 .any(|s| s.get_element(0) == "24");
241 let sts = ctx.find_segments_at(scope, "STS").iter().any(|s| {
242 s.get_element(0) == "E01"
243 && matches!(
244 (s.get_component(2, 0), s.get_component(2, 1)),
245 ("A06", "E_0017") | ("A05", "E_0052")
246 )
247 });
248 return ConditionResult::from(ide_24 && !sts);
249 }
250 let nav = match ctx.navigator() {
251 Some(n) => n,
252 None => {
253 let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
254 let found = sts_segs.iter().any(|s| {
255 let code = s
256 .elements
257 .get(2)
258 .and_then(|e| e.first())
259 .map(|v| v.as_str());
260 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
261 (code == Some("A06") && list == Some("E_0017"))
262 || (code == Some("A05") && list == Some("E_0052"))
263 });
264 return ConditionResult::from(!found);
265 }
266 };
267 let sg4_count = nav.group_instance_count(&["SG4"]);
268 for i in 0..sg4_count {
269 let ide_segs = nav.find_segments_in_group("IDE", &["SG4"], i);
270 let has_ide_24 = ide_segs.iter().any(|s| {
271 s.elements
272 .first()
273 .and_then(|e| e.first())
274 .is_some_and(|v| v == "24")
275 });
276 if !has_ide_24 {
277 continue;
278 }
279 let sts_segs = nav.find_segments_in_group("STS", &["SG4"], i);
280 let found = sts_segs.iter().any(|s| {
281 let qual = s
282 .elements
283 .first()
284 .and_then(|e| e.first())
285 .map(|v| v.as_str());
286 let code = s
287 .elements
288 .get(2)
289 .and_then(|e| e.first())
290 .map(|v| v.as_str());
291 let list = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
292 qual == Some("E01")
293 && ((code == Some("A06") && list == Some("E_0017"))
294 || (code == Some("A05") && list == Some("E_0052")))
295 });
296 if !found {
297 return ConditionResult::True;
298 }
299 }
300 ConditionResult::False
301 }
302
303 fn evaluate_79(&self, ctx: &EvaluationContext) -> ConditionResult {
305 ctx.has_segment_matching("STS", &[(0, 0, "7"), (2, 0, "Z33")])
308 }
309
310 fn evaluate_136(&self, ctx: &EvaluationContext) -> ConditionResult {
312 if let Some(_scope) = ctx.enclosing_scope("SG8") {
315 return ConditionResult::from(
316 ctx.enclosing_child_segments("SG8", "SG10", &["CCI", "CAV"])
317 .unwrap_or_default()
318 .iter()
319 .any(|segs| {
320 segs.iter()
321 .any(|s| s.id == "CCI" && s.get_component(2, 0) == "E13")
322 && segs
323 .iter()
324 .any(|s| s.id == "CAV" && s.get_element(0) == "EHZ")
325 }),
326 );
327 }
328 let nav = match ctx.navigator() {
329 Some(n) => n,
330 None => return ctx.has_qualified_value("CAV", 0, "EHZ", 0, 0, &["EHZ"]),
331 };
332 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
333 for i in 0..sg8_count {
334 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
335 for j in 0..sg10_count {
336 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
337 let has_cci_e13 = ccis.iter().any(|s| {
338 s.elements
339 .get(2)
340 .and_then(|e| e.first())
341 .is_some_and(|v| v == "E13")
342 });
343 if has_cci_e13 {
344 let cavs =
345 nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
346 if cavs.iter().any(|s| {
347 s.elements
348 .first()
349 .and_then(|e| e.first())
350 .is_some_and(|v| v == "EHZ")
351 }) {
352 return ConditionResult::True;
353 }
354 }
355 }
356 }
357 ConditionResult::False
358 }
359
360 fn evaluate_139(&self, ctx: &EvaluationContext) -> ConditionResult {
363 if let Some(scope) = ctx.enclosing_scope("SG8") {
366 return ConditionResult::from(
367 !ctx.find_segments_at(scope, "CAV")
368 .iter()
369 .any(|s| s.get_element(0) == "IVA"),
370 );
371 }
372 let nav = match ctx.navigator() {
373 Some(n) => n,
374 None => return ctx.lacks_qualifier("CAV", 0, "IVA"),
375 };
376 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
377 for i in 0..sg8_count {
378 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
379 for j in 0..sg10_count {
380 let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
381 if cavs.iter().any(|s| {
382 s.elements
383 .first()
384 .and_then(|e| e.first())
385 .is_some_and(|v| v == "IVA")
386 }) {
387 return ConditionResult::False;
388 }
389 }
390 }
391 ConditionResult::True
392 }
393
394 fn evaluate_157(&self, ctx: &EvaluationContext) -> ConditionResult {
396 let result = ctx.has_segment_matching("STS", &[(0, 0, "7"), (2, 0, "Z33"), (3, 0, "ZZB")]);
397 match result {
398 ConditionResult::True => ConditionResult::False,
399 ConditionResult::False => ConditionResult::True,
400 ConditionResult::Unknown => ConditionResult::Unknown,
401 }
402 }
403
404 fn evaluate_158(&self, ctx: &EvaluationContext) -> ConditionResult {
406 ConditionResult::from(ctx.self_segment_value_equals("DTM", 0, 2, "106"))
407 }
408
409 fn evaluate_168(&self, ctx: &EvaluationContext) -> ConditionResult {
411 ctx.this_group_has_qualified_value(
413 "PIA",
414 0,
415 "Z02",
416 1,
417 0,
418 &["1-02-0-002", "1-02-0-003", "1-02-0-004"],
419 &["SG4", "SG8"],
420 )
421 }
422
423 fn evaluate_169(&self, ctx: &EvaluationContext) -> ConditionResult {
426 let nav = match ctx.navigator() {
427 Some(n) => n,
428 None => return ConditionResult::Unknown,
429 };
430 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
431 let mut sg8_data: Vec<(String, String)> = Vec::new();
432 for i in 0..sg8_count {
433 let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
434 let zeitraum_id = seqs
435 .iter()
436 .find(|s| {
437 s.elements
438 .first()
439 .and_then(|e| e.first())
440 .is_some_and(|v| v == "Z45")
441 })
442 .and_then(|s| s.elements.get(1))
443 .and_then(|e| e.first())
444 .filter(|v| !v.is_empty())
445 .cloned();
446 if let Some(zid) = zeitraum_id {
447 let pias = nav.find_segments_in_group("PIA", &["SG4", "SG8"], i);
448 let article_id = pias
449 .iter()
450 .find(|s| {
451 s.elements
452 .first()
453 .and_then(|e| e.first())
454 .is_some_and(|v| v == "Z02")
455 })
456 .and_then(|s| s.elements.get(1))
457 .and_then(|e| e.first())
458 .cloned()
459 .unwrap_or_default();
460 sg8_data.push((zid, article_id));
461 }
462 }
463 for i in 0..sg8_data.len() {
464 for j in (i + 1)..sg8_data.len() {
465 if sg8_data[i].0 == sg8_data[j].0 {
466 let (id_i, id_j) = (&sg8_data[i].1, &sg8_data[j].1);
467 let i_is_002 = id_i == "1-02-0-002";
468 let j_is_002 = id_j == "1-02-0-002";
469 let i_is_003_004 = id_i == "1-02-0-003" || id_i == "1-02-0-004";
470 let j_is_003_004 = id_j == "1-02-0-003" || id_j == "1-02-0-004";
471 if (i_is_002 && j_is_003_004) || (j_is_002 && i_is_003_004) {
472 return ConditionResult::True;
473 }
474 }
475 }
476 }
477 if sg8_data.is_empty() {
478 ConditionResult::Unknown
479 } else {
480 ConditionResult::False
481 }
482 }
483
484 fn evaluate_242(&self, ctx: &EvaluationContext) -> ConditionResult {
486 let nav = match ctx.navigator() {
487 Some(n) => n,
488 None => return ConditionResult::Unknown,
489 };
490 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
491 let mut ids: Vec<String> = Vec::new();
492 for i in 0..sg8_count {
493 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
494 for seq in &seq_segs {
495 let qual = seq
496 .elements
497 .first()
498 .and_then(|e| e.first())
499 .map(|s| s.as_str());
500 if matches!(qual, Some("Z78") | Some("ZC7") | Some("ZC8") | Some("ZD5")) {
501 if let Some(id) = seq.elements.get(1).and_then(|e| e.first()) {
502 if !id.is_empty() {
503 ids.push(id.clone());
504 }
505 }
506 }
507 }
508 }
509 if ids.is_empty() {
510 return ConditionResult::Unknown;
511 }
512 let mut seen = std::collections::HashSet::new();
513 ConditionResult::from(ids.iter().any(|id| !seen.insert(id.as_str())))
514 }
515
516 fn evaluate_253(&self, ctx: &EvaluationContext) -> ConditionResult {
518 match ctx.has_segment_matching("STS", &[(0, 0, "E01"), (2, 0, "ZC9")]) {
519 ConditionResult::True => ConditionResult::False,
520 ConditionResult::False => ConditionResult::True,
521 ConditionResult::Unknown => ConditionResult::Unknown,
522 }
523 }
524
525 fn evaluate_258(&self, ctx: &EvaluationContext) -> ConditionResult {
527 if let (Some(sg8), Some(nav)) = (ctx.enclosing_scope("SG8"), ctx.navigator()) {
530 let is_z01 = nav
531 .find_segments_in_instance("SEQ", sg8)
532 .iter()
533 .any(|s| s.get_element(0) == "Z01");
534 let verbrauch = nav
535 .find_segments_in_subtree("CCI", sg8)
536 .iter()
537 .any(|s| s.get_element(0) == "Z30" && s.get_component(2, 0) == "Z07");
538 return ConditionResult::from(is_z01 && verbrauch);
539 }
540 let nav = match ctx.navigator() {
541 Some(n) => n,
542 None => return ctx.has_qualified_value("CCI", 0, "Z30", 2, 0, &["Z07"]),
543 };
544 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
545 for i in 0..sg8_count {
546 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
547 let has_z01 = seq_segs.iter().any(|s| {
548 s.elements
549 .first()
550 .and_then(|e| e.first())
551 .is_some_and(|v| v == "Z01")
552 });
553 if has_z01 {
554 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
555 for j in 0..sg10_count {
556 let ccis =
557 nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
558 if ccis.iter().any(|s| {
559 s.elements
560 .first()
561 .and_then(|e| e.first())
562 .is_some_and(|v| v == "Z30")
563 && s.elements
564 .get(2)
565 .and_then(|e| e.first())
566 .is_some_and(|v| v == "Z07")
567 }) {
568 return ConditionResult::True;
569 }
570 }
571 }
572 }
573 ConditionResult::False
574 }
575
576 fn evaluate_263(&self, ctx: &EvaluationContext) -> ConditionResult {
579 let nav = match ctx.navigator() {
580 Some(n) => n,
581 None => return ctx.has_qualified_value("CCI", 0, "Z30", 2, 0, &["Z07"]),
582 };
583 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
584 for i in 0..sg8_count {
585 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
586 let has_z01 = seq_segs.iter().any(|s| {
587 s.elements
588 .first()
589 .and_then(|e| e.first())
590 .is_some_and(|v| v == "Z01")
591 });
592 if !has_z01 {
593 continue;
594 }
595 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
596 for j in 0..sg10_count {
597 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
598 if ccis.iter().any(|s| {
599 s.elements
600 .first()
601 .and_then(|e| e.first())
602 .is_some_and(|v| v == "Z30")
603 && s.elements
604 .get(2)
605 .and_then(|e| e.first())
606 .is_some_and(|v| v == "Z07")
607 }) {
608 return ConditionResult::True;
609 }
610 }
611 }
612 ConditionResult::False
613 }
614
615 fn evaluate_297(&self, ctx: &EvaluationContext) -> ConditionResult {
618 let nav = match ctx.navigator() {
619 Some(n) => n,
620 None => return ConditionResult::Unknown,
621 };
622 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
623 let mut keys: Vec<(String, String)> = Vec::new();
625 for i in 0..sg8_count {
626 let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
627 for seq in &seq_segs {
628 let qual = seq
629 .elements
630 .first()
631 .and_then(|e| e.first())
632 .map(|s| s.as_str());
633 if matches!(qual, Some("Z02") | Some("ZE3")) {
634 let pia_segs = nav.find_segments_in_group("PIA", &["SG4", "SG8"], i);
635 let has_pia5 = pia_segs.iter().any(|s| {
636 s.elements
637 .first()
638 .and_then(|e| e.first())
639 .is_some_and(|v| v == "5")
640 });
641 if has_pia5 {
642 let zeitraum_id = seq
643 .elements
644 .get(1)
645 .and_then(|e| e.first())
646 .cloned()
647 .unwrap_or_default();
648 if !zeitraum_id.is_empty() {
649 keys.push((qual.unwrap_or_default().to_string(), zeitraum_id));
650 }
651 }
652 }
653 }
654 }
655 if keys.is_empty() {
656 return ConditionResult::Unknown;
657 }
658 let mut seen = std::collections::HashSet::new();
659 ConditionResult::from(keys.iter().any(|k| !seen.insert(k)))
660 }
661
662 fn evaluate_312(&self, ctx: &EvaluationContext) -> ConditionResult {
664 ctx.dtm_lt("137", "202603312200+00")
665 }
666
667 fn evaluate_313(&self, ctx: &EvaluationContext) -> ConditionResult {
669 ctx.dtm_ge("137", "202603312200+00")
670 }
671
672 fn evaluate_326(&self, ctx: &EvaluationContext) -> ConditionResult {
675 ctx.external.evaluate("market_location_not_decommissioned")
676 }
677
678 fn evaluate_328(&self, ctx: &EvaluationContext) -> ConditionResult {
681 ctx.external.evaluate("market_location_decommissioned")
682 }
683
684 fn evaluate_346(&self, ctx: &EvaluationContext) -> ConditionResult {
686 if let Some(_scope) = ctx.enclosing_scope("SG8") {
689 return ConditionResult::from(
690 ctx.enclosing_child_segments("SG8", "SG10", &["CCI", "CAV"])
691 .unwrap_or_default()
692 .iter()
693 .any(|segs| {
694 segs.iter()
695 .any(|s| s.id == "CCI" && s.get_component(2, 0) == "E13")
696 && segs
697 .iter()
698 .any(|s| s.id == "CAV" && s.get_element(0) == "MME")
699 }),
700 );
701 }
702 let nav = match ctx.navigator() {
703 Some(n) => n,
704 None => {
705 let has_cci = ctx.has_qualifier("CCI", 2, "E13");
707 let has_cav = ctx.has_qualifier("CAV", 0, "MME");
708 return match (has_cci, has_cav) {
709 (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
710 (ConditionResult::False, _) | (_, ConditionResult::False) => {
711 ConditionResult::False
712 }
713 _ => ConditionResult::Unknown,
714 };
715 }
716 };
717 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
718 for i in 0..sg8_count {
719 let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
720 for j in 0..sg10_count {
721 let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
722 let has_cci_e13 = ccis.iter().any(|s| {
723 s.elements
724 .get(2)
725 .and_then(|e| e.first())
726 .is_some_and(|v| v == "E13")
727 });
728 if has_cci_e13 {
729 let cavs =
730 nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
731 if cavs.iter().any(|s| {
732 s.elements
733 .first()
734 .and_then(|e| e.first())
735 .is_some_and(|v| v == "MME")
736 }) {
737 return ConditionResult::True;
738 }
739 }
740 }
741 }
742 ConditionResult::False
743 }
744
745 fn evaluate_413(&self, ctx: &EvaluationContext) -> ConditionResult {
747 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_kumuliert) >= 1)
751 }
752
753 fn evaluate_414(&self, ctx: &EvaluationContext) -> ConditionResult {
755 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_kumuliert) == 0)
757 }
758
759 fn evaluate_415(&self, ctx: &EvaluationContext) -> ConditionResult {
761 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_quarter_hour) >= 2)
764 }
765
766 fn evaluate_416(&self, ctx: &EvaluationContext) -> ConditionResult {
768 ConditionResult::from(ctx.count_sg8_obis_matches(is_obis_wirkarbeit_quarter_hour) == 0)
771 }
772
773 fn evaluate_461(&self, ctx: &EvaluationContext) -> ConditionResult {
775 ctx.this_group_has_qualifier("CAV", 0, "ZG8", &["SG4", "SG8", "SG10"])
780 }
781
782 fn evaluate_534(&self, _ctx: &EvaluationContext) -> ConditionResult {
784 ConditionResult::True
788 }
789
790 fn evaluate_557(&self, _ctx: &EvaluationContext) -> ConditionResult {
792 ConditionResult::True
796 }
797
798 fn evaluate_560(&self, _ctx: &EvaluationContext) -> ConditionResult {
800 ConditionResult::True
802 }
803
804 fn evaluate_561(&self, _ctx: &EvaluationContext) -> ConditionResult {
806 ConditionResult::True
808 }
809
810 fn evaluate_562(&self, _ctx: &EvaluationContext) -> ConditionResult {
812 ConditionResult::True
814 }
815
816 fn evaluate_564(&self, _ctx: &EvaluationContext) -> ConditionResult {
818 ConditionResult::True
820 }
821
822 fn evaluate_565(&self, _ctx: &EvaluationContext) -> ConditionResult {
824 ConditionResult::True
826 }
827
828 fn evaluate_578(&self, _ctx: &EvaluationContext) -> ConditionResult {
830 ConditionResult::True
832 }
833
834 fn evaluate_681(&self, _ctx: &EvaluationContext) -> ConditionResult {
836 ConditionResult::True
838 }
839
840 fn evaluate_686(&self, _ctx: &EvaluationContext) -> ConditionResult {
842 ConditionResult::True
844 }
845
846 fn evaluate_2000(&self, ctx: &EvaluationContext) -> ConditionResult {
849 let nav = match ctx.navigator() {
852 Some(n) => n,
853 None => {
854 let count = ctx.count_qualified_in_group("LOC", 0, "Z16", &["SG4", "SG5"]);
855 return ConditionResult::from(count == 1);
856 }
857 };
858 let sg4_count = nav.group_instance_count(&["SG4"]);
859 if sg4_count == 0 {
860 return ConditionResult::Unknown;
861 }
862 for i in 0..sg4_count {
863 let sg5_count = nav.child_group_instance_count(&["SG4"], i, "SG5");
864 let mut loc_z16_count = 0usize;
865 for j in 0..sg5_count {
866 let locs = nav.find_segments_in_child_group("LOC", &["SG4"], i, "SG5", j);
867 for loc in &locs {
868 if loc
869 .elements
870 .first()
871 .and_then(|e| e.first())
872 .is_some_and(|v| v == "Z16")
873 {
874 loc_z16_count += 1;
875 }
876 }
877 }
878 if loc_z16_count != 1 {
879 return ConditionResult::False;
880 }
881 }
882 ConditionResult::True
883 }
884
885 fn evaluate_2016(&self, ctx: &EvaluationContext) -> ConditionResult {
888 let nav = match ctx.navigator() {
892 Some(n) => n,
893 None => return ConditionResult::Unknown,
894 };
895 let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
896 let mut required_ids: std::collections::HashSet<String> = std::collections::HashSet::new();
897 for i in 0..sg6_count {
898 let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
899 for rff in &rffs {
900 let qual = rff
901 .elements
902 .first()
903 .and_then(|e| e.first())
904 .map(|s| s.as_str());
905 if matches!(qual, Some("Z49") | Some("Z53")) {
906 if let Some(zeitraum_id) = rff.elements.first().and_then(|e| e.get(2)) {
907 if !zeitraum_id.is_empty() {
908 required_ids.insert(zeitraum_id.clone());
909 }
910 }
911 }
912 }
913 }
914 if required_ids.is_empty() {
915 return ConditionResult::Unknown;
916 }
917 let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
919 let mut found_ids: std::collections::HashSet<String> = std::collections::HashSet::new();
920 for i in 0..sg8_count {
921 let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
922 for seq in &seqs {
923 if let Some(ref_id) = seq.elements.get(1).and_then(|e| e.first()) {
924 if !ref_id.is_empty() {
925 found_ids.insert(ref_id.clone());
926 }
927 }
928 }
929 }
930 ConditionResult::from(required_ids.iter().all(|id| found_ids.contains(id)))
931 }
932
933 fn evaluate_2121(&self, ctx: &EvaluationContext) -> ConditionResult {
936 ctx.any_group_has_any_qualifier("SEQ", 0, &["Z01", "Z80", "Z81"], &["SG4", "SG8"])
939 }
940}