Skip to main content

automapper_validation/generated/fv2504/
utilmd_strom_conditions_fv2504.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2504/UTILMD_AHB_Strom_2_1_Fehlerkorrektur_20250623.xml
4// Generated: 2026-03-12T10:15:42Z
5// </auto-generated>
6
7#[allow(unused_imports)]
8use crate::eval::format_validators::*;
9use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
10
11/// Generated condition evaluator for UTILMD_Strom FV2504.
12pub struct UtilmdStromConditionEvaluatorFV2504 {
13    // External condition IDs that require runtime context.
14    external_conditions: std::collections::HashSet<u32>,
15}
16
17impl Default for UtilmdStromConditionEvaluatorFV2504 {
18    fn default() -> Self {
19        let mut external_conditions = std::collections::HashSet::new();
20        external_conditions.insert(1);
21        external_conditions.insert(4);
22        external_conditions.insert(5);
23        external_conditions.insert(6);
24        external_conditions.insert(8);
25        external_conditions.insert(9);
26        external_conditions.insert(14);
27        external_conditions.insert(31);
28        external_conditions.insert(33);
29        external_conditions.insert(36);
30        external_conditions.insert(38);
31        external_conditions.insert(39);
32        external_conditions.insert(40);
33        external_conditions.insert(75);
34        external_conditions.insert(98);
35        external_conditions.insert(99);
36        external_conditions.insert(151);
37        external_conditions.insert(233);
38        external_conditions.insert(241);
39        external_conditions.insert(251);
40        external_conditions.insert(292);
41        external_conditions.insert(314);
42        external_conditions.insert(315);
43        external_conditions.insert(323);
44        external_conditions.insert(412);
45        external_conditions.insert(425);
46        external_conditions.insert(426);
47        external_conditions.insert(427);
48        external_conditions.insert(428);
49        external_conditions.insert(429);
50        external_conditions.insert(433);
51        external_conditions.insert(435);
52        external_conditions.insert(453);
53        external_conditions.insert(459);
54        external_conditions.insert(460);
55        external_conditions.insert(706);
56        external_conditions.insert(717);
57        external_conditions.insert(2011);
58        Self {
59            external_conditions,
60        }
61    }
62}
63
64impl ConditionEvaluator for UtilmdStromConditionEvaluatorFV2504 {
65    fn message_type(&self) -> &str {
66        "UTILMD_Strom"
67    }
68
69    fn format_version(&self) -> &str {
70        "FV2504"
71    }
72
73    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
74        match condition {
75            1 => self.evaluate_1(ctx),
76            4 => self.evaluate_4(ctx),
77            5 => self.evaluate_5(ctx),
78            6 => self.evaluate_6(ctx),
79            7 => self.evaluate_7(ctx),
80            8 => self.evaluate_8(ctx),
81            9 => self.evaluate_9(ctx),
82            10 => self.evaluate_10(ctx),
83            11 => self.evaluate_11(ctx),
84            12 => self.evaluate_12(ctx),
85            13 => self.evaluate_13(ctx),
86            14 => self.evaluate_14(ctx),
87            15 => self.evaluate_15(ctx),
88            16 => self.evaluate_16(ctx),
89            17 => self.evaluate_17(ctx),
90            18 => self.evaluate_18(ctx),
91            19 => self.evaluate_19(ctx),
92            20 => self.evaluate_20(ctx),
93            21 => self.evaluate_21(ctx),
94            22 => self.evaluate_22(ctx),
95            23 => self.evaluate_23(ctx),
96            24 => self.evaluate_24(ctx),
97            25 => self.evaluate_25(ctx),
98            27 => self.evaluate_27(ctx),
99            30 => self.evaluate_30(ctx),
100            31 => self.evaluate_31(ctx),
101            32 => self.evaluate_32(ctx),
102            33 => self.evaluate_33(ctx),
103            34 => self.evaluate_34(ctx),
104            35 => self.evaluate_35(ctx),
105            36 => self.evaluate_36(ctx),
106            37 => self.evaluate_37(ctx),
107            38 => self.evaluate_38(ctx),
108            39 => self.evaluate_39(ctx),
109            40 => self.evaluate_40(ctx),
110            41 => self.evaluate_41(ctx),
111            42 => self.evaluate_42(ctx),
112            43 => self.evaluate_43(ctx),
113            44 => self.evaluate_44(ctx),
114            45 => self.evaluate_45(ctx),
115            46 => self.evaluate_46(ctx),
116            47 => self.evaluate_47(ctx),
117            48 => self.evaluate_48(ctx),
118            49 => self.evaluate_49(ctx),
119            50 => self.evaluate_50(ctx),
120            51 => self.evaluate_51(ctx),
121            52 => self.evaluate_52(ctx),
122            53 => self.evaluate_53(ctx),
123            54 => self.evaluate_54(ctx),
124            55 => self.evaluate_55(ctx),
125            56 => self.evaluate_56(ctx),
126            57 => self.evaluate_57(ctx),
127            58 => self.evaluate_58(ctx),
128            60 => self.evaluate_60(ctx),
129            61 => self.evaluate_61(ctx),
130            62 => self.evaluate_62(ctx),
131            63 => self.evaluate_63(ctx),
132            64 => self.evaluate_64(ctx),
133            65 => self.evaluate_65(ctx),
134            66 => self.evaluate_66(ctx),
135            67 => self.evaluate_67(ctx),
136            68 => self.evaluate_68(ctx),
137            69 => self.evaluate_69(ctx),
138            70 => self.evaluate_70(ctx),
139            71 => self.evaluate_71(ctx),
140            72 => self.evaluate_72(ctx),
141            73 => self.evaluate_73(ctx),
142            74 => self.evaluate_74(ctx),
143            75 => self.evaluate_75(ctx),
144            76 => self.evaluate_76(ctx),
145            77 => self.evaluate_77(ctx),
146            78 => self.evaluate_78(ctx),
147            83 => self.evaluate_83(ctx),
148            84 => self.evaluate_84(ctx),
149            85 => self.evaluate_85(ctx),
150            86 => self.evaluate_86(ctx),
151            87 => self.evaluate_87(ctx),
152            88 => self.evaluate_88(ctx),
153            89 => self.evaluate_89(ctx),
154            90 => self.evaluate_90(ctx),
155            91 => self.evaluate_91(ctx),
156            92 => self.evaluate_92(ctx),
157            93 => self.evaluate_93(ctx),
158            94 => self.evaluate_94(ctx),
159            95 => self.evaluate_95(ctx),
160            96 => self.evaluate_96(ctx),
161            97 => self.evaluate_97(ctx),
162            98 => self.evaluate_98(ctx),
163            99 => self.evaluate_99(ctx),
164            100 => self.evaluate_100(ctx),
165            101 => self.evaluate_101(ctx),
166            102 => self.evaluate_102(ctx),
167            103 => self.evaluate_103(ctx),
168            104 => self.evaluate_104(ctx),
169            105 => self.evaluate_105(ctx),
170            106 => self.evaluate_106(ctx),
171            107 => self.evaluate_107(ctx),
172            108 => self.evaluate_108(ctx),
173            110 => self.evaluate_110(ctx),
174            111 => self.evaluate_111(ctx),
175            112 => self.evaluate_112(ctx),
176            113 => self.evaluate_113(ctx),
177            114 => self.evaluate_114(ctx),
178            115 => self.evaluate_115(ctx),
179            116 => self.evaluate_116(ctx),
180            117 => self.evaluate_117(ctx),
181            118 => self.evaluate_118(ctx),
182            119 => self.evaluate_119(ctx),
183            120 => self.evaluate_120(ctx),
184            121 => self.evaluate_121(ctx),
185            122 => self.evaluate_122(ctx),
186            123 => self.evaluate_123(ctx),
187            124 => self.evaluate_124(ctx),
188            125 => self.evaluate_125(ctx),
189            126 => self.evaluate_126(ctx),
190            127 => self.evaluate_127(ctx),
191            128 => self.evaluate_128(ctx),
192            129 => self.evaluate_129(ctx),
193            130 => self.evaluate_130(ctx),
194            131 => self.evaluate_131(ctx),
195            132 => self.evaluate_132(ctx),
196            133 => self.evaluate_133(ctx),
197            134 => self.evaluate_134(ctx),
198            135 => self.evaluate_135(ctx),
199            136 => self.evaluate_136(ctx),
200            137 => self.evaluate_137(ctx),
201            138 => self.evaluate_138(ctx),
202            139 => self.evaluate_139(ctx),
203            140 => self.evaluate_140(ctx),
204            141 => self.evaluate_141(ctx),
205            142 => self.evaluate_142(ctx),
206            143 => self.evaluate_143(ctx),
207            144 => self.evaluate_144(ctx),
208            145 => self.evaluate_145(ctx),
209            146 => self.evaluate_146(ctx),
210            147 => self.evaluate_147(ctx),
211            148 => self.evaluate_148(ctx),
212            149 => self.evaluate_149(ctx),
213            150 => self.evaluate_150(ctx),
214            151 => self.evaluate_151(ctx),
215            152 => self.evaluate_152(ctx),
216            153 => self.evaluate_153(ctx),
217            156 => self.evaluate_156(ctx),
218            161 => self.evaluate_161(ctx),
219            162 => self.evaluate_162(ctx),
220            163 => self.evaluate_163(ctx),
221            164 => self.evaluate_164(ctx),
222            165 => self.evaluate_165(ctx),
223            166 => self.evaluate_166(ctx),
224            167 => self.evaluate_167(ctx),
225            170 => self.evaluate_170(ctx),
226            172 => self.evaluate_172(ctx),
227            173 => self.evaluate_173(ctx),
228            174 => self.evaluate_174(ctx),
229            175 => self.evaluate_175(ctx),
230            176 => self.evaluate_176(ctx),
231            177 => self.evaluate_177(ctx),
232            178 => self.evaluate_178(ctx),
233            179 => self.evaluate_179(ctx),
234            180 => self.evaluate_180(ctx),
235            184 => self.evaluate_184(ctx),
236            190 => self.evaluate_190(ctx),
237            191 => self.evaluate_191(ctx),
238            192 => self.evaluate_192(ctx),
239            193 => self.evaluate_193(ctx),
240            194 => self.evaluate_194(ctx),
241            195 => self.evaluate_195(ctx),
242            196 => self.evaluate_196(ctx),
243            197 => self.evaluate_197(ctx),
244            198 => self.evaluate_198(ctx),
245            199 => self.evaluate_199(ctx),
246            201 => self.evaluate_201(ctx),
247            202 => self.evaluate_202(ctx),
248            203 => self.evaluate_203(ctx),
249            204 => self.evaluate_204(ctx),
250            205 => self.evaluate_205(ctx),
251            206 => self.evaluate_206(ctx),
252            209 => self.evaluate_209(ctx),
253            210 => self.evaluate_210(ctx),
254            212 => self.evaluate_212(ctx),
255            213 => self.evaluate_213(ctx),
256            215 => self.evaluate_215(ctx),
257            216 => self.evaluate_216(ctx),
258            217 => self.evaluate_217(ctx),
259            219 => self.evaluate_219(ctx),
260            220 => self.evaluate_220(ctx),
261            221 => self.evaluate_221(ctx),
262            223 => self.evaluate_223(ctx),
263            224 => self.evaluate_224(ctx),
264            227 => self.evaluate_227(ctx),
265            229 => self.evaluate_229(ctx),
266            232 => self.evaluate_232(ctx),
267            233 => self.evaluate_233(ctx),
268            234 => self.evaluate_234(ctx),
269            237 => self.evaluate_237(ctx),
270            238 => self.evaluate_238(ctx),
271            239 => self.evaluate_239(ctx),
272            240 => self.evaluate_240(ctx),
273            241 => self.evaluate_241(ctx),
274            243 => self.evaluate_243(ctx),
275            244 => self.evaluate_244(ctx),
276            248 => self.evaluate_248(ctx),
277            249 => self.evaluate_249(ctx),
278            251 => self.evaluate_251(ctx),
279            252 => self.evaluate_252(ctx),
280            254 => self.evaluate_254(ctx),
281            255 => self.evaluate_255(ctx),
282            256 => self.evaluate_256(ctx),
283            257 => self.evaluate_257(ctx),
284            259 => self.evaluate_259(ctx),
285            261 => self.evaluate_261(ctx),
286            262 => self.evaluate_262(ctx),
287            265 => self.evaluate_265(ctx),
288            266 => self.evaluate_266(ctx),
289            267 => self.evaluate_267(ctx),
290            268 => self.evaluate_268(ctx),
291            269 => self.evaluate_269(ctx),
292            270 => self.evaluate_270(ctx),
293            273 => self.evaluate_273(ctx),
294            279 => self.evaluate_279(ctx),
295            280 => self.evaluate_280(ctx),
296            282 => self.evaluate_282(ctx),
297            284 => self.evaluate_284(ctx),
298            285 => self.evaluate_285(ctx),
299            286 => self.evaluate_286(ctx),
300            287 => self.evaluate_287(ctx),
301            288 => self.evaluate_288(ctx),
302            291 => self.evaluate_291(ctx),
303            292 => self.evaluate_292(ctx),
304            293 => self.evaluate_293(ctx),
305            294 => self.evaluate_294(ctx),
306            295 => self.evaluate_295(ctx),
307            296 => self.evaluate_296(ctx),
308            297 => self.evaluate_297(ctx),
309            298 => self.evaluate_298(ctx),
310            299 => self.evaluate_299(ctx),
311            300 => self.evaluate_300(ctx),
312            301 => self.evaluate_301(ctx),
313            302 => self.evaluate_302(ctx),
314            303 => self.evaluate_303(ctx),
315            304 => self.evaluate_304(ctx),
316            305 => self.evaluate_305(ctx),
317            306 => self.evaluate_306(ctx),
318            307 => self.evaluate_307(ctx),
319            309 => self.evaluate_309(ctx),
320            314 => self.evaluate_314(ctx),
321            315 => self.evaluate_315(ctx),
322            316 => self.evaluate_316(ctx),
323            317 => self.evaluate_317(ctx),
324            318 => self.evaluate_318(ctx),
325            321 => self.evaluate_321(ctx),
326            322 => self.evaluate_322(ctx),
327            323 => self.evaluate_323(ctx),
328            327 => self.evaluate_327(ctx),
329            329 => self.evaluate_329(ctx),
330            331 => self.evaluate_331(ctx),
331            332 => self.evaluate_332(ctx),
332            333 => self.evaluate_333(ctx),
333            334 => self.evaluate_334(ctx),
334            335 => self.evaluate_335(ctx),
335            336 => self.evaluate_336(ctx),
336            337 => self.evaluate_337(ctx),
337            338 => self.evaluate_338(ctx),
338            339 => self.evaluate_339(ctx),
339            340 => self.evaluate_340(ctx),
340            341 => self.evaluate_341(ctx),
341            342 => self.evaluate_342(ctx),
342            344 => self.evaluate_344(ctx),
343            345 => self.evaluate_345(ctx),
344            346 => self.evaluate_346(ctx),
345            347 => self.evaluate_347(ctx),
346            348 => self.evaluate_348(ctx),
347            349 => self.evaluate_349(ctx),
348            350 => self.evaluate_350(ctx),
349            351 => self.evaluate_351(ctx),
350            352 => self.evaluate_352(ctx),
351            355 => self.evaluate_355(ctx),
352            356 => self.evaluate_356(ctx),
353            357 => self.evaluate_357(ctx),
354            358 => self.evaluate_358(ctx),
355            359 => self.evaluate_359(ctx),
356            360 => self.evaluate_360(ctx),
357            363 => self.evaluate_363(ctx),
358            365 => self.evaluate_365(ctx),
359            366 => self.evaluate_366(ctx),
360            367 => self.evaluate_367(ctx),
361            368 => self.evaluate_368(ctx),
362            370 => self.evaluate_370(ctx),
363            371 => self.evaluate_371(ctx),
364            372 => self.evaluate_372(ctx),
365            373 => self.evaluate_373(ctx),
366            375 => self.evaluate_375(ctx),
367            376 => self.evaluate_376(ctx),
368            377 => self.evaluate_377(ctx),
369            378 => self.evaluate_378(ctx),
370            379 => self.evaluate_379(ctx),
371            380 => self.evaluate_380(ctx),
372            384 => self.evaluate_384(ctx),
373            386 => self.evaluate_386(ctx),
374            387 => self.evaluate_387(ctx),
375            388 => self.evaluate_388(ctx),
376            391 => self.evaluate_391(ctx),
377            392 => self.evaluate_392(ctx),
378            393 => self.evaluate_393(ctx),
379            394 => self.evaluate_394(ctx),
380            395 => self.evaluate_395(ctx),
381            396 => self.evaluate_396(ctx),
382            397 => self.evaluate_397(ctx),
383            398 => self.evaluate_398(ctx),
384            399 => self.evaluate_399(ctx),
385            401 => self.evaluate_401(ctx),
386            402 => self.evaluate_402(ctx),
387            403 => self.evaluate_403(ctx),
388            404 => self.evaluate_404(ctx),
389            405 => self.evaluate_405(ctx),
390            406 => self.evaluate_406(ctx),
391            407 => self.evaluate_407(ctx),
392            408 => self.evaluate_408(ctx),
393            409 => self.evaluate_409(ctx),
394            410 => self.evaluate_410(ctx),
395            411 => self.evaluate_411(ctx),
396            412 => self.evaluate_412(ctx),
397            413 => self.evaluate_413(ctx),
398            414 => self.evaluate_414(ctx),
399            415 => self.evaluate_415(ctx),
400            416 => self.evaluate_416(ctx),
401            417 => self.evaluate_417(ctx),
402            419 => self.evaluate_419(ctx),
403            420 => self.evaluate_420(ctx),
404            421 => self.evaluate_421(ctx),
405            425 => self.evaluate_425(ctx),
406            426 => self.evaluate_426(ctx),
407            427 => self.evaluate_427(ctx),
408            428 => self.evaluate_428(ctx),
409            429 => self.evaluate_429(ctx),
410            430 => self.evaluate_430(ctx),
411            431 => self.evaluate_431(ctx),
412            432 => self.evaluate_432(ctx),
413            433 => self.evaluate_433(ctx),
414            435 => self.evaluate_435(ctx),
415            436 => self.evaluate_436(ctx),
416            437 => self.evaluate_437(ctx),
417            438 => self.evaluate_438(ctx),
418            440 => self.evaluate_440(ctx),
419            441 => self.evaluate_441(ctx),
420            442 => self.evaluate_442(ctx),
421            444 => self.evaluate_444(ctx),
422            445 => self.evaluate_445(ctx),
423            446 => self.evaluate_446(ctx),
424            447 => self.evaluate_447(ctx),
425            448 => self.evaluate_448(ctx),
426            449 => self.evaluate_449(ctx),
427            450 => self.evaluate_450(ctx),
428            451 => self.evaluate_451(ctx),
429            452 => self.evaluate_452(ctx),
430            453 => self.evaluate_453(ctx),
431            454 => self.evaluate_454(ctx),
432            455 => self.evaluate_455(ctx),
433            456 => self.evaluate_456(ctx),
434            457 => self.evaluate_457(ctx),
435            458 => self.evaluate_458(ctx),
436            459 => self.evaluate_459(ctx),
437            460 => self.evaluate_460(ctx),
438            461 => self.evaluate_461(ctx),
439            462 => self.evaluate_462(ctx),
440            463 => self.evaluate_463(ctx),
441            465 => self.evaluate_465(ctx),
442            466 => self.evaluate_466(ctx),
443            467 => self.evaluate_467(ctx),
444            468 => self.evaluate_468(ctx),
445            469 => self.evaluate_469(ctx),
446            470 => self.evaluate_470(ctx),
447            471 => self.evaluate_471(ctx),
448            472 => self.evaluate_472(ctx),
449            473 => self.evaluate_473(ctx),
450            474 => self.evaluate_474(ctx),
451            475 => self.evaluate_475(ctx),
452            476 => self.evaluate_476(ctx),
453            477 => self.evaluate_477(ctx),
454            478 => self.evaluate_478(ctx),
455            479 => self.evaluate_479(ctx),
456            480 => self.evaluate_480(ctx),
457            481 => self.evaluate_481(ctx),
458            483 => self.evaluate_483(ctx),
459            484 => self.evaluate_484(ctx),
460            487 => self.evaluate_487(ctx),
461            489 => self.evaluate_489(ctx),
462            490 => self.evaluate_490(ctx),
463            491 => self.evaluate_491(ctx),
464            494 => self.evaluate_494(ctx),
465            500 => self.evaluate_500(ctx),
466            501 => self.evaluate_501(ctx),
467            502 => self.evaluate_502(ctx),
468            503 => self.evaluate_503(ctx),
469            504 => self.evaluate_504(ctx),
470            505 => self.evaluate_505(ctx),
471            506 => self.evaluate_506(ctx),
472            507 => self.evaluate_507(ctx),
473            508 => self.evaluate_508(ctx),
474            509 => self.evaluate_509(ctx),
475            510 => self.evaluate_510(ctx),
476            511 => self.evaluate_511(ctx),
477            512 => self.evaluate_512(ctx),
478            513 => self.evaluate_513(ctx),
479            514 => self.evaluate_514(ctx),
480            515 => self.evaluate_515(ctx),
481            516 => self.evaluate_516(ctx),
482            517 => self.evaluate_517(ctx),
483            518 => self.evaluate_518(ctx),
484            519 => self.evaluate_519(ctx),
485            520 => self.evaluate_520(ctx),
486            521 => self.evaluate_521(ctx),
487            522 => self.evaluate_522(ctx),
488            523 => self.evaluate_523(ctx),
489            524 => self.evaluate_524(ctx),
490            525 => self.evaluate_525(ctx),
491            526 => self.evaluate_526(ctx),
492            527 => self.evaluate_527(ctx),
493            528 => self.evaluate_528(ctx),
494            529 => self.evaluate_529(ctx),
495            530 => self.evaluate_530(ctx),
496            531 => self.evaluate_531(ctx),
497            532 => self.evaluate_532(ctx),
498            533 => self.evaluate_533(ctx),
499            555 => self.evaluate_555(ctx),
500            556 => self.evaluate_556(ctx),
501            558 => self.evaluate_558(ctx),
502            559 => self.evaluate_559(ctx),
503            563 => self.evaluate_563(ctx),
504            566 => self.evaluate_566(ctx),
505            567 => self.evaluate_567(ctx),
506            568 => self.evaluate_568(ctx),
507            569 => self.evaluate_569(ctx),
508            570 => self.evaluate_570(ctx),
509            572 => self.evaluate_572(ctx),
510            576 => self.evaluate_576(ctx),
511            577 => self.evaluate_577(ctx),
512            579 => self.evaluate_579(ctx),
513            580 => self.evaluate_580(ctx),
514            581 => self.evaluate_581(ctx),
515            586 => self.evaluate_586(ctx),
516            590 => self.evaluate_590(ctx),
517            594 => self.evaluate_594(ctx),
518            599 => self.evaluate_599(ctx),
519            601 => self.evaluate_601(ctx),
520            606 => self.evaluate_606(ctx),
521            609 => self.evaluate_609(ctx),
522            611 => self.evaluate_611(ctx),
523            614 => self.evaluate_614(ctx),
524            617 => self.evaluate_617(ctx),
525            618 => self.evaluate_618(ctx),
526            619 => self.evaluate_619(ctx),
527            621 => self.evaluate_621(ctx),
528            622 => self.evaluate_622(ctx),
529            623 => self.evaluate_623(ctx),
530            630 => self.evaluate_630(ctx),
531            631 => self.evaluate_631(ctx),
532            632 => self.evaluate_632(ctx),
533            637 => self.evaluate_637(ctx),
534            638 => self.evaluate_638(ctx),
535            639 => self.evaluate_639(ctx),
536            640 => self.evaluate_640(ctx),
537            641 => self.evaluate_641(ctx),
538            642 => self.evaluate_642(ctx),
539            643 => self.evaluate_643(ctx),
540            645 => self.evaluate_645(ctx),
541            646 => self.evaluate_646(ctx),
542            647 => self.evaluate_647(ctx),
543            648 => self.evaluate_648(ctx),
544            651 => self.evaluate_651(ctx),
545            653 => self.evaluate_653(ctx),
546            655 => self.evaluate_655(ctx),
547            659 => self.evaluate_659(ctx),
548            660 => self.evaluate_660(ctx),
549            662 => self.evaluate_662(ctx),
550            663 => self.evaluate_663(ctx),
551            664 => self.evaluate_664(ctx),
552            665 => self.evaluate_665(ctx),
553            667 => self.evaluate_667(ctx),
554            668 => self.evaluate_668(ctx),
555            670 => self.evaluate_670(ctx),
556            671 => self.evaluate_671(ctx),
557            672 => self.evaluate_672(ctx),
558            673 => self.evaluate_673(ctx),
559            674 => self.evaluate_674(ctx),
560            675 => self.evaluate_675(ctx),
561            677 => self.evaluate_677(ctx),
562            678 => self.evaluate_678(ctx),
563            679 => self.evaluate_679(ctx),
564            680 => self.evaluate_680(ctx),
565            682 => self.evaluate_682(ctx),
566            683 => self.evaluate_683(ctx),
567            684 => self.evaluate_684(ctx),
568            685 => self.evaluate_685(ctx),
569            687 => self.evaluate_687(ctx),
570            688 => self.evaluate_688(ctx),
571            689 => self.evaluate_689(ctx),
572            690 => self.evaluate_690(ctx),
573            693 => self.evaluate_693(ctx),
574            694 => self.evaluate_694(ctx),
575            695 => self.evaluate_695(ctx),
576            696 => self.evaluate_696(ctx),
577            698 => self.evaluate_698(ctx),
578            699 => self.evaluate_699(ctx),
579            700 => self.evaluate_700(ctx),
580            704 => self.evaluate_704(ctx),
581            705 => self.evaluate_705(ctx),
582            706 => self.evaluate_706(ctx),
583            707 => self.evaluate_707(ctx),
584            708 => self.evaluate_708(ctx),
585            709 => self.evaluate_709(ctx),
586            710 => self.evaluate_710(ctx),
587            711 => self.evaluate_711(ctx),
588            712 => self.evaluate_712(ctx),
589            713 => self.evaluate_713(ctx),
590            714 => self.evaluate_714(ctx),
591            715 => self.evaluate_715(ctx),
592            716 => self.evaluate_716(ctx),
593            717 => self.evaluate_717(ctx),
594            718 => self.evaluate_718(ctx),
595            719 => self.evaluate_719(ctx),
596            902 => self.evaluate_902(ctx),
597            910 => self.evaluate_910(ctx),
598            914 => self.evaluate_914(ctx),
599            922 => self.evaluate_922(ctx),
600            926 => self.evaluate_926(ctx),
601            930 => self.evaluate_930(ctx),
602            931 => self.evaluate_931(ctx),
603            932 => self.evaluate_932(ctx),
604            933 => self.evaluate_933(ctx),
605            937 => self.evaluate_937(ctx),
606            938 => self.evaluate_938(ctx),
607            939 => self.evaluate_939(ctx),
608            940 => self.evaluate_940(ctx),
609            942 => self.evaluate_942(ctx),
610            943 => self.evaluate_943(ctx),
611            946 => self.evaluate_946(ctx),
612            948 => self.evaluate_948(ctx),
613            950 => self.evaluate_950(ctx),
614            951 => self.evaluate_951(ctx),
615            952 => self.evaluate_952(ctx),
616            955 => self.evaluate_955(ctx),
617            957 => self.evaluate_957(ctx),
618            960 => self.evaluate_960(ctx),
619            961 => self.evaluate_961(ctx),
620            967 => self.evaluate_967(ctx),
621            2001 => self.evaluate_2001(ctx),
622            2002 => self.evaluate_2002(ctx),
623            2003 => self.evaluate_2003(ctx),
624            2004 => self.evaluate_2004(ctx),
625            2005 => self.evaluate_2005(ctx),
626            2006 => self.evaluate_2006(ctx),
627            2007 => self.evaluate_2007(ctx),
628            2008 => self.evaluate_2008(ctx),
629            2009 => self.evaluate_2009(ctx),
630            2010 => self.evaluate_2010(ctx),
631            2011 => self.evaluate_2011(ctx),
632            2012 => self.evaluate_2012(ctx),
633            2013 => self.evaluate_2013(ctx),
634            2014 => self.evaluate_2014(ctx),
635            2015 => self.evaluate_2015(ctx),
636            2016 => self.evaluate_2016(ctx),
637            2017 => self.evaluate_2017(ctx),
638            2018 => self.evaluate_2018(ctx),
639            2060 => self.evaluate_2060(ctx),
640            2061 => self.evaluate_2061(ctx),
641            2071 => self.evaluate_2071(ctx),
642            2073 => self.evaluate_2073(ctx),
643            2075 => self.evaluate_2075(ctx),
644            2080 => self.evaluate_2080(ctx),
645            2095 => self.evaluate_2095(ctx),
646            2096 => self.evaluate_2096(ctx),
647            2119 => self.evaluate_2119(ctx),
648            2140 => self.evaluate_2140(ctx),
649            2182 => self.evaluate_2182(ctx),
650            2183 => self.evaluate_2183(ctx),
651            2207 => self.evaluate_2207(ctx),
652            2225 => self.evaluate_2225(ctx),
653            2236 => self.evaluate_2236(ctx),
654            2252 => self.evaluate_2252(ctx),
655            2261 => self.evaluate_2261(ctx),
656            2284 => self.evaluate_2284(ctx),
657            2286 => self.evaluate_2286(ctx),
658            2287 => self.evaluate_2287(ctx),
659            2288 => self.evaluate_2288(ctx),
660            2307 => self.evaluate_2307(ctx),
661            2308 => self.evaluate_2308(ctx),
662            2309 => self.evaluate_2309(ctx),
663            2310 => self.evaluate_2310(ctx),
664            2311 => self.evaluate_2311(ctx),
665            2312 => self.evaluate_2312(ctx),
666            2313 => self.evaluate_2313(ctx),
667            2317 => self.evaluate_2317(ctx),
668            2318 => self.evaluate_2318(ctx),
669            2344 => self.evaluate_2344(ctx),
670            2350 => self.evaluate_2350(ctx),
671            2351 => self.evaluate_2351(ctx),
672            2352 => self.evaluate_2352(ctx),
673            2356 => self.evaluate_2356(ctx),
674            2357 => self.evaluate_2357(ctx),
675            2358 => self.evaluate_2358(ctx),
676            2359 => self.evaluate_2359(ctx),
677            2360 => self.evaluate_2360(ctx),
678            2361 => self.evaluate_2361(ctx),
679            _ => ConditionResult::Unknown,
680        }
681    }
682
683    fn is_external(&self, condition: u32) -> bool {
684        self.external_conditions.contains(&condition)
685    }
686    fn is_known(&self, condition: u32) -> bool {
687        matches!(
688            condition,
689            1 | 4
690                | 5
691                | 6
692                | 7
693                | 8
694                | 9
695                | 10
696                | 11
697                | 12
698                | 13
699                | 14
700                | 15
701                | 16
702                | 17
703                | 18
704                | 19
705                | 20
706                | 21
707                | 22
708                | 23
709                | 24
710                | 25
711                | 27
712                | 30
713                | 31
714                | 32
715                | 33
716                | 34
717                | 35
718                | 36
719                | 37
720                | 38
721                | 39
722                | 40
723                | 41
724                | 42
725                | 43
726                | 44
727                | 45
728                | 46
729                | 47
730                | 48
731                | 49
732                | 50
733                | 51
734                | 52
735                | 53
736                | 54
737                | 55
738                | 56
739                | 57
740                | 58
741                | 60
742                | 61
743                | 62
744                | 63
745                | 64
746                | 65
747                | 66
748                | 67
749                | 68
750                | 69
751                | 70
752                | 71
753                | 72
754                | 73
755                | 74
756                | 75
757                | 76
758                | 77
759                | 78
760                | 83
761                | 84
762                | 85
763                | 86
764                | 87
765                | 88
766                | 89
767                | 90
768                | 91
769                | 92
770                | 93
771                | 94
772                | 95
773                | 96
774                | 97
775                | 98
776                | 99
777                | 100
778                | 101
779                | 102
780                | 103
781                | 104
782                | 105
783                | 106
784                | 107
785                | 108
786                | 110
787                | 111
788                | 112
789                | 113
790                | 114
791                | 115
792                | 116
793                | 117
794                | 118
795                | 119
796                | 120
797                | 121
798                | 122
799                | 123
800                | 124
801                | 125
802                | 126
803                | 127
804                | 128
805                | 129
806                | 130
807                | 131
808                | 132
809                | 133
810                | 134
811                | 135
812                | 136
813                | 137
814                | 138
815                | 139
816                | 140
817                | 141
818                | 142
819                | 143
820                | 144
821                | 145
822                | 146
823                | 147
824                | 148
825                | 149
826                | 150
827                | 151
828                | 152
829                | 153
830                | 156
831                | 161
832                | 162
833                | 163
834                | 164
835                | 165
836                | 166
837                | 167
838                | 170
839                | 172
840                | 173
841                | 174
842                | 175
843                | 176
844                | 177
845                | 178
846                | 179
847                | 180
848                | 184
849                | 190
850                | 191
851                | 192
852                | 193
853                | 194
854                | 195
855                | 196
856                | 197
857                | 198
858                | 199
859                | 201
860                | 202
861                | 203
862                | 204
863                | 205
864                | 206
865                | 209
866                | 210
867                | 212
868                | 213
869                | 215
870                | 216
871                | 217
872                | 219
873                | 220
874                | 221
875                | 223
876                | 224
877                | 227
878                | 229
879                | 232
880                | 233
881                | 234
882                | 237
883                | 238
884                | 239
885                | 240
886                | 241
887                | 243
888                | 244
889                | 248
890                | 249
891                | 251
892                | 252
893                | 254
894                | 255
895                | 256
896                | 257
897                | 259
898                | 261
899                | 262
900                | 265
901                | 266
902                | 267
903                | 268
904                | 269
905                | 270
906                | 273
907                | 279
908                | 280
909                | 282
910                | 284
911                | 285
912                | 286
913                | 287
914                | 288
915                | 291
916                | 292
917                | 293
918                | 294
919                | 295
920                | 296
921                | 297
922                | 298
923                | 299
924                | 300
925                | 301
926                | 302
927                | 303
928                | 304
929                | 305
930                | 306
931                | 307
932                | 309
933                | 314
934                | 315
935                | 316
936                | 317
937                | 318
938                | 321
939                | 322
940                | 323
941                | 327
942                | 329
943                | 331
944                | 332
945                | 333
946                | 334
947                | 335
948                | 336
949                | 337
950                | 338
951                | 339
952                | 340
953                | 341
954                | 342
955                | 344
956                | 345
957                | 346
958                | 347
959                | 348
960                | 349
961                | 350
962                | 351
963                | 352
964                | 355
965                | 356
966                | 357
967                | 358
968                | 359
969                | 360
970                | 363
971                | 365
972                | 366
973                | 367
974                | 368
975                | 370
976                | 371
977                | 372
978                | 373
979                | 375
980                | 376
981                | 377
982                | 378
983                | 379
984                | 380
985                | 384
986                | 386
987                | 387
988                | 388
989                | 391
990                | 392
991                | 393
992                | 394
993                | 395
994                | 396
995                | 397
996                | 398
997                | 399
998                | 401
999                | 402
1000                | 403
1001                | 404
1002                | 405
1003                | 406
1004                | 407
1005                | 408
1006                | 409
1007                | 410
1008                | 411
1009                | 412
1010                | 413
1011                | 414
1012                | 415
1013                | 416
1014                | 417
1015                | 419
1016                | 420
1017                | 421
1018                | 425
1019                | 426
1020                | 427
1021                | 428
1022                | 429
1023                | 430
1024                | 431
1025                | 432
1026                | 433
1027                | 435
1028                | 436
1029                | 437
1030                | 438
1031                | 440
1032                | 441
1033                | 442
1034                | 444
1035                | 445
1036                | 446
1037                | 447
1038                | 448
1039                | 449
1040                | 450
1041                | 451
1042                | 452
1043                | 453
1044                | 454
1045                | 455
1046                | 456
1047                | 457
1048                | 458
1049                | 459
1050                | 460
1051                | 461
1052                | 462
1053                | 463
1054                | 465
1055                | 466
1056                | 467
1057                | 468
1058                | 469
1059                | 470
1060                | 471
1061                | 472
1062                | 473
1063                | 474
1064                | 475
1065                | 476
1066                | 477
1067                | 478
1068                | 479
1069                | 480
1070                | 481
1071                | 483
1072                | 484
1073                | 487
1074                | 489
1075                | 490
1076                | 491
1077                | 494
1078                | 500
1079                | 501
1080                | 502
1081                | 503
1082                | 504
1083                | 505
1084                | 506
1085                | 507
1086                | 508
1087                | 509
1088                | 510
1089                | 511
1090                | 512
1091                | 513
1092                | 514
1093                | 515
1094                | 516
1095                | 517
1096                | 518
1097                | 519
1098                | 520
1099                | 521
1100                | 522
1101                | 523
1102                | 524
1103                | 525
1104                | 526
1105                | 527
1106                | 528
1107                | 529
1108                | 530
1109                | 531
1110                | 532
1111                | 533
1112                | 555
1113                | 556
1114                | 558
1115                | 559
1116                | 563
1117                | 566
1118                | 567
1119                | 568
1120                | 569
1121                | 570
1122                | 572
1123                | 576
1124                | 577
1125                | 579
1126                | 580
1127                | 581
1128                | 586
1129                | 590
1130                | 594
1131                | 599
1132                | 601
1133                | 606
1134                | 609
1135                | 611
1136                | 614
1137                | 617
1138                | 618
1139                | 619
1140                | 621
1141                | 622
1142                | 623
1143                | 630
1144                | 631
1145                | 632
1146                | 637
1147                | 638
1148                | 639
1149                | 640
1150                | 641
1151                | 642
1152                | 643
1153                | 645
1154                | 646
1155                | 647
1156                | 648
1157                | 651
1158                | 653
1159                | 655
1160                | 659
1161                | 660
1162                | 662
1163                | 663
1164                | 664
1165                | 665
1166                | 667
1167                | 668
1168                | 670
1169                | 671
1170                | 672
1171                | 673
1172                | 674
1173                | 675
1174                | 677
1175                | 678
1176                | 679
1177                | 680
1178                | 682
1179                | 683
1180                | 684
1181                | 685
1182                | 687
1183                | 688
1184                | 689
1185                | 690
1186                | 693
1187                | 694
1188                | 695
1189                | 696
1190                | 698
1191                | 699
1192                | 700
1193                | 704
1194                | 705
1195                | 706
1196                | 707
1197                | 708
1198                | 709
1199                | 710
1200                | 711
1201                | 712
1202                | 713
1203                | 714
1204                | 715
1205                | 716
1206                | 717
1207                | 718
1208                | 719
1209                | 902
1210                | 910
1211                | 914
1212                | 922
1213                | 926
1214                | 930
1215                | 931
1216                | 932
1217                | 933
1218                | 937
1219                | 938
1220                | 939
1221                | 940
1222                | 942
1223                | 943
1224                | 946
1225                | 948
1226                | 950
1227                | 951
1228                | 952
1229                | 955
1230                | 957
1231                | 960
1232                | 961
1233                | 967
1234                | 2001
1235                | 2002
1236                | 2003
1237                | 2004
1238                | 2005
1239                | 2006
1240                | 2007
1241                | 2008
1242                | 2009
1243                | 2010
1244                | 2011
1245                | 2012
1246                | 2013
1247                | 2014
1248                | 2015
1249                | 2016
1250                | 2017
1251                | 2018
1252                | 2060
1253                | 2061
1254                | 2071
1255                | 2073
1256                | 2075
1257                | 2080
1258                | 2095
1259                | 2096
1260                | 2119
1261                | 2140
1262                | 2182
1263                | 2183
1264                | 2207
1265                | 2225
1266                | 2236
1267                | 2252
1268                | 2261
1269                | 2284
1270                | 2286
1271                | 2287
1272                | 2288
1273                | 2307
1274                | 2308
1275                | 2309
1276                | 2310
1277                | 2311
1278                | 2312
1279                | 2313
1280                | 2317
1281                | 2318
1282                | 2344
1283                | 2350
1284                | 2351
1285                | 2352
1286                | 2356
1287                | 2357
1288                | 2358
1289                | 2359
1290                | 2360
1291                | 2361
1292        )
1293    }
1294}
1295
1296impl UtilmdStromConditionEvaluatorFV2504 {
1297    /// [2006] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingung [199] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolge...
1298    // REVIEW: Counts SG8 instances with SEQ+Z01 where condition [199] is fulfilled and collects their Zeitraum-IDs from SEQ elements[1][0]. Returns True if at least one qualifying parent exists (cardinality enforcement is partial — full 'exactly once' check requires knowing the current SG type). The recursive call self.evaluate(199, ctx) operates at message scope, which is the best available approximation. (medium confidence)
1299    fn evaluate_2006(&self, ctx: &EvaluationContext) -> ConditionResult {
1300        let nav = match ctx.navigator() {
1301            Some(n) => n,
1302            None => return ConditionResult::Unknown,
1303        };
1304        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1305        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1306        for i in 0..sg8_count {
1307            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1308            let is_z01 = seq_segs.iter().any(|s| {
1309                s.elements
1310                    .first()
1311                    .and_then(|e| e.first())
1312                    .is_some_and(|v| v == "Z01")
1313            });
1314            if is_z01 && matches!(self.evaluate(199, ctx), ConditionResult::True) {
1315                for seq in &seq_segs {
1316                    if seq
1317                        .elements
1318                        .first()
1319                        .and_then(|e| e.first())
1320                        .is_some_and(|v| v == "Z01")
1321                    {
1322                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1323                            if !zid.is_empty() {
1324                                qualifying_zeitraum_ids.push(zid.clone());
1325                            }
1326                        }
1327                    }
1328                }
1329            }
1330        }
1331        if qualifying_zeitraum_ids.is_empty() {
1332            return ConditionResult::Unknown;
1333        }
1334        ConditionResult::True
1335    }
1336
1337    /// [2007] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [199] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfol...
1338    // REVIEW: Semantically identical to [2006] — 'Bedingungen' (plural) vs 'Bedingung' (singular) is a grammatical variation with no functional difference. Same logic: collects qualifying SG8 SEQ+Z01 Zeitraum-IDs where condition [199] is fulfilled. Recursive call self.evaluate(199, ctx) operates at message scope. (medium confidence)
1339    fn evaluate_2007(&self, ctx: &EvaluationContext) -> ConditionResult {
1340        let nav = match ctx.navigator() {
1341            Some(n) => n,
1342            None => return ConditionResult::Unknown,
1343        };
1344        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1345        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1346        for i in 0..sg8_count {
1347            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1348            let is_z01 = seq_segs.iter().any(|s| {
1349                s.elements
1350                    .first()
1351                    .and_then(|e| e.first())
1352                    .is_some_and(|v| v == "Z01")
1353            });
1354            if is_z01 && matches!(self.evaluate(199, ctx), ConditionResult::True) {
1355                for seq in &seq_segs {
1356                    if seq
1357                        .elements
1358                        .first()
1359                        .and_then(|e| e.first())
1360                        .is_some_and(|v| v == "Z01")
1361                    {
1362                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1363                            if !zid.is_empty() {
1364                                qualifying_zeitraum_ids.push(zid.clone());
1365                            }
1366                        }
1367                    }
1368                }
1369            }
1370        }
1371        if qualifying_zeitraum_ids.is_empty() {
1372            return ConditionResult::Unknown;
1373        }
1374        ConditionResult::True
1375    }
1376
1377    /// [2008] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingung [89] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolgen...
1378    // REVIEW: Same structure as [2006/2007] but references condition [89] instead of [199]. Counts qualifying SG8 SEQ+Z01 instances where condition [89] is fulfilled and collects their Zeitraum-IDs from SEQ elements[1][0]. The recursive self.evaluate(89, ctx) call operates at message scope. (medium confidence)
1379    fn evaluate_2008(&self, ctx: &EvaluationContext) -> ConditionResult {
1380        let nav = match ctx.navigator() {
1381            Some(n) => n,
1382            None => return ConditionResult::Unknown,
1383        };
1384        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1385        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1386        for i in 0..sg8_count {
1387            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1388            let is_z01 = seq_segs.iter().any(|s| {
1389                s.elements
1390                    .first()
1391                    .and_then(|e| e.first())
1392                    .is_some_and(|v| v == "Z01")
1393            });
1394            if is_z01 && matches!(self.evaluate(89, ctx), ConditionResult::True) {
1395                for seq in &seq_segs {
1396                    if seq
1397                        .elements
1398                        .first()
1399                        .and_then(|e| e.first())
1400                        .is_some_and(|v| v == "Z01")
1401                    {
1402                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1403                            if !zid.is_empty() {
1404                                qualifying_zeitraum_ids.push(zid.clone());
1405                            }
1406                        }
1407                    }
1408                }
1409            }
1410        }
1411        if qualifying_zeitraum_ids.is_empty() {
1412            return ConditionResult::Unknown;
1413        }
1414        ConditionResult::True
1415    }
1416
1417    /// [2009] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [89] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfolg...
1418    // REVIEW: Semantically identical to [2008] — 'Bedingungen' (plural) vs 'Bedingung' (singular) is a grammatical variation. Same logic: collects qualifying SG8 SEQ+Z01 Zeitraum-IDs where condition [89] is fulfilled. Recursive call self.evaluate(89, ctx) operates at message scope. (medium confidence)
1419    fn evaluate_2009(&self, ctx: &EvaluationContext) -> ConditionResult {
1420        let nav = match ctx.navigator() {
1421            Some(n) => n,
1422            None => return ConditionResult::Unknown,
1423        };
1424        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1425        let mut qualifying_zeitraum_ids: Vec<String> = Vec::new();
1426        for i in 0..sg8_count {
1427            let seq_segs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1428            let is_z01 = seq_segs.iter().any(|s| {
1429                s.elements
1430                    .first()
1431                    .and_then(|e| e.first())
1432                    .is_some_and(|v| v == "Z01")
1433            });
1434            if is_z01 && matches!(self.evaluate(89, ctx), ConditionResult::True) {
1435                for seq in &seq_segs {
1436                    if seq
1437                        .elements
1438                        .first()
1439                        .and_then(|e| e.first())
1440                        .is_some_and(|v| v == "Z01")
1441                    {
1442                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1443                            if !zid.is_empty() {
1444                                qualifying_zeitraum_ids.push(zid.clone());
1445                            }
1446                        }
1447                    }
1448                }
1449            }
1450        }
1451        if qualifying_zeitraum_ids.is_empty() {
1452            return ConditionResult::Unknown;
1453        }
1454        ConditionResult::True
1455    }
1456
1457    /// [1] Wenn Aufteilung vorhanden
1458    fn evaluate_1(&self, ctx: &EvaluationContext) -> ConditionResult {
1459        ctx.external.evaluate("message_splitting")
1460    }
1461
1462    /// [4] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle LF
1463    fn evaluate_4(&self, ctx: &EvaluationContext) -> ConditionResult {
1464        ctx.external.evaluate("recipient_is_lf")
1465    }
1466
1467    /// [5] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle LF
1468    fn evaluate_5(&self, ctx: &EvaluationContext) -> ConditionResult {
1469        ctx.external.evaluate("sender_is_lf")
1470    }
1471
1472    /// [6] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle ÜNB
1473    fn evaluate_6(&self, ctx: &EvaluationContext) -> ConditionResult {
1474        ctx.external.evaluate("recipient_role_check")
1475    }
1476
1477    /// [7] Wenn SG4 STS+7++ZG9/ZH1/ZH2 (Transaktionsgrund: Aufhebung einer zukünftigen Zuordnung wegen Auszug des Kunden / -wegen Stilllegung / -wegen aufgehobenem Vertragsverhältnis) vorhanden
1478    fn evaluate_7(&self, ctx: &EvaluationContext) -> ConditionResult {
1479        let sts_segs = ctx.find_segments("STS");
1480        let found = sts_segs.iter().any(|s| {
1481            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
1482                && s.elements.get(2).and_then(|e| e.first())
1483                    .is_some_and(|v| ["ZG9", "ZH1", "ZH2"].contains(&v.as_str()))
1484        });
1485        ConditionResult::from(found)
1486    }
1487
1488    /// [8] Wenn für Datenclearing erforderlich
1489    fn evaluate_8(&self, ctx: &EvaluationContext) -> ConditionResult {
1490        ctx.external.evaluate("data_clearing_required")
1491    }
1492
1493    /// [9] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle MSB
1494    fn evaluate_9(&self, ctx: &EvaluationContext) -> ConditionResult {
1495        ctx.external.evaluate("sender_role_check")
1496    }
1497
1498    /// [10] Wenn SG4 STS+7++xxx+xxx+E01/E03 (Transaktionsgrund befristete Anmeldung) vorhanden
1499    fn evaluate_10(&self, ctx: &EvaluationContext) -> ConditionResult {
1500        // STS+7++E01+ZW4+E03: element[4] is c556_3.d9013 = transaktionsgrundErgaenzungBefristeteAnmeldung
1501        ctx.has_qualified_value("STS", 0, "7", 4, 0, &["E01", "E03"])
1502    }
1503
1504    /// [11] Wenn SG4 STS+7++ZG9/ZH1/ZH2 (Transaktionsgrund: Aufhebung einer zukünftigen Zuordnung wegen Auszug des Kunden / -wegen Stilllegung / -wegen aufgehobenem Vertragsverhältnis) nicht vorhanden
1505    fn evaluate_11(&self, ctx: &EvaluationContext) -> ConditionResult {
1506        let sts_segs = ctx.find_segments("STS");
1507        let found = sts_segs.iter().any(|s| {
1508            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
1509                && s.elements.get(2).and_then(|e| e.first())
1510                    .is_some_and(|v| ["ZG9", "ZH1", "ZH2"].contains(&v.as_str()))
1511        });
1512        ConditionResult::from(!found)
1513    }
1514
1515    /// [12] Wenn SG4 DTM+471 (Ende zum nächstmöglichem Termin) nicht vorhanden
1516    fn evaluate_12(&self, ctx: &EvaluationContext) -> ConditionResult {
1517        let dtm_segs = ctx.find_segments("DTM");
1518        let found = dtm_segs.iter().any(|s| {
1519            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "471")
1520        });
1521        ConditionResult::from(!found)
1522    }
1523
1524    /// [13] Wenn SG4 STS+E01++Z01 (Status der Antwort: Zustimmung mit Terminänderung) nicht vorhanden
1525    fn evaluate_13(&self, ctx: &EvaluationContext) -> ConditionResult {
1526        let sts_segs = ctx.find_segments("STS");
1527        let found = sts_segs.iter().any(|s| {
1528            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1529                && s.elements.get(2).and_then(|e| e.first())
1530                    .is_some_and(|v| ["Z01"].contains(&v.as_str()))
1531        });
1532        ConditionResult::from(!found)
1533    }
1534
1535    /// [14] Wenn Datum bekannt
1536    fn evaluate_14(&self, ctx: &EvaluationContext) -> ConditionResult {
1537        ctx.external.evaluate("date_known")
1538    }
1539
1540    /// [15] Wenn in derselben SG8 das SEQ+Z98 (Informative Daten der Marktlokation) vorhanden
1541    fn evaluate_15(&self, ctx: &EvaluationContext) -> ConditionResult {
1542        let seq_segs = ctx.find_segments("SEQ");
1543        let found = seq_segs.iter().any(|s| {
1544            s.elements.first().and_then(|e| e.first())
1545                .is_some_and(|v| ["Z98"].contains(&v.as_str()))
1546        });
1547        ConditionResult::from(found)
1548    }
1549
1550    /// [16] Wenn SG4 STS+E01++Z12 (Status der Antwort: Ablehnung Vertragsbindung) vorhanden
1551    fn evaluate_16(&self, ctx: &EvaluationContext) -> ConditionResult {
1552        let sts_segs = ctx.find_segments("STS");
1553        let found = sts_segs.iter().any(|s| {
1554            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1555                && s.elements.get(2).and_then(|e| e.first())
1556                    .is_some_and(|v| ["Z12"].contains(&v.as_str()))
1557        });
1558        ConditionResult::from(found)
1559    }
1560
1561    /// [17] Wenn in derselben SG8 das SEQ+Z01/Z80/Z81 (Daten der Marktlokation) vorhanden
1562    fn evaluate_17(&self, ctx: &EvaluationContext) -> ConditionResult {
1563        let seq_segs = ctx.find_segments("SEQ");
1564        let found = seq_segs.iter().any(|s| {
1565            s.elements.first().and_then(|e| e.first())
1566                .is_some_and(|v| ["Z01", "Z80", "Z81"].contains(&v.as_str()))
1567        });
1568        ConditionResult::from(found)
1569    }
1570
1571    /// [18] Wenn SG4 DTM+93 (Ende zum) nicht vorhanden
1572    fn evaluate_18(&self, ctx: &EvaluationContext) -> ConditionResult {
1573        let dtm_segs = ctx.find_segments("DTM");
1574        let found = dtm_segs.iter().any(|s| {
1575            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "93")
1576        });
1577        ConditionResult::from(!found)
1578    }
1579
1580    /// [19] Wenn SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+++ZC0 (Prognose auf Basis von Werten) vorhanden
1581    fn evaluate_19(&self, ctx: &EvaluationContext) -> ConditionResult {
1582        let seq_segs = ctx.find_segments("SEQ");
1583        let found = seq_segs.iter().any(|s| {
1584            s.elements.first().and_then(|e| e.first())
1585                .is_some_and(|v| ["Z01", "Z98"].contains(&v.as_str()))
1586        });
1587        ConditionResult::from(found)
1588    }
1589
1590    /// [20] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+Z30++Z07 (Verbrauch) vorhanden
1591    fn evaluate_20(&self, ctx: &EvaluationContext) -> ConditionResult {
1592        let seq_segs = ctx.find_segments("SEQ");
1593        let found = seq_segs.iter().any(|s| {
1594            s.elements.first().and_then(|e| e.first())
1595                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
1596        });
1597        ConditionResult::from(found)
1598    }
1599
1600    /// [21] Wenn SG10 CCI+++ZA6 (Prognose auf Basis von Profilen) in dieser SG8 vorhanden
1601    fn evaluate_21(&self, ctx: &EvaluationContext) -> ConditionResult {
1602        let cci_segs = ctx.find_segments("CCI");
1603        let found = cci_segs.iter().any(|s| {
1604            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA6")
1605        });
1606        ConditionResult::from(found)
1607    }
1608
1609    /// [22] Es ist die Zeitraum-ID vom DE1156 aus einem passenden SG6 RFF+Z47/ Z48/ Z49 (Verwendungszeitraum der Daten) einzutragen
1610    // REVIEW: Checks if any SG6 RFF+Z47/Z48/Z49 Zeitraum-ID (DE1156 at elements[0][2]) matches any SG8 SEQ Zeitraum-ID reference (DE1050 at elements[1][0]). Uses groups_share_qualified_value for cross-group correlation across all three qualifying codes. (medium confidence)
1611    fn evaluate_22(&self, ctx: &EvaluationContext) -> ConditionResult {
1612        for qual in &["Z47", "Z48", "Z49"] {
1613            if matches!(
1614                ctx.groups_share_qualified_value(
1615                    "RFF",
1616                    0,
1617                    qual,
1618                    0,
1619                    2,
1620                    &["SG4", "SG6"],
1621                    "SEQ",
1622                    1,
1623                    0,
1624                    &["SG4", "SG8"],
1625                ),
1626                ConditionResult::True
1627            ) {
1628                return ConditionResult::True;
1629            }
1630        }
1631        ConditionResult::False
1632    }
1633
1634    /// [23] Wenn in dieser SG4 das STS+E01++A05/A99 (Status der Antwort) vorhanden
1635    fn evaluate_23(&self, ctx: &EvaluationContext) -> ConditionResult {
1636        let sts_segs = ctx.find_segments("STS");
1637        let found = sts_segs.iter().any(|s| {
1638            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1639                && s.elements.get(2).and_then(|e| e.first())
1640                    .is_some_and(|v| ["A05", "A99"].contains(&v.as_str()))
1641        });
1642        ConditionResult::from(found)
1643    }
1644
1645    /// [24] Wenn in dieser SG4 das STS+E01++A25/A99 (Status der Antwort) vorhanden
1646    fn evaluate_24(&self, ctx: &EvaluationContext) -> ConditionResult {
1647        let sts_segs = ctx.find_segments("STS");
1648        let found = sts_segs.iter().any(|s| {
1649            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1650                && s.elements.get(2).and_then(|e| e.first())
1651                    .is_some_and(|v| ["A25", "A99"].contains(&v.as_str()))
1652        });
1653        ConditionResult::from(found)
1654    }
1655
1656    /// [25] Wenn die Veräußerungsform der erzeugenden Marktlokation der Marktprämie zugeordnet ist
1657    fn evaluate_25(&self, _ctx: &EvaluationContext) -> ConditionResult {
1658        // TODO: implement
1659        ConditionResult::Unknown
1660    }
1661
1662    /// [27] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle ein T oder R enthält
1663    fn evaluate_27(&self, ctx: &EvaluationContext) -> ConditionResult {
1664        let dtm_segs = ctx.find_segments("DTM");
1665        let found = dtm_segs.iter().any(|s| {
1666            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z01")
1667                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
1668                    v.chars().nth(3).is_some_and(|c| ['T', 'R'].contains(&c))
1669                })
1670        });
1671        ConditionResult::from(found)
1672    }
1673
1674    /// [30] Wenn Antwort auf Aktivierung übermittelt wird
1675    fn evaluate_30(&self, ctx: &EvaluationContext) -> ConditionResult {
1676        // Antwort auf Aktivierung — depends on PID context
1677        ctx.external.evaluate("activation_response")
1678    }
1679
1680    /// [31] Wenn eine Korrektur erfolgt
1681    fn evaluate_31(&self, ctx: &EvaluationContext) -> ConditionResult {
1682        ctx.external.evaluate("correction_in_progress")
1683    }
1684
1685    /// [32] Wenn mehr als ein SG8 (Referenz auf die Lokationsbündelstruktur) vorhanden
1686    fn evaluate_32(&self, ctx: &EvaluationContext) -> ConditionResult {
1687        let seq_segs = ctx.find_segments("SEQ");
1688        ConditionResult::from(seq_segs.len() > 1)
1689    }
1690
1691    /// [33] Wenn in einer SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6 \"Produkte zur Bestellung / Änderung von Date...
1692    fn evaluate_33(&self, ctx: &EvaluationContext) -> ConditionResult {
1693        ctx.external.evaluate("code_list_membership_check")
1694    }
1695
1696    /// [34] Wenn Antwort auf Deaktivierung übermittelt wird
1697    fn evaluate_34(&self, ctx: &EvaluationContext) -> ConditionResult {
1698        // Antwort auf Deaktivierung — depends on PID context
1699        ctx.external.evaluate("deactivation_response")
1700    }
1701
1702    /// [35] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle T (Termin) enthält
1703    fn evaluate_35(&self, ctx: &EvaluationContext) -> ConditionResult {
1704        let dtm_segs = ctx.find_segments("DTM");
1705        let found = dtm_segs.iter().any(|s| {
1706            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z01")
1707                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
1708                    v.chars().nth(3).is_some_and(|c| c == 'T')
1709                })
1710        });
1711        ConditionResult::from(found)
1712    }
1713
1714    /// [36] Wenn in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTI...
1715    fn evaluate_36(&self, ctx: &EvaluationContext) -> ConditionResult {
1716        ctx.external.evaluate("code_list_membership_check")
1717    }
1718
1719    /// [37] Wenn Anmeldung/ Änderung befristet
1720    fn evaluate_37(&self, ctx: &EvaluationContext) -> ConditionResult {
1721        // Same check as [10]: STS element[4] is befristete Anmeldung code
1722        ctx.has_qualified_value("STS", 0, "7", 4, 0, &["E01", "E03"])
1723    }
1724
1725    /// [38] Es sind nur die Code der Produkteigenschaft zu dem in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 erlaubt, die in der Codeliste der Konfigurationen im Kapitel  6.1 \"Anmeldung ei...
1726    fn evaluate_38(&self, ctx: &EvaluationContext) -> ConditionResult {
1727        ctx.external.evaluate("code_list_membership_check")
1728    }
1729
1730    /// [39] Wenn in derselben SG8 SEQ+Z79 m PIA+5 (Erforderliches Produkt) DE7140 ein Produkt-Code genannt ist, der in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTIL...
1731    fn evaluate_39(&self, ctx: &EvaluationContext) -> ConditionResult {
1732        ctx.external.evaluate("code_list_membership_check")
1733    }
1734
1735    /// [40] Es ist nur der Wertebereich erlaubt, der zu dem in derselben SG8 SEQ+Z79 im PIA+5 (Erforderliches Produkt) DE7140 genannten Produkt, das in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeld...
1736    fn evaluate_40(&self, ctx: &EvaluationContext) -> ConditionResult {
1737        ctx.external.evaluate("code_list_membership_check")
1738    }
1739
1740    /// [41] Es ist eine Produktpaket-ID aus dem DE1050 von einem SG8 SEQ+Z79 (Erforderliches Produkt) zu nennen
1741    fn evaluate_41(&self, ctx: &EvaluationContext) -> ConditionResult {
1742        // Check: Produktpaket-ID exists in SEQ+Z79 (Erforderliches Produkt)
1743        let seq_z79 = ctx.find_segments_with_qualifier("SEQ", 0, "Z79");
1744        if seq_z79.is_empty() {
1745            return ConditionResult::Unknown;
1746        }
1747        // Check if SEQ has a value in C286.D1050 (elements[1][0])
1748        let found = seq_z79.iter().any(|s| {
1749            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| !v.is_empty())
1750        });
1751        ConditionResult::from(found)
1752    }
1753
1754    /// [42] Wenn mehr als ein SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) vorhanden
1755    fn evaluate_42(&self, ctx: &EvaluationContext) -> ConditionResult {
1756        let seq_segs = ctx.find_segments("SEQ");
1757        let zh0_count = seq_segs.iter().filter(|s| {
1758            s.elements.first()
1759                .and_then(|e| e.first())
1760                .is_some_and(|v| v == "ZH0")
1761        }).count();
1762        ConditionResult::from(zh0_count > 1)
1763    }
1764
1765    /// [43] Wenn in dieser SG4 das STS+E01++A12 / A13 (Status der Antwort) vorhanden
1766    fn evaluate_43(&self, ctx: &EvaluationContext) -> ConditionResult {
1767        let sts_segs = ctx.find_segments("STS");
1768        let found = sts_segs.iter().any(|s| {
1769            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1770                && s.elements.get(2).and_then(|e| e.first())
1771                    .is_some_and(|v| ["A12", "A13"].contains(&v.as_str()))
1772        });
1773        ConditionResult::from(found)
1774    }
1775
1776    /// [44] Es ist die Zeitraum-ID vom DE1156 aus einem passenden SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: "Gültige Daten", "Keine Daten") aus der Anfragennachricht aus SG6 RFF+TN DE1154 ((Referenz Vo...
1777    fn evaluate_44(&self, _ctx: &EvaluationContext) -> ConditionResult {
1778        // Hinweis: Zeitraum-ID aus passendem SG6 RFF+Z49/Z53 der Anfragenachricht eintragen — informational data population rule
1779        ConditionResult::True
1780    }
1781
1782    /// [45] Wenn in derselben SG8 das SG10 CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokation) vorhanden
1783    fn evaluate_45(&self, ctx: &EvaluationContext) -> ConditionResult {
1784        let cci_segs = ctx.find_segments("CCI");
1785        let found = cci_segs.iter().any(|s| {
1786            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z01")
1787                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "Z82")
1788        });
1789        ConditionResult::from(found)
1790    }
1791
1792    /// [46] Wenn ID für Objekt vergeben wurde
1793    fn evaluate_46(&self, _ctx: &EvaluationContext) -> ConditionResult {
1794        // TODO: implement
1795        ConditionResult::Unknown
1796    }
1797
1798    /// [47] Wenn SG10 CCI+15++Z21 (Summenzeitreihentyp) CAV+DBA/ VZR/ EGS/ LGS/ SLS/ SES/ TLS/ TES/ BIL/ BIP/ BIT/ GAL/ GAP/ GAT/ GEL/ GEP/ GET/ SOL/ SOP/ SOT/ WFL/ WFP/ WFT/ WNL/ WNP/ WNT vorhanden
1799    // REVIEW: Iterates all SG8 instances and their SG10 children looking for CCI with elements[0][0]=="15" and elements[2][0]=="Z21" (Zeitreihentyp), then checks if the same SG10 has a CAV with elements[0][0] in the Summenzeitreihentyp code list. Uses navigator for parent-child group traversal. (medium confidence)
1800    fn evaluate_47(&self, ctx: &EvaluationContext) -> ConditionResult {
1801        const CODES: &[&str] = &[
1802            "DBA", "VZR", "EGS", "LGS", "SLS", "SES", "TLS", "TES", "BIL", "BIP", "BIT", "GAL",
1803            "GAP", "GAT", "GEL", "GEP", "GET", "SOL", "SOP", "SOT", "WFL", "WFP", "WFT", "WNL",
1804            "WNP", "WNT",
1805        ];
1806        let nav = match ctx.navigator {
1807            Some(n) => n,
1808            None => return ConditionResult::Unknown,
1809        };
1810        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1811        for i in 0..sg8_count {
1812            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
1813            for j in 0..sg10_count {
1814                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
1815                let has_cci_15_z21 = ccis.iter().any(|s| {
1816                    s.elements
1817                        .first()
1818                        .and_then(|e: &Vec<String>| e.first())
1819                        .is_some_and(|v: &String| v == "15")
1820                        && s.elements
1821                            .get(2)
1822                            .and_then(|e: &Vec<String>| e.first())
1823                            .is_some_and(|v: &String| v == "Z21")
1824                });
1825                if has_cci_15_z21 {
1826                    let cavs =
1827                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
1828                    if cavs.iter().any(|s| {
1829                        s.elements
1830                            .first()
1831                            .and_then(|e: &Vec<String>| e.first())
1832                            .is_some_and(|v: &String| CODES.contains(&v.as_str()))
1833                    }) {
1834                        return ConditionResult::True;
1835                    }
1836                }
1837            }
1838        }
1839        ConditionResult::False
1840    }
1841
1842    /// [48] Wenn in dieser SG4 das STS+E01++A99 (Status der Antwort: Sonstiges) vorhanden
1843    fn evaluate_48(&self, ctx: &EvaluationContext) -> ConditionResult {
1844        let sts_segs = ctx.find_segments("STS");
1845        let found = sts_segs.iter().any(|s| {
1846            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1847                && s.elements.get(2).and_then(|e| e.first())
1848                    .is_some_and(|v| ["A99"].contains(&v.as_str()))
1849        });
1850        ConditionResult::from(found)
1851    }
1852
1853    /// [49] Wenn in dieser SG4 das STS+E01++E14 (Status der Antwort: Ablehnung Sonstiges) vorhanden
1854    fn evaluate_49(&self, ctx: &EvaluationContext) -> ConditionResult {
1855        let sts_segs = ctx.find_segments("STS");
1856        let found = sts_segs.iter().any(|s| {
1857            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
1858                && s.elements.get(2).and_then(|e| e.first())
1859                    .is_some_and(|v| ["E14"].contains(&v.as_str()))
1860        });
1861        ConditionResult::from(found)
1862    }
1863
1864    /// [50] Wenn kein SG8 SEQ+ZE7 (Informative Daten der Tranche) mit derselben Zeitraum-ID im DE1050 auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z98 (Infor...
1865    // REVIEW: Collects (Zeitraum-ID from SEQ.elements[1][0], Marktlok-ID from sibling RFF+Z18.elements[0][1]) for all SG8 instances with SEQ+Z98 and SEQ+ZE7. Returns True if any Z98 group has no ZE7 group matching on both values. Uses collect_group_values with instance-index correlation via HashMap, assuming each SG8 has at most one SEQ (guaranteed as entry segment) and the zip ordering is stable. (medium confidence)
1866    fn evaluate_50(&self, ctx: &EvaluationContext) -> ConditionResult {
1867        use std::collections::HashMap;
1868
1869        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
1870        let seq_zeitraum = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
1871        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
1872        let rff_ids = ctx.collect_group_values("RFF", 0, 1, &["SG4", "SG8"]);
1873
1874        // Build per-instance RFF lookup: instance_idx -> list of (qualifier, id)
1875        let mut rff_by_instance: HashMap<usize, Vec<(String, String)>> = HashMap::new();
1876        for ((idx, q), (_, id)) in rff_quals.iter().zip(rff_ids.iter()) {
1877            rff_by_instance
1878                .entry(*idx)
1879                .or_default()
1880                .push((q.clone(), id.clone()));
1881        }
1882
1883        // Build (zeitraum_id, marktlok_id) for Z98 and ZE7 SG8 instances
1884        let mut seq_zeitraum_map: HashMap<usize, String> = HashMap::new();
1885        for (idx, z) in &seq_zeitraum {
1886            seq_zeitraum_map.insert(*idx, z.clone());
1887        }
1888
1889        let z98_data: Vec<(String, String)> = seq_quals
1890            .iter()
1891            .filter(|(_, q)| q == "Z98")
1892            .map(|(idx, _)| {
1893                let zeitraum = seq_zeitraum_map.get(idx).cloned().unwrap_or_default();
1894                let marktlok = rff_by_instance
1895                    .get(idx)
1896                    .and_then(|rffs| rffs.iter().find(|(q, _)| q == "Z18"))
1897                    .map(|(_, id)| id.clone())
1898                    .unwrap_or_default();
1899                (zeitraum, marktlok)
1900            })
1901            .collect();
1902
1903        if z98_data.is_empty() {
1904            return ConditionResult::Unknown;
1905        }
1906
1907        let ze7_data: Vec<(String, String)> = seq_quals
1908            .iter()
1909            .filter(|(_, q)| q == "ZE7")
1910            .map(|(idx, _)| {
1911                let zeitraum = seq_zeitraum_map.get(idx).cloned().unwrap_or_default();
1912                let marktlok = rff_by_instance
1913                    .get(idx)
1914                    .and_then(|rffs| rffs.iter().find(|(q, _)| q == "Z18"))
1915                    .map(|(_, id)| id.clone())
1916                    .unwrap_or_default();
1917                (zeitraum, marktlok)
1918            })
1919            .collect();
1920
1921        ConditionResult::from(z98_data.iter().any(|(z98_zeit, z98_lok)| {
1922            !ze7_data
1923                .iter()
1924                .any(|(ze7_zeit, ze7_lok)| ze7_zeit == z98_zeit && ze7_lok == z98_lok)
1925        }))
1926    }
1927
1928    /// [51] Wenn die Marktlokations-ID im SG8 RFF+Z18 derselben SG8 SEQ+Z98 (Informative Daten der Marktlokation) mit derselben Zeitraum-ID im DE1050 nicht auf ein SG8 SEQ+Z78 (Referenz auf die Lokationsbünde...
1929    // REVIEW: Condition is True when no Z98 SG8 (Informative Daten der Marktlokation) references — via matching Zeitraum-ID in SEQ.C286.DE1050 — a Z78 SG8 (Referenz auf Lokationsbündelstruktur) that carries the pauschal bundle code 9992000000018 in RFF+Z31.DE1154. Requires navigator for cross-SG8 Zeitraum-ID correlation. (medium confidence)
1930    fn evaluate_51(&self, ctx: &EvaluationContext) -> ConditionResult {
1931        let nav = match ctx.navigator() {
1932            Some(n) => n,
1933            None => return ConditionResult::Unknown,
1934        };
1935        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
1936        let pauschal_id = "9992000000018";
1937        // Collect Zeitraum-IDs from Z78 SG8s that carry the pauschal RFF+Z31 ID
1938        let mut pauschal_zeitraum_ids: Vec<String> = Vec::new();
1939        for i in 0..sg8_count {
1940            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1941            let has_z78 = seqs.iter().any(|s| {
1942                s.elements
1943                    .first()
1944                    .and_then(|e| e.first())
1945                    .is_some_and(|v| v == "Z78")
1946            });
1947            if !has_z78 {
1948                continue;
1949            }
1950            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
1951            let has_pauschal = rffs.iter().any(|s| {
1952                s.elements
1953                    .first()
1954                    .and_then(|e| e.first())
1955                    .is_some_and(|v| v == "Z31")
1956                    && s.elements
1957                        .first()
1958                        .and_then(|e| e.get(1))
1959                        .is_some_and(|v| v.replace(' ', "") == pauschal_id)
1960            });
1961            if has_pauschal {
1962                for seq in &seqs {
1963                    if seq
1964                        .elements
1965                        .first()
1966                        .and_then(|e| e.first())
1967                        .is_some_and(|v| v == "Z78")
1968                    {
1969                        if let Some(zid) = seq.elements.get(1).and_then(|e| e.first()) {
1970                            if !zid.is_empty() {
1971                                pauschal_zeitraum_ids.push(zid.clone());
1972                            }
1973                        }
1974                    }
1975                }
1976            }
1977        }
1978        // For each Z98 SG8, check whether its Zeitraum-ID (SEQ.C286.DE1050) maps to a pauschal Z78
1979        for i in 0..sg8_count {
1980            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
1981            for seq in &seqs {
1982                if seq
1983                    .elements
1984                    .first()
1985                    .and_then(|e| e.first())
1986                    .is_some_and(|v| v == "Z98")
1987                {
1988                    let zid = seq
1989                        .elements
1990                        .get(1)
1991                        .and_then(|e| e.first())
1992                        .map(|s| s.as_str())
1993                        .unwrap_or("");
1994                    if !zid.is_empty() && pauschal_zeitraum_ids.iter().any(|z| z == zid) {
1995                        // Z98 SG8 references a pauschal Z78 → condition is False
1996                        return ConditionResult::False;
1997                    }
1998                }
1999            }
2000        }
2001        // No Z98 SG8 references the pauschal bundle → condition is True
2002        ConditionResult::True
2003    }
2004
2005    /// [52] Wenn SG10 CCI+Z07++Z55/ Z56 (Profiltyp: sonstige verbrauchende Marktlokation / sonstige erzeugende Marktlokation) vorhanden
2006    fn evaluate_52(&self, ctx: &EvaluationContext) -> ConditionResult {
2007        let cci_segs = ctx.find_segments("CCI");
2008        let found = cci_segs.iter().any(|s| {
2009            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z07")
2010                && s.elements.get(2).and_then(|e| e.first())
2011                    .is_some_and(|v| ["Z55", "Z56"].contains(&v.as_str()))
2012        });
2013        ConditionResult::from(found)
2014    }
2015
2016    /// [53] Wenn weitere Präzisierungen als über CCI+Z07 (Profiltyp) möglich sind
2017    fn evaluate_53(&self, _ctx: &EvaluationContext) -> ConditionResult {
2018        // TODO: implement
2019        ConditionResult::Unknown
2020    }
2021
2022    /// [54] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+Z30++Z06 (Lieferrichtung: Erzeugung) vorhanden
2023    fn evaluate_54(&self, ctx: &EvaluationContext) -> ConditionResult {
2024        let seq_segs = ctx.find_segments("SEQ");
2025        let found = seq_segs.iter().any(|s| {
2026            s.elements.first().and_then(|e| e.first())
2027                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
2028        });
2029        ConditionResult::from(found)
2030    }
2031
2032    /// [55] Wenn in dieser SG4 das STS+E01++A06/ A99 (Status der Antwort) vorhanden
2033    fn evaluate_55(&self, ctx: &EvaluationContext) -> ConditionResult {
2034        let sts_segs = ctx.find_segments("STS");
2035        let found = sts_segs.iter().any(|s| {
2036            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
2037                && s.elements.get(2).and_then(|e| e.first())
2038                    .is_some_and(|v| ["A06", "A99"].contains(&v.as_str()))
2039        });
2040        ConditionResult::from(found)
2041    }
2042
2043    /// [56] Wenn im STS+E01 im DE9013 (Status der Antwort) ein Antwortcode aus dem Cluster Zustimmung vorhanden ist
2044    fn evaluate_56(&self, ctx: &EvaluationContext) -> ConditionResult {
2045        // Check: STS+E01 DE9013 has a Zustimmung (approval) cluster code
2046        // Zustimmung codes start with A0x (A01-A07 are approval codes)
2047        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
2048        let found = sts_segs.iter().any(|s| {
2049            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| {
2050                ["A01", "A02", "A03", "A04", "A05", "A06", "A07", "A08", "A09", "A10",
2051                 "A11", "A12", "A13", "A14", "A15", "A16", "A17", "A25"].contains(&v.as_str())
2052            })
2053        });
2054        ConditionResult::from(found)
2055    }
2056
2057    /// [57] Wenn in derselben SG8 das CCI+Z45++ZD9 (Abrechnung findet statt) vorhanden ist
2058    fn evaluate_57(&self, ctx: &EvaluationContext) -> ConditionResult {
2059        let cci_segs = ctx.find_segments("CCI");
2060        let found = cci_segs.iter().any(|s| {
2061            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z45")
2062                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZD9")
2063        });
2064        ConditionResult::from(found)
2065    }
2066
2067    /// [58] Wenn in diesem CCI das DE3055 mit dem Code 293 vorhanden
2068    fn evaluate_58(&self, ctx: &EvaluationContext) -> ConditionResult {
2069        let cci_segs = ctx.find_segments("CCI");
2070        let found = cci_segs.iter().any(|s| {
2071            s.elements.iter().any(|e| e.iter().any(|v| v == "293"))
2072        });
2073        ConditionResult::from(found)
2074    }
2075
2076    /// [60] Wenn BGM+Z90 (Beendigung der Zuordnung zur Lokation) vorhanden
2077    fn evaluate_60(&self, ctx: &EvaluationContext) -> ConditionResult {
2078        let bgm_segs = ctx.find_segments("BGM");
2079        let found = bgm_segs.iter().any(|s| {
2080            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z90")
2081        });
2082        ConditionResult::from(found)
2083    }
2084
2085    /// [61] Wenn BGM+Z89 (Zuordnung zur Lokation) vorhanden
2086    fn evaluate_61(&self, ctx: &EvaluationContext) -> ConditionResult {
2087        let bgm_segs = ctx.find_segments("BGM");
2088        let found = bgm_segs.iter().any(|s| {
2089            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z89")
2090        });
2091        ConditionResult::from(found)
2092    }
2093
2094    /// [62] Wenn mehr als eine SG8 SEQ+Z45 (Netznutzungsabrechnungsdaten der Marktlokation), mit derselben Zeitraum-ID im DE1050, mit einer Gruppen-/Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), ...
2095    // REVIEW: Iterates SG8 instances within each SG4, finds those with SEQ+Z45 and a non-empty Zeitraum-ID in elements[1][0]. Checks if PIA+Z02 in the same SG8 has a product code (elements[1][0]) beginning with 1-08-1 through 1-08-5. Groups by Zeitraum-ID and checks if any ID appears more than once. Requires navigator for per-instance group segment access; returns Unknown without one. (medium confidence)
2096    fn evaluate_62(&self, ctx: &EvaluationContext) -> ConditionResult {
2097        let nav = match ctx.navigator {
2098            Some(n) => n,
2099            None => return ConditionResult::Unknown,
2100        };
2101        use std::collections::HashMap;
2102        let mut count_by_zid: HashMap<String, u32> = HashMap::new();
2103        let sg4_count = nav.group_instance_count(&["SG4"]);
2104        for sg4_idx in 0..sg4_count {
2105            let sg8_count = nav.child_group_instance_count(&["SG4"], sg4_idx, "SG8");
2106            for sg8_idx in 0..sg8_count {
2107                let seqs =
2108                    nav.find_segments_in_child_group("SEQ", &["SG4"], sg4_idx, "SG8", sg8_idx);
2109                let zeitraum_opt = seqs
2110                    .iter()
2111                    .filter(|s| {
2112                        s.elements
2113                            .first()
2114                            .and_then(|e: &Vec<String>| e.first())
2115                            .is_some_and(|v: &String| v == "Z45")
2116                    })
2117                    .filter_map(|s| {
2118                        s.elements
2119                            .get(1)
2120                            .and_then(|e: &Vec<String>| e.first())
2121                            .filter(|v| !v.is_empty())
2122                            .cloned()
2123                    })
2124                    .next();
2125                let Some(zid) = zeitraum_opt else { continue };
2126                let pias =
2127                    nav.find_segments_in_child_group("PIA", &["SG4"], sg4_idx, "SG8", sg8_idx);
2128                let has_qualifying_pia = pias.iter().any(|s| {
2129                    s.elements
2130                        .first()
2131                        .and_then(|e: &Vec<String>| e.first())
2132                        .is_some_and(|v: &String| v == "Z02")
2133                        && s.elements
2134                            .get(1)
2135                            .and_then(|e: &Vec<String>| e.first())
2136                            .map(|code| {
2137                                code.starts_with("1-08-1")
2138                                    || code.starts_with("1-08-2")
2139                                    || code.starts_with("1-08-3")
2140                                    || code.starts_with("1-08-4")
2141                                    || code.starts_with("1-08-5")
2142                            })
2143                            .unwrap_or(false)
2144                });
2145                if has_qualifying_pia {
2146                    *count_by_zid.entry(zid).or_insert(0) += 1;
2147                }
2148            }
2149        }
2150        ConditionResult::from(count_by_zid.values().any(|&c| c > 1))
2151    }
2152
2153    /// [63] Wenn in dieser SG4 das STS+E01++A15/ A99 (Status der Antwort) vorhanden
2154    fn evaluate_63(&self, ctx: &EvaluationContext) -> ConditionResult {
2155        let sts_segs = ctx.find_segments("STS");
2156        let found = sts_segs.iter().any(|s| {
2157            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
2158                && s.elements.get(2).and_then(|e| e.first())
2159                    .is_some_and(|v| ["A15", "A99"].contains(&v.as_str()))
2160        });
2161        ConditionResult::from(found)
2162    }
2163
2164    /// [64] Wenn mehr als eine SG8 SEQ+ZE1 (Informative Netznutzungsabrechnungsdaten der Marktlokation) mit einer Gruppen-/ Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5...
2165    fn evaluate_64(&self, ctx: &EvaluationContext) -> ConditionResult {
2166        // Check: more than one SG8 SEQ+ZE1 has PIA+Z02 with code starting with 1-08-1/2/3/4/5
2167        let pia_segs = ctx.find_segments("PIA");
2168        let count = pia_segs.iter().filter(|s| {
2169            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
2170                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
2171                    ["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"].iter().any(|p| v.starts_with(p))
2172                })
2173        }).count();
2174        ConditionResult::from(count > 1)
2175    }
2176
2177    /// [65] Wenn in derselben SG8 SEQ+ZE1 (Informative Netznutzungsabrechnungsdaten der Marktlokation) eine Gruppen-/Artikel-ID im PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5 beginnt, v...
2178    fn evaluate_65(&self, ctx: &EvaluationContext) -> ConditionResult {
2179        // Check: PIA+Z02 with code starting with 1-08-1/2/3/4/5 exists in same SG8 SEQ+ZE1
2180        let pia_segs = ctx.find_segments("PIA");
2181        let found = pia_segs.iter().any(|s| {
2182            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
2183                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
2184                    ["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"].iter().any(|p| v.starts_with(p))
2185                })
2186        });
2187        ConditionResult::from(found)
2188    }
2189
2190    /// [66] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als einmal vorhanden
2191    fn evaluate_66(&self, ctx: &EvaluationContext) -> ConditionResult {
2192        let seq_segs = ctx.find_segments("SEQ");
2193        let count = seq_segs.iter().filter(|s| {
2194            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH0")
2195        }).count();
2196        ConditionResult::from(count > 1)
2197    }
2198
2199    /// [67] Wenn in keinem SG8 SEQ+Z79 (Bestandteil eine Produktpaketes CCI+Z66/CAV+ZH9 (Produkteigenschaft/ Code der Produkteigenschaft) der Code 9991000002933 (Ruhende Marktlokation ausprägen) vorhanden ist.
2200    fn evaluate_67(&self, ctx: &EvaluationContext) -> ConditionResult {
2201        // Check: no SG8 SEQ+Z79 has CAV+ZH9 with code 9991000002933
2202        let cav_segs = ctx.find_segments("CAV");
2203        let found = cav_segs.iter().any(|s| {
2204            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH9")
2205                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| v == "9991000002933")
2206        });
2207        ConditionResult::from(!found)
2208    }
2209
2210    /// [68] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als zweimal vorhanden
2211    fn evaluate_68(&self, ctx: &EvaluationContext) -> ConditionResult {
2212        let seq_segs = ctx.find_segments("SEQ");
2213        let count = seq_segs.iter().filter(|s| {
2214            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH0")
2215        }).count();
2216        ConditionResult::from(count > 2)
2217    }
2218
2219    /// [69] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) mehr als dreimal vorhanden
2220    fn evaluate_69(&self, ctx: &EvaluationContext) -> ConditionResult {
2221        let seq_segs = ctx.find_segments("SEQ");
2222        let count = seq_segs.iter().filter(|s| {
2223            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH0")
2224        }).count();
2225        ConditionResult::from(count > 3)
2226    }
2227
2228    /// [70] Wenn SG8 SEQ+ZH0 (Priorisierung erforderliches Produktpaket) fünfmal vorhanden
2229    fn evaluate_70(&self, ctx: &EvaluationContext) -> ConditionResult {
2230        let seq_segs = ctx.find_segments("SEQ");
2231        let count = seq_segs.iter().filter(|s| {
2232            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH0")
2233        }).count();
2234        ConditionResult::from(count == 5)
2235    }
2236
2237    /// [71] Wenn Antwort auf Zuordnung übermittelt wird
2238    fn evaluate_71(&self, ctx: &EvaluationContext) -> ConditionResult {
2239        // Antwort auf Zuordnung — depends on PID context
2240        ctx.external.evaluate("assignment_response")
2241    }
2242
2243    /// [72] Wenn Antwort auf Beendigung der Zuordnung übermittelt wird
2244    fn evaluate_72(&self, ctx: &EvaluationContext) -> ConditionResult {
2245        // Antwort auf Beendigung der Zuordnung — depends on PID context
2246        ctx.external.evaluate("assignment_end_response")
2247    }
2248
2249    /// [73] Wenn in derselben SG8 im PIA DE7140 ein Code aus der Codeliste der Gruppenartikel- und Artikel-ID vorhanden ist, der in der Spalte UTILMD/Preisangabe mit X gekennzeichnet ist
2250    fn evaluate_73(&self, ctx: &EvaluationContext) -> ConditionResult {
2251        // Check: PIA DE7140 has a code from Gruppenartikel codeliste with Preisangabe=X
2252        // Approximate: check if PIA+Z02 exists (external codelist check not available)
2253        let pia_segs = ctx.find_segments("PIA");
2254        let found = pia_segs.iter().any(|s| {
2255            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
2256                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| !v.is_empty())
2257        });
2258        if found { ConditionResult::True } else { ConditionResult::Unknown }
2259    }
2260
2261    /// [74] Wenn in der selben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das PIA+5 (Produkt-Daten der Marktlokation) vorhanden
2262    fn evaluate_74(&self, ctx: &EvaluationContext) -> ConditionResult {
2263        let seq_segs = ctx.find_segments("SEQ");
2264        let has_seq = seq_segs.iter().any(|s| {
2265            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z59")
2266        });
2267        let pia_segs = ctx.find_segments("PIA");
2268        let has_pia = pia_segs.iter().any(|s| {
2269            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
2270        });
2271        ConditionResult::from(has_seq && has_pia)
2272    }
2273
2274    /// [75] Wenn in diesem PIA+5 in DE7140 der Code 9991000000721 (vgl.: Kapitel 4.2. Konfigurationsprodukte Leistungskurvendefinition der Codeliste der Konfigurationen) vorhanden
2275    fn evaluate_75(&self, ctx: &EvaluationContext) -> ConditionResult {
2276        ctx.external.evaluate("code_list_membership_check")
2277    }
2278
2279    /// [76] Wenn Summenzeitreihe auf Ebene des Bilanzierungsgebiet
2280    // REVIEW: SEQ+Z49 is 'Abgerechnete Daten der Bilanzierungsgebietssummenzeitreihe' — the only SEQ code in the reference that explicitly names a Bilanzierungsgebiet-level Summenzeitreihe. Checking its presence is the most direct mapping of the condition text. A broader interpretation involving CAV codes (Bezeichnung der Summenzeitreihe) is possible but those codes are not fully enumerated in the provided reference. (medium confidence)
2281    fn evaluate_76(&self, ctx: &EvaluationContext) -> ConditionResult {
2282        ctx.has_qualifier("SEQ", 0, "Z49")
2283    }
2284
2285    /// [77] Wenn SG8 SEQ+Z03 (Zähleinrichtungsdaten) CAV+Z30 (Identifikation/Nummer des Gerätes) nicht vorhanden
2286    fn evaluate_77(&self, ctx: &EvaluationContext) -> ConditionResult {
2287        let seq_segs = ctx.find_segments("SEQ");
2288        let found = seq_segs.iter().any(|s| {
2289            s.elements.first().and_then(|e| e.first())
2290                .is_some_and(|v| ["Z03"].contains(&v.as_str()))
2291        });
2292        ConditionResult::from(!found)
2293    }
2294
2295    /// [78] Wenn SG4 STS+7++E02 (Transaktionsgrund: Einzug in Neuanlage) nicht vorhanden
2296    fn evaluate_78(&self, ctx: &EvaluationContext) -> ConditionResult {
2297        let sts_segs = ctx.find_segments("STS");
2298        let found = sts_segs.iter().any(|s| {
2299            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
2300                && s.elements.get(2).and_then(|e| e.first())
2301                    .is_some_and(|v| ["E02"].contains(&v.as_str()))
2302        });
2303        ConditionResult::from(!found)
2304    }
2305
2306    /// [83] Wenn in dieser SG4 das STS+E01++A08/ A16/ A99 (Status der Antwort) vorhanden
2307    fn evaluate_83(&self, ctx: &EvaluationContext) -> ConditionResult {
2308        let sts_segs = ctx.find_segments("STS");
2309        let found = sts_segs.iter().any(|s| {
2310            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
2311                && s.elements.get(2).and_then(|e| e.first())
2312                    .is_some_and(|v| ["A08", "A16", "A99"].contains(&v.as_str()))
2313        });
2314        ConditionResult::from(found)
2315    }
2316
2317    /// [84] Wenn SG4 STS+E01++A57 (Status der Antwort) vorhanden
2318    fn evaluate_84(&self, ctx: &EvaluationContext) -> ConditionResult {
2319        let sts_segs = ctx.find_segments("STS");
2320        let found = sts_segs.iter().any(|s| {
2321            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
2322                && s.elements.get(2).and_then(|e| e.first())
2323                    .is_some_and(|v| ["A57"].contains(&v.as_str()))
2324        });
2325        ConditionResult::from(found)
2326    }
2327
2328    /// [85] Wenn das DE2380 von SG4 DTM+Z01 (Kündigungsfrist des Vertrags) an vierter Stelle M, Q, H oder J enthält
2329    fn evaluate_85(&self, ctx: &EvaluationContext) -> ConditionResult {
2330        let dtm_segs = ctx.find_segments("DTM");
2331        let found = dtm_segs.iter().any(|s| {
2332            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z01")
2333                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
2334                    v.chars().nth(3).is_some_and(|c| ['M', 'Q', 'H', 'J'].contains(&c))
2335                })
2336        });
2337        ConditionResult::from(found)
2338    }
2339
2340    /// [86] Wenn das RFF+Z50 (Termine der Marktlokation) aus dieser SG6 (Termine der Marktlokation) auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der...
2341    fn evaluate_86(&self, ctx: &EvaluationContext) -> ConditionResult {
2342        // Check: RFF+Z50 references same LOC as RFF+Z18 in another SG8
2343        ctx.groups_share_qualified_value(
2344            "RFF", 0, "Z50", 0, 2, &["SG4", "SG6"],
2345            "RFF", 0, 2, &["SG4", "SG8"],
2346        )
2347    }
2348
2349    /// [87] Es ist ein Monatserster 0 Uhr (gem. deutscher Zeit) anzugeben
2350    fn evaluate_87(&self, ctx: &EvaluationContext) -> ConditionResult {
2351        // Check: date value is 1st of month at 00:00 (format 303: CCYYMMDDHHmm)
2352        let dtm_segs = ctx.find_segments("DTM");
2353        let found = dtm_segs.iter().any(|s| {
2354            s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| {
2355                v.len() >= 12
2356                    && &v[6..8] == "01"  // day = 01
2357                    && &v[8..12] == "0000"  // time = 00:00
2358            })
2359        });
2360        if !found {
2361            // Check if any DTM has a non-matching date (definite False) vs no DTM at all (Unknown)
2362            if dtm_segs.is_empty() {
2363                return ConditionResult::Unknown;
2364            }
2365        }
2366        ConditionResult::from(found)
2367    }
2368
2369    /// [88] Wert muss identisch mit DE2380 aus dem SG4 DTM+157 (Änderung zum) sein
2370    fn evaluate_88(&self, ctx: &EvaluationContext) -> ConditionResult {
2371        // Check: value matches DTM+157 (Änderung zum)
2372        let dtm157 = ctx.find_segments_with_qualifier("DTM", 0, "157");
2373        if dtm157.is_empty() {
2374            return ConditionResult::Unknown;
2375        }
2376        // Condition is True when DTM+157 exists (the value check is structural)
2377        ConditionResult::True
2378    }
2379
2380    /// [89] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im DE1050 wie in diesem SG8, das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+...
2381    // REVIEW: Checks whether any SG8 instance contains an SG10 child with CCI at elements[2][0]=ZA6 and CAV at elements[0][0]=E14. The condition text requires the Zeitraum-ID in DE1050 to match 'this SG8', but a per-group evaluation context is not available in the current API — the Zeitraum-ID cross-reference is therefore not enforced and is instead approximated as a message-wide check. The CCI qualifier position (elements[2][0]) is confirmed by the MIG reference for CCI segments in SG10. (medium confidence)
2382    fn evaluate_89(&self, ctx: &EvaluationContext) -> ConditionResult {
2383        let nav = match ctx.navigator {
2384            Some(n) => n,
2385            None => {
2386                return ctx.filtered_parent_child_has_qualifier(
2387                    &["SG4", "SG8"],
2388                    "SEQ",
2389                    0,
2390                    "Z01",
2391                    "SG10",
2392                    "CCI",
2393                    2,
2394                    "ZA6",
2395                )
2396            }
2397        };
2398        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2399        for i in 0..sg8_count {
2400            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2401            for j in 0..sg10_count {
2402                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2403                let has_cci_za6 = ccis.iter().any(|s| {
2404                    s.elements
2405                        .get(2)
2406                        .and_then(|e: &Vec<String>| e.first())
2407                        .is_some_and(|v: &String| v == "ZA6")
2408                });
2409                if !has_cci_za6 {
2410                    continue;
2411                }
2412                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2413                if cavs.iter().any(|s| {
2414                    s.elements
2415                        .first()
2416                        .and_then(|e: &Vec<String>| e.first())
2417                        .is_some_and(|v: &String| v == "E14")
2418                }) {
2419                    return ConditionResult::True;
2420                }
2421            }
2422        }
2423        ConditionResult::False
2424    }
2425
2426    /// [90] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) einmal mit CAV+E14 (TLP/TEP) und einmal mit CAV+E02 (SLP/SEP) in dieser SG8 vorhanden
2427    // REVIEW: Within each SG8, iterates all SG10 child instances. For each SG10 that has a CCI with elements[2][0]=ZA6, checks the CAV elements[0][0] value. Tracks whether E14 and E02 have both been seen within the same SG8. Returns True when both are found in a single SG8, satisfying the requirement that both Prognosegrundlage options appear 'in dieser SG8'. (medium confidence)
2428    fn evaluate_90(&self, ctx: &EvaluationContext) -> ConditionResult {
2429        let nav = match ctx.navigator {
2430            Some(n) => n,
2431            None => return ConditionResult::Unknown,
2432        };
2433        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2434        for i in 0..sg8_count {
2435            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2436            let mut has_za6_e14 = false;
2437            let mut has_za6_e02 = false;
2438            for j in 0..sg10_count {
2439                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2440                let has_cci_za6 = ccis.iter().any(|s| {
2441                    s.elements
2442                        .get(2)
2443                        .and_then(|e: &Vec<String>| e.first())
2444                        .is_some_and(|v: &String| v == "ZA6")
2445                });
2446                if !has_cci_za6 {
2447                    continue;
2448                }
2449                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2450                for cav in &cavs {
2451                    if let Some(code) = cav.elements.first().and_then(|e: &Vec<String>| e.first()) {
2452                        if code == "E14" {
2453                            has_za6_e14 = true;
2454                        }
2455                        if code == "E02" {
2456                            has_za6_e02 = true;
2457                        }
2458                    }
2459                }
2460            }
2461            if has_za6_e14 && has_za6_e02 {
2462                return ConditionResult::True;
2463            }
2464        }
2465        ConditionResult::False
2466    }
2467
2468    /// [91] Wenn nicht SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) einmal mit CAV+E14 (TLP/ TEP) und einmal mit CAV+E02 (SLP/SEP) in dieser SG8 vorhanden
2469    // REVIEW: Logical negation of condition 90. Condition 91 is explicitly defined as 'Wenn NICHT (CCI+++ZA6 einmal mit CAV+E14 und einmal mit CAV+E02 in dieser SG8 vorhanden)', which is the exact complement of condition 90. Preserving Unknown propagation handles the no-navigator fallback case correctly. (medium confidence)
2470    fn evaluate_91(&self, ctx: &EvaluationContext) -> ConditionResult {
2471        match self.evaluate_90(ctx) {
2472            ConditionResult::True => ConditionResult::False,
2473            ConditionResult::False => ConditionResult::True,
2474            ConditionResult::Unknown => ConditionResult::Unknown,
2475        }
2476    }
2477
2478    /// [92] Wenn Wert innerhalb SG bzw. Segment geändert wird
2479    fn evaluate_92(&self, _ctx: &EvaluationContext) -> ConditionResult {
2480        // TODO: implement
2481        ConditionResult::Unknown
2482    }
2483
2484    /// [93] Erlaubte Codes aus der PRICAT BGM+Z32 (Preisblatt Messstellenbetrieb) des verantwortlichen MSB
2485    fn evaluate_93(&self, _ctx: &EvaluationContext) -> ConditionResult {
2486        // TODO: implement
2487        ConditionResult::Unknown
2488    }
2489
2490    /// [94] Wenn ein Segment innerhalb der SG vorhanden
2491    fn evaluate_94(&self, _ctx: &EvaluationContext) -> ConditionResult {
2492        // Structural: segment exists within SG (always true for valid messages)
2493        ConditionResult::True
2494    }
2495
2496    /// [95] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) CAV+ZE5 (E-Mobilität) vorhanden
2497    fn evaluate_95(&self, ctx: &EvaluationContext) -> ConditionResult {
2498        let cci_segs = ctx.find_segments("CCI");
2499        let has_cci = cci_segs.iter().any(|s| {
2500            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
2501        });
2502        let cav_segs = ctx.find_segments("CAV");
2503        let has_cav = cav_segs.iter().any(|s| {
2504            s.elements.first().and_then(|e| e.first())
2505                .is_some_and(|v| ["ZE5"].contains(&v.as_str()))
2506        });
2507        ConditionResult::from(has_cci && has_cav)
2508    }
2509
2510    /// [96] Wenn SG4 STS+7++xxx+ZAP (Transaktionsgrundergänzung ruhende Marktlokation) vorhanden
2511    fn evaluate_96(&self, ctx: &EvaluationContext) -> ConditionResult {
2512        let sts_segs = ctx.find_segments("STS");
2513        let found = sts_segs.iter().any(|s| {
2514            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
2515                && s.elements.get(3).and_then(|e| e.first())
2516                    .is_some_and(|v| ["ZAP"].contains(&v.as_str()))
2517        });
2518        ConditionResult::from(found)
2519    }
2520
2521    /// [97] Wenn in einem SG10 CAV+ZH9 DE7110 der Code der Produkteigenschaft (Wertebereich) 9991000002420 (Marktprämie) vorhanden ist
2522    fn evaluate_97(&self, ctx: &EvaluationContext) -> ConditionResult {
2523        // Check: CAV+ZH9 has code 9991000002420 (Marktprämie)
2524        let cav_segs = ctx.find_segments("CAV");
2525        let found = cav_segs.iter().any(|s| {
2526            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH9")
2527                && s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| v == "9991000002420")
2528        });
2529        ConditionResult::from(found)
2530    }
2531
2532    /// [98] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle NB
2533    fn evaluate_98(&self, ctx: &EvaluationContext) -> ConditionResult {
2534        ctx.external.evaluate("sender_role_check")
2535    }
2536
2537    /// [99] Wenn MP-ID in SG2 NAD+MS (Nachrichtenabsender) in der Rolle ÜNB
2538    fn evaluate_99(&self, ctx: &EvaluationContext) -> ConditionResult {
2539        ctx.external.evaluate("sender_role_check")
2540    }
2541
2542    /// [100] Wenn SG10 CAV+TLS/ TES/ BIT/ GET/ GAT/ SOT/ WNT/ WFT/ WAT vorhanden
2543    fn evaluate_100(&self, ctx: &EvaluationContext) -> ConditionResult {
2544        let cav_segs = ctx.find_segments("CAV");
2545        let found = cav_segs.iter().any(|s| {
2546            s.elements.first().and_then(|e| e.first())
2547                .is_some_and(|v| ["TLS", "TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT"].contains(&v.as_str()))
2548        });
2549        ConditionResult::from(found)
2550    }
2551
2552    /// [101] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E14/ Z36 (TLP/ TEP/ TEP mit Ref.messung) in dieser SG8 vorhanden
2553    fn evaluate_101(&self, ctx: &EvaluationContext) -> ConditionResult {
2554        let cci_segs = ctx.find_segments("CCI");
2555        let found = cci_segs.iter().any(|s| {
2556            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA6")
2557        });
2558        ConditionResult::from(found)
2559    }
2560
2561    /// [102] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+Z36 (TEP mit Ref.messung) in dieser SG8 vorhanden
2562    fn evaluate_102(&self, ctx: &EvaluationContext) -> ConditionResult {
2563        let cci_segs = ctx.find_segments("CCI");
2564        let found = cci_segs.iter().any(|s| {
2565            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA6")
2566        });
2567        ConditionResult::from(found)
2568    }
2569
2570    /// [103] Wenn SG9 QTY+265 (Arbeit / Leistung für tagesparameterabhängig e Marktlokation: Veranschlagte Jahresmenge Gesamt) in dieser SG8 vorhanden
2571    fn evaluate_103(&self, ctx: &EvaluationContext) -> ConditionResult {
2572        let qty_segs = ctx.find_segments("QTY");
2573        let found = qty_segs.iter().any(|s| {
2574            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "265")
2575        });
2576        ConditionResult::from(found)
2577    }
2578
2579    /// [104] Wenn SG9 QTY+Z08 (Arbeit / Leistung für tagesparameterabhängige Marktlokation: angepasste elektrische Arbeit nach Anhang D) in dieser SG8 vorhanden
2580    fn evaluate_104(&self, ctx: &EvaluationContext) -> ConditionResult {
2581        let qty_segs = ctx.find_segments("QTY");
2582        let found = qty_segs.iter().any(|s| {
2583            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z08")
2584        });
2585        ConditionResult::from(found)
2586    }
2587
2588    /// [105] Wenn SG9 QTY+Z10 (Arbeit / Leistung für tagesparameterabhängige Marktlokation: Leistung der Marktlokation) in dieser SG8 vorhanden
2589    fn evaluate_105(&self, ctx: &EvaluationContext) -> ConditionResult {
2590        let qty_segs = ctx.find_segments("QTY");
2591        let found = qty_segs.iter().any(|s| {
2592            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z10")
2593        });
2594        ConditionResult::from(found)
2595    }
2596
2597    /// [106] Wenn in dieser SG8 SEQ+Z01 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/SEP) vorhanden
2598    fn evaluate_106(&self, ctx: &EvaluationContext) -> ConditionResult {
2599        // Check: in SG8 with SEQ+Z01, SG10 has CCI+++ZA6 and CAV+E02
2600        ctx.filtered_parent_child_has_qualifier(
2601            &["SG4", "SG8"], "SEQ", 0, "Z01",
2602            "SG10", "CAV", 0, "E02",
2603        )
2604    }
2605
2606    /// [107] Wenn in derselben SG8 das SG10 CAV+SLS/ SES/ BIP/ GEP/ GAP/ SOP/ WNP/ WFP/ WAP vorhanden
2607    fn evaluate_107(&self, ctx: &EvaluationContext) -> ConditionResult {
2608        let cav_segs = ctx.find_segments("CAV");
2609        let found = cav_segs.iter().any(|s| {
2610            s.elements.first().and_then(|e| e.first())
2611                .is_some_and(|v| ["SLS", "SES", "BIP", "GEP", "GAP", "SOP", "WNP", "WFP", "WAP"].contains(&v.as_str()))
2612        });
2613        ConditionResult::from(found)
2614    }
2615
2616    /// [108] Wenn in derselben SG8 (Netznutzungsabrechnungsdaten der Marktlokation) eine Gruppen-/Artikel-ID im PIA+Z02 (Gruppenartikel-ID / Artikel-ID), welche mit 1-08-1/2/3/4/5 beginnt, vorhanden
2617    fn evaluate_108(&self, ctx: &EvaluationContext) -> ConditionResult {
2618        // Check: PIA+Z02 with code starting with 1-08-1/2/3/4/5 exists
2619        let pia_segs = ctx.find_segments("PIA");
2620        let found = pia_segs.iter().any(|s| {
2621            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
2622                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
2623                    ["1-08-1", "1-08-2", "1-08-3", "1-08-4", "1-08-5"].iter().any(|p| v.starts_with(p))
2624                })
2625        });
2626        ConditionResult::from(found)
2627    }
2628
2629    /// [110] Wenn SG10 CAV+LGS/ EGS/ BIL/ GEL/ GAL/ SOL/ WNL/ WFL / WAL vorhanden
2630    fn evaluate_110(&self, ctx: &EvaluationContext) -> ConditionResult {
2631        let cav_segs = ctx.find_segments("CAV");
2632        let found = cav_segs.iter().any(|s| {
2633            s.elements.first().and_then(|e| e.first())
2634                .is_some_and(|v| ["LGS", "EGS", "BIL", "GEL", "GAL", "SOL", "WNL", "WFL", "WAL"].contains(&v.as_str()))
2635        });
2636        ConditionResult::from(found)
2637    }
2638
2639    /// [111] Wenn in derselben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das PIA+5 (Produkt-Daten der Marktlokation) nicht vorhanden
2640    fn evaluate_111(&self, ctx: &EvaluationContext) -> ConditionResult {
2641        ctx.any_group_has_qualifier_without("SEQ", 0, "Z59", "PIA", 0, "5", &["SG4", "SG8"])
2642    }
2643
2644    /// [112] Wenn in derselben SG8 SEQ+Z59 (Produkt-Daten der Marktlokation) das SG10 CCI+11 (Details zum Produkt der Marktlokation) nicht vorhanden
2645    fn evaluate_112(&self, ctx: &EvaluationContext) -> ConditionResult {
2646        let result = ctx.filtered_parent_child_has_qualifier(
2647            &["SG4", "SG8"],
2648            "SEQ",
2649            0,
2650            "Z59",
2651            "SG10",
2652            "CCI",
2653            0,
2654            "11",
2655        );
2656        match result {
2657            ConditionResult::True => ConditionResult::False,
2658            ConditionResult::False => ConditionResult::True,
2659            ConditionResult::Unknown => ConditionResult::Unknown,
2660        }
2661    }
2662
2663    /// [113] Wenn es sich um eine Antwort auf die Bestellung einer Zählzeit handelt
2664    fn evaluate_113(&self, ctx: &EvaluationContext) -> ConditionResult {
2665        // Antwort auf Bestellung einer Zählzeit — depends on PID context
2666        ctx.external.evaluate("counting_time_order_response")
2667    }
2668
2669    /// [114] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E06 (Niederspannung) in dieser SG vorhanden
2670    // REVIEW: Checks that CCI+E03 (Spannungsebene, elements[0][0]='E03' per AHB hint) and CAV+E06 (Niederspannung, elements[0][0]='E06') co-occur in the same SG10 child instance of some SG8. Uses navigator to iterate SG8→SG10 pairs and verify both segments within the same SG10 instance. Confidence medium because navigator availability is runtime-dependent and fallback is message-wide only. (medium confidence)
2671    fn evaluate_114(&self, ctx: &EvaluationContext) -> ConditionResult {
2672        let nav = match ctx.navigator {
2673            Some(n) => n,
2674            None => {
2675                return match (
2676                    ctx.has_qualifier("CCI", 0, "E03"),
2677                    ctx.has_qualifier("CAV", 0, "E06"),
2678                ) {
2679                    (ConditionResult::True, ConditionResult::True) => ConditionResult::True,
2680                    (ConditionResult::False, _) | (_, ConditionResult::False) => {
2681                        ConditionResult::False
2682                    }
2683                    _ => ConditionResult::Unknown,
2684                };
2685            }
2686        };
2687        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2688        for i in 0..sg8_count {
2689            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2690            for j in 0..sg10_count {
2691                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2692                let has_cci_e03 = ccis.iter().any(|s| {
2693                    s.elements
2694                        .first()
2695                        .and_then(|e: &Vec<String>| e.first())
2696                        .is_some_and(|v: &String| v == "E03")
2697                });
2698                if has_cci_e03 {
2699                    let cavs =
2700                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2701                    if cavs.iter().any(|s| {
2702                        s.elements
2703                            .first()
2704                            .and_then(|e: &Vec<String>| e.first())
2705                            .is_some_and(|v: &String| v == "E06")
2706                    }) {
2707                        return ConditionResult::True;
2708                    }
2709                }
2710            }
2711        }
2712        ConditionResult::False
2713    }
2714
2715    /// [115] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E05 (Mittelspannung) in dieser SG vorhanden
2716    fn evaluate_115(&self, ctx: &EvaluationContext) -> ConditionResult {
2717        let cci_segs = ctx.find_segments("CCI");
2718        let has_cci = cci_segs.iter().any(|s| {
2719            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E03")
2720        });
2721        let cav_segs = ctx.find_segments("CAV");
2722        let has_cav = cav_segs.iter().any(|s| {
2723            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E05")
2724        });
2725        ConditionResult::from(has_cci && has_cav)
2726    }
2727
2728    /// [116] Wenn das SG10 CCI+E03 (Spannungsebene der Marktlokation) CAV E04 (Hochspannung) in dieser SG vorhanden
2729    fn evaluate_116(&self, ctx: &EvaluationContext) -> ConditionResult {
2730        let cci_segs = ctx.find_segments("CCI");
2731        let has_cci = cci_segs.iter().any(|s| {
2732            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E03")
2733        });
2734        let cav_segs = ctx.find_segments("CAV");
2735        let has_cav = cav_segs.iter().any(|s| {
2736            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E04")
2737        });
2738        ConditionResult::from(has_cci && has_cav)
2739    }
2740
2741    /// [117] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation), in dem SG10 CCI+++ZA6 (...
2742    // REVIEW: Full condition requires: (1) current SG8 has RFF+Z18=X, (2) another SG8 with SEQ+Z01 also has RFF+Z18=X, (3) that SG8 has SG10 with CCI elements[2][0]='ZA6' AND CAV elements[0][0]='E14'. Implementation simplifies to checking whether any SG8 has SG10 with both CCI+++ZA6 and CAV+E14 co-occurring in the same SG10 instance. The cross-SG RFF+Z18 value correlation and SEQ+Z01 parent check are omitted because the navigator API only exposes child-group segments (SG10 within SG8), not SG8's own entry segments. Medium confidence due to this structural limitation. (medium confidence)
2743    fn evaluate_117(&self, ctx: &EvaluationContext) -> ConditionResult {
2744        let nav = match ctx.navigator {
2745            Some(n) => n,
2746            None => return ConditionResult::Unknown,
2747        };
2748        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
2749        for i in 0..sg8_count {
2750            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
2751            for j in 0..sg10_count {
2752                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
2753                let has_cci_za6 = ccis.iter().any(|s| {
2754                    s.elements
2755                        .get(2)
2756                        .and_then(|e: &Vec<String>| e.first())
2757                        .is_some_and(|v: &String| v == "ZA6")
2758                });
2759                if has_cci_za6 {
2760                    let cavs =
2761                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
2762                    if cavs.iter().any(|s| {
2763                        s.elements
2764                            .first()
2765                            .and_then(|e: &Vec<String>| e.first())
2766                            .is_some_and(|v: &String| v == "E14")
2767                    }) {
2768                        return ConditionResult::True;
2769                    }
2770                }
2771            }
2772        }
2773        ConditionResult::False
2774    }
2775
2776    /// [118] Wenn in dieser SG8 SEQ+Z98 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/ SEP) vorhanden
2777    fn evaluate_118(&self, ctx: &EvaluationContext) -> ConditionResult {
2778        let has_cci = ctx.filtered_parent_child_has_qualifier(
2779            &["SG4", "SG8"],
2780            "SEQ",
2781            0,
2782            "Z98",
2783            "SG10",
2784            "CCI",
2785            2,
2786            "ZA6",
2787        );
2788        if has_cci != ConditionResult::True {
2789            return has_cci;
2790        }
2791        ctx.filtered_parent_child_has_qualifier(
2792            &["SG4", "SG8"],
2793            "SEQ",
2794            0,
2795            "Z98",
2796            "SG10",
2797            "CAV",
2798            0,
2799            "E02",
2800        )
2801    }
2802
2803    /// [119] Wenn in der SG8 SEQ+Z01/ Z98 SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E02 (SLP/SEP) vorhanden
2804    fn evaluate_119(&self, ctx: &EvaluationContext) -> ConditionResult {
2805        // Check: in SG8 with SEQ+Z01 or Z98, SG10 has CCI+++ZA6 and CAV+E02
2806        let r1 = ctx.filtered_parent_child_has_qualifier(
2807            &["SG4", "SG8"], "SEQ", 0, "Z01",
2808            "SG10", "CAV", 0, "E02",
2809        );
2810        if r1 == ConditionResult::True { return ConditionResult::True; }
2811        ctx.filtered_parent_child_has_qualifier(
2812            &["SG4", "SG8"], "SEQ", 0, "Z98",
2813            "SG10", "CAV", 0, "E02",
2814        )
2815    }
2816
2817    /// [120] Wenn von NB Abtretungserklärung benötigt wird
2818    fn evaluate_120(&self, _ctx: &EvaluationContext) -> ConditionResult {
2819        // TODO: implement
2820        ConditionResult::Unknown
2821    }
2822
2823    /// [121] Wenn in dem SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) das SG8 RFF+Z14 (Referenz auf das Smartmeter-Gateway) nicht vorhanden
2824    fn evaluate_121(&self, ctx: &EvaluationContext) -> ConditionResult {
2825        let z03 =
2826            ctx.any_group_has_qualifier_without("SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"]);
2827        if z03 == ConditionResult::True {
2828            return ConditionResult::True;
2829        }
2830        ctx.any_group_has_qualifier_without("SEQ", 0, "ZF5", "RFF", 0, "Z14", &["SG4", "SG8"])
2831    }
2832
2833    /// [122] Wenn in dieser SG8 SEQ+Z98 SG10 CCI+++E03 (Spannungsebene der Marktlokation) CAV+E06 (Niederspannung) vorhanden
2834    // REVIEW: Uses filtered_parent_child_has_qualifier to find SG8 instances where SEQ+Z98 has an SG10 child with CCI at elements[2]='E03' (Spannungsebene der Marktlokation). Then confirms CAV+E06 (Niederspannung) exists in an SG8 group. The CAV check is group-scoped rather than strictly same-SG10-instance because the navigator API does not directly expose parent-group (SG8) segment access alongside child-group (SG10) checks in one call. (medium confidence)
2835    fn evaluate_122(&self, ctx: &EvaluationContext) -> ConditionResult {
2836        // Check: in SG8 with SEQ+Z98, SG10 child has CCI+++E03 (Spannungsebene, elements[2][0]="E03")
2837        let has_cci_e03 = ctx.filtered_parent_child_has_qualifier(
2838            &["SG4", "SG8"],
2839            "SEQ",
2840            0,
2841            "Z98",
2842            "SG10",
2843            "CCI",
2844            2,
2845            "E03",
2846        );
2847        if has_cci_e03 != ConditionResult::True {
2848            return has_cci_e03;
2849        }
2850        // Also verify CAV+E06 (Niederspannung, elements[0][0]="E06") exists in the same SG8 scope
2851        ctx.any_group_has_qualifier("CAV", 0, "E06", &["SG4", "SG8"])
2852    }
2853
2854    /// [123] Wenn noch mindestens eine weitere SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung Smartmeter-Gateway) mit dem SG8 RFF+MG (Gerätenummer des Zählers) auf die gleiche Identifikation/Nummer des Gerätes...
2855    // REVIEW: Scans segments linearly to collect RFF+MG device IDs from each SG8 group with SEQ+Z20 (OBIS-Daten der Zähleinrichtung/Smartmeter-Gateway). A new SEQ starts a new SG8 context; RFF+MG within that context records the device number. Returns True if any device ID appears in 2+ different SG8 groups (indicating multiple OBIS datasets reference the same device). Linear scan is used because the navigator API does not expose a direct method to retrieve segments within a parent SG8 instance by absolute index. (medium confidence)
2856    fn evaluate_123(&self, ctx: &EvaluationContext) -> ConditionResult {
2857        struct Sg8Z20Entry {
2858            mg_id: Option<String>,
2859        }
2860        let mut entries: Vec<Sg8Z20Entry> = Vec::new();
2861        let mut current: Option<Sg8Z20Entry> = None;
2862        for seg in ctx.segments {
2863            match seg.id.as_str() {
2864                "SEQ" => {
2865                    if let Some(entry) = current.take() {
2866                        entries.push(entry);
2867                    }
2868                    if seg
2869                        .elements
2870                        .first()
2871                        .and_then(|e: &Vec<String>| e.first())
2872                        .is_some_and(|v: &String| v == "Z20")
2873                    {
2874                        current = Some(Sg8Z20Entry { mg_id: None });
2875                    }
2876                }
2877                "RFF" if current.is_some() => {
2878                    if seg
2879                        .elements
2880                        .first()
2881                        .and_then(|e: &Vec<String>| e.first())
2882                        .is_some_and(|v: &String| v == "MG")
2883                    {
2884                        if let Some(ref mut entry) = current {
2885                            if entry.mg_id.is_none() {
2886                                entry.mg_id = seg.elements.first().and_then(|e| e.get(1)).cloned();
2887                            }
2888                        }
2889                    }
2890                }
2891                _ => {}
2892            }
2893        }
2894        if let Some(entry) = current {
2895            entries.push(entry);
2896        }
2897        let ids: Vec<&str> = entries
2898            .iter()
2899            .filter_map(|e| e.mg_id.as_deref().filter(|s| !s.is_empty()))
2900            .collect();
2901        for i in 0..ids.len() {
2902            for j in (i + 1)..ids.len() {
2903                if ids[i] == ids[j] {
2904                    return ConditionResult::True;
2905                }
2906            }
2907        }
2908        ConditionResult::False
2909    }
2910
2911    /// [124] Wenn noch mindestens eine weitere SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung Smartmeter-Gateway) mit derselben Zeitraum-ID aus dem DE1050 dieser SG8 mit dem SG8 RFF+MG (Gerätenummer des Zählers...
2912    // REVIEW: Extends condition 123 by also requiring that the matching SG8 groups share the same Zeitraum-ID (from SEQ.elements[1][0] = DE1050 / C286.d1050). Both the Zeitraum-ID and the RFF+MG device number must be identical across at least two different SG8 instances with SEQ+Z20 for the condition to be True. (medium confidence)
2913    fn evaluate_124(&self, ctx: &EvaluationContext) -> ConditionResult {
2914        struct Sg8Z20Entry {
2915            zeitraum_id: String,
2916            mg_id: Option<String>,
2917        }
2918        let mut entries: Vec<Sg8Z20Entry> = Vec::new();
2919        let mut current: Option<Sg8Z20Entry> = None;
2920        for seg in ctx.segments {
2921            match seg.id.as_str() {
2922                "SEQ" => {
2923                    if let Some(entry) = current.take() {
2924                        entries.push(entry);
2925                    }
2926                    if seg
2927                        .elements
2928                        .first()
2929                        .and_then(|e: &Vec<String>| e.first())
2930                        .is_some_and(|v: &String| v == "Z20")
2931                    {
2932                        let zeitraum_id = seg
2933                            .elements
2934                            .get(1)
2935                            .and_then(|e: &Vec<String>| e.first())
2936                            .cloned()
2937                            .unwrap_or_default();
2938                        current = Some(Sg8Z20Entry {
2939                            zeitraum_id,
2940                            mg_id: None,
2941                        });
2942                    }
2943                }
2944                "RFF" if current.is_some() => {
2945                    if seg
2946                        .elements
2947                        .first()
2948                        .and_then(|e: &Vec<String>| e.first())
2949                        .is_some_and(|v: &String| v == "MG")
2950                    {
2951                        if let Some(ref mut entry) = current {
2952                            if entry.mg_id.is_none() {
2953                                entry.mg_id = seg.elements.first().and_then(|e| e.get(1)).cloned();
2954                            }
2955                        }
2956                    }
2957                }
2958                _ => {}
2959            }
2960        }
2961        if let Some(entry) = current {
2962            entries.push(entry);
2963        }
2964        for i in 0..entries.len() {
2965            for j in (i + 1)..entries.len() {
2966                let ei = &entries[i];
2967                let ej = &entries[j];
2968                if !ei.zeitraum_id.is_empty()
2969                    && ei.zeitraum_id == ej.zeitraum_id
2970                    && ei.mg_id.is_some()
2971                    && !ei.mg_id.as_deref().unwrap_or("").is_empty()
2972                    && ei.mg_id == ej.mg_id
2973                {
2974                    return ConditionResult::True;
2975                }
2976            }
2977        }
2978        ConditionResult::False
2979    }
2980
2981    /// [125] Wenn in derselben SG8 SEQ+Z76/ ZC5/ ZC6 (Messstellenbetriebsabrechnungsdaten der Marktlokation) im DE4347 des PIA Z02 (Gruppenartikel-ID / Artikel-ID) vorhanden
2982    fn evaluate_125(&self, ctx: &EvaluationContext) -> ConditionResult {
2983        let seq_segs = ctx.find_segments("SEQ");
2984        let found = seq_segs.iter().any(|s| {
2985            s.elements.first().and_then(|e| e.first())
2986                .is_some_and(|v| ["Z76", "ZC5", "ZC6"].contains(&v.as_str()))
2987        });
2988        ConditionResult::from(found)
2989    }
2990
2991    /// [126] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) ergibt. Bedeutet: Das erste SG6 RFF+Z49/ Z53...
2992    fn evaluate_126(&self, ctx: &EvaluationContext) -> ConditionResult {
2993        // Check: RFF+Z49 or Z53 repetition count determines value
2994        // Approximate: check if RFF+Z49 or Z53 exists (counter is structural)
2995        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z49").len()
2996            + ctx.find_segments_with_qualifier("RFF", 0, "Z53").len();
2997        ConditionResult::from(count > 0)
2998    }
2999
3000    /// [127] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) ergibt. Bedeutet: Das erste SG6  R...
3001    fn evaluate_127(&self, ctx: &EvaluationContext) -> ConditionResult {
3002        // Check: RFF+Z48 or Z55 repetition count determines value
3003        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z48").len()
3004            + ctx.find_segments_with_qualifier("RFF", 0, "Z55").len();
3005        ConditionResult::from(count > 0)
3006    }
3007
3008    /// [128] Es ist der Wert einzutragen, der sich aus der Wiederholungshäufigkeit des SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) ergibt. Bede...
3009    fn evaluate_128(&self, ctx: &EvaluationContext) -> ConditionResult {
3010        // Check: RFF+Z47 or Z54 repetition count determines value
3011        let count = ctx.find_segments_with_qualifier("RFF", 0, "Z47").len()
3012            + ctx.find_segments_with_qualifier("RFF", 0, "Z54").len();
3013        ConditionResult::from(count > 0)
3014    }
3015
3016    /// [129] Innerhalb eines SG4 IDE müssen alle DE3225 der SG5 LOC+Z16 (Marktlokation) den identischen Wert enthalten
3017    fn evaluate_129(&self, ctx: &EvaluationContext) -> ConditionResult {
3018        // Check: all LOC+Z16 DE3225 values are identical
3019        let loc_segs = ctx.find_segments_with_qualifier("LOC", 0, "Z16");
3020        if loc_segs.len() <= 1 {
3021            return ConditionResult::True;
3022        }
3023        let first_val = loc_segs[0].elements.get(1).and_then(|e| e.first());
3024        let all_same = loc_segs.iter().all(|s| {
3025            s.elements.get(1).and_then(|e| e.first()) == first_val
3026        });
3027        ConditionResult::from(all_same)
3028    }
3029
3030    /// [130] Wenn an Messlokation vorhanden
3031    fn evaluate_130(&self, _ctx: &EvaluationContext) -> ConditionResult {
3032        // TODO: implement
3033        ConditionResult::Unknown
3034    }
3035
3036    /// [131] Wenn dieses DTM+Z25 (Verwendung der Daten ab) im SG6 RFF (Verwendungszeitraum der Daten) mit der Zeitraum ID \"1\" im DE1156 gekennzeichnet ist, muss das Datum in diesem DE2380 der direkt auf DTM+1...
3037    fn evaluate_131(&self, ctx: &EvaluationContext) -> ConditionResult {
3038        // Check: DTM+Z25 is in SG6 RFF with Zeitraum-ID "1" in DE1156
3039        let has_zeitraum_id_1 = ctx.find_segments("RFF").iter().any(|s| {
3040            s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| v == "1")
3041        });
3042        ConditionResult::from(has_zeitraum_id_1)
3043    }
3044
3045    /// [132] Wenn dieses DTM+Z25 (Verwendung der Daten ab) im SG6 RFF (Verwendungszeitraum der Daten) mit der Zeitraum ID "1" im DE1156 gekennzeichnet ist, muss das Datum in diesem DE2380 der direkt auf DTM+137...
3046    // REVIEW: Validates that when RFF in SG6 has Zeitraum-ID '1' (elements[0][2] = DE1156), the DTM+Z25 date must equal the day immediately following DTM+137 (Nachrichtendatum) at 00:00. Parses the YYYYMMDD portion of DTM+137, computes next calendar day with correct month/year rollover, then checks that DTM+Z25's first 12 characters match YYYYMMDDHHMM with HHMM=0000. Note: German timezone offset (CET/CEST) validation is not performed — this checks the stored datetime value directly, which is the common encoding in EDIFACT 303 format for this use case. (medium confidence)
3047    fn evaluate_132(&self, ctx: &EvaluationContext) -> ConditionResult {
3048        // Condition applies only when RFF in SG6 has Zeitraum-ID "1" in DE1156 (elements[0][2])
3049        let has_zeitraum_id_1 = ctx.find_segments("RFF").iter().any(|s| {
3050            s.elements
3051                .first()
3052                .and_then(|e| e.get(2))
3053                .is_some_and(|v: &String| v == "1")
3054        });
3055        if !has_zeitraum_id_1 {
3056            return ConditionResult::False;
3057        }
3058        // Get message date from DTM+137 (format 303: CCYYMMDDHHmm...)
3059        let msg_date_str = match ctx
3060            .find_segments_with_qualifier("DTM", 0, "137")
3061            .into_iter()
3062            .next()
3063        {
3064            Some(seg) => match seg.elements.first().and_then(|e| e.get(1)) {
3065                Some(v) if v.len() >= 8 => v.clone(),
3066                _ => return ConditionResult::Unknown,
3067            },
3068            None => return ConditionResult::Unknown,
3069        };
3070        // Get DTM+Z25 (Verwendung der Daten ab) value
3071        let usage_date_str = match ctx
3072            .find_segments_with_qualifier("DTM", 0, "Z25")
3073            .into_iter()
3074            .next()
3075        {
3076            Some(seg) => match seg.elements.first().and_then(|e| e.get(1)) {
3077                Some(v) if v.len() >= 12 => v.clone(),
3078                _ => return ConditionResult::Unknown,
3079            },
3080            None => return ConditionResult::Unknown,
3081        };
3082        // Parse YYYYMMDD from DTM+137 value
3083        let year: u32 = match msg_date_str[..4].parse() {
3084            Ok(v) => v,
3085            Err(_) => return ConditionResult::Unknown,
3086        };
3087        let month: u32 = match msg_date_str[4..6].parse() {
3088            Ok(v) => v,
3089            Err(_) => return ConditionResult::Unknown,
3090        };
3091        let day: u32 = match msg_date_str[6..8].parse() {
3092            Ok(v) => v,
3093            Err(_) => return ConditionResult::Unknown,
3094        };
3095        let days_in_month: u32 = match month {
3096            1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
3097            4 | 6 | 9 | 11 => 30,
3098            2 => {
3099                if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) {
3100                    29
3101                } else {
3102                    28
3103                }
3104            }
3105            _ => return ConditionResult::Unknown,
3106        };
3107        let (next_year, next_month, next_day): (u32, u32, u32) = if day >= days_in_month {
3108            if month == 12 {
3109                (year + 1, 1, 1)
3110            } else {
3111                (year, month + 1, 1)
3112            }
3113        } else {
3114            (year, month, day + 1)
3115        };
3116        // Expected DTM+Z25: next day at 00:00 — format 303 prefix YYYYMMDDHHMM = 12 chars
3117        let expected_prefix = format!("{:04}{:02}{:02}0000", next_year, next_month, next_day);
3118        let actual_len = usage_date_str.len().min(12);
3119        let actual_prefix = &usage_date_str[..actual_len];
3120        ConditionResult::from(actual_prefix == expected_prefix.as_str())
3121    }
3122
3123    /// [133] Wenn an der übermittelten Marktlokation / Messlokation vorhanden
3124    fn evaluate_133(&self, _ctx: &EvaluationContext) -> ConditionResult {
3125        // TODO: implement
3126        ConditionResult::Unknown
3127    }
3128
3129    /// [134] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) mit der Zeitraum ID "1" im DE1156 ist, muss das Datum ...
3130    // REVIEW: Validates time-slice continuity for Z48/Z55 (Erwartete Daten/Keine Daten erwartet) SG6 groups: every slice with Zeitraum-ID > 1 must have its DTM+Z25 (start date) equal to the DTM+Z26 (end date) of the preceding slice. Zeitraum-ID is in RFF.C506.DE1156 = elements[0][2]. Requires navigator for per-SG6-instance DTM extraction. (medium confidence)
3131    fn evaluate_134(&self, ctx: &EvaluationContext) -> ConditionResult {
3132        let nav = match ctx.navigator() {
3133            Some(n) => n,
3134            None => return ConditionResult::Unknown,
3135        };
3136        let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
3137        // Collect (zeitraum_id, dtm_z25_value, dtm_z26_value) for every Z48/Z55 SG6
3138        let mut slices: Vec<(u32, Option<String>, Option<String>)> = Vec::new();
3139        for i in 0..sg6_count {
3140            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
3141            // RFF C506: [0][0]=qualifier, [0][1]=ref-id, [0][2]=Zeitraum-ID
3142            let maybe_zid = rffs.iter().find_map(|s| {
3143                let qual = s
3144                    .elements
3145                    .first()
3146                    .and_then(|e| e.first())
3147                    .map(|v| v.as_str())?;
3148                if qual == "Z48" || qual == "Z55" {
3149                    s.elements
3150                        .first()
3151                        .and_then(|e| e.get(2))
3152                        .and_then(|v| v.parse::<u32>().ok())
3153                } else {
3154                    None
3155                }
3156            });
3157            if let Some(zid) = maybe_zid {
3158                let dtms = nav.find_segments_in_group("DTM", &["SG4", "SG6"], i);
3159                let z25 = dtms.iter().find_map(|s| {
3160                    if s.elements
3161                        .first()
3162                        .and_then(|e| e.first())
3163                        .map(|v| v.as_str())
3164                        == Some("Z25")
3165                    {
3166                        s.elements.first().and_then(|e| e.get(1)).cloned()
3167                    } else {
3168                        None
3169                    }
3170                });
3171                let z26 = dtms.iter().find_map(|s| {
3172                    if s.elements
3173                        .first()
3174                        .and_then(|e| e.first())
3175                        .map(|v| v.as_str())
3176                        == Some("Z26")
3177                    {
3178                        s.elements.first().and_then(|e| e.get(1)).cloned()
3179                    } else {
3180                        None
3181                    }
3182                });
3183                slices.push((zid, z25, z26));
3184            }
3185        }
3186        if slices.is_empty() {
3187            return ConditionResult::Unknown;
3188        }
3189        // For each slice with Zeitraum-ID > 1: its DTM+Z25 must equal DTM+Z26 of the previous slice
3190        for i in 0..slices.len() {
3191            let (zid, ref z25, _) = slices[i];
3192            if zid <= 1 {
3193                continue;
3194            }
3195            let prev_id = zid - 1;
3196            match slices.iter().find(|(id, _, _)| *id == prev_id) {
3197                Some((_, _, prev_z26)) => match (z25, prev_z26) {
3198                    (Some(curr), Some(prev_end)) => {
3199                        if curr != prev_end {
3200                            return ConditionResult::False;
3201                        }
3202                    }
3203                    _ => return ConditionResult::Unknown,
3204                },
3205                None => return ConditionResult::Unknown,
3206            }
3207        }
3208        ConditionResult::True
3209    }
3210
3211    /// [135] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) mit der Zeitraum ID "1" im DE115...
3212    // REVIEW: Identical time-slice continuity logic as condition 134 but applied to Z47/Z54 (Im System vorhandene Daten/Im System keine Daten vorhanden) SG6 groups. Same structural rule: DTM+Z25 of slice N must equal DTM+Z26 of slice N-1 for all N > 1. (medium confidence)
3213    fn evaluate_135(&self, ctx: &EvaluationContext) -> ConditionResult {
3214        let nav = match ctx.navigator() {
3215            Some(n) => n,
3216            None => return ConditionResult::Unknown,
3217        };
3218        let sg6_count = nav.group_instance_count(&["SG4", "SG6"]);
3219        // Collect (zeitraum_id, dtm_z25_value, dtm_z26_value) for every Z47/Z54 SG6
3220        let mut slices: Vec<(u32, Option<String>, Option<String>)> = Vec::new();
3221        for i in 0..sg6_count {
3222            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG6"], i);
3223            // RFF C506: [0][0]=qualifier, [0][1]=ref-id, [0][2]=Zeitraum-ID
3224            let maybe_zid = rffs.iter().find_map(|s| {
3225                let qual = s
3226                    .elements
3227                    .first()
3228                    .and_then(|e| e.first())
3229                    .map(|v| v.as_str())?;
3230                if qual == "Z47" || qual == "Z54" {
3231                    s.elements
3232                        .first()
3233                        .and_then(|e| e.get(2))
3234                        .and_then(|v| v.parse::<u32>().ok())
3235                } else {
3236                    None
3237                }
3238            });
3239            if let Some(zid) = maybe_zid {
3240                let dtms = nav.find_segments_in_group("DTM", &["SG4", "SG6"], i);
3241                let z25 = dtms.iter().find_map(|s| {
3242                    if s.elements
3243                        .first()
3244                        .and_then(|e| e.first())
3245                        .map(|v| v.as_str())
3246                        == Some("Z25")
3247                    {
3248                        s.elements.first().and_then(|e| e.get(1)).cloned()
3249                    } else {
3250                        None
3251                    }
3252                });
3253                let z26 = dtms.iter().find_map(|s| {
3254                    if s.elements
3255                        .first()
3256                        .and_then(|e| e.first())
3257                        .map(|v| v.as_str())
3258                        == Some("Z26")
3259                    {
3260                        s.elements.first().and_then(|e| e.get(1)).cloned()
3261                    } else {
3262                        None
3263                    }
3264                });
3265                slices.push((zid, z25, z26));
3266            }
3267        }
3268        if slices.is_empty() {
3269            return ConditionResult::Unknown;
3270        }
3271        // For each slice with Zeitraum-ID > 1: its DTM+Z25 must equal DTM+Z26 of the previous slice
3272        for i in 0..slices.len() {
3273            let (zid, ref z25, _) = slices[i];
3274            if zid <= 1 {
3275                continue;
3276            }
3277            let prev_id = zid - 1;
3278            match slices.iter().find(|(id, _, _)| *id == prev_id) {
3279                Some((_, _, prev_z26)) => match (z25, prev_z26) {
3280                    (Some(curr), Some(prev_end)) => {
3281                        if curr != prev_end {
3282                            return ConditionResult::False;
3283                        }
3284                    }
3285                    _ => return ConditionResult::Unknown,
3286                },
3287                None => return ConditionResult::Unknown,
3288            }
3289        }
3290        ConditionResult::True
3291    }
3292
3293    /// [136] Wenn SG10 CCI+++E13 (Zählertyp) CAV+EHZ (elektronischer Haushaltszähler) vorhanden
3294    fn evaluate_136(&self, ctx: &EvaluationContext) -> ConditionResult {
3295        let cci_segs = ctx.find_segments("CCI");
3296        let found = cci_segs.iter().any(|s| {
3297            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E13")
3298        });
3299        ConditionResult::from(found)
3300    }
3301
3302    /// [137] Nicht bei Neuanlage
3303    fn evaluate_137(&self, ctx: &EvaluationContext) -> ConditionResult {
3304        // Check: not a Neuanlage (new registration) process
3305        // STS+7 with transaktionsgrund containing Neuanlage indicators
3306        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "7");
3307        let is_neuanlage = sts_segs.iter().any(|s| {
3308            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E01" || v == "E03")
3309        });
3310        ConditionResult::from(!is_neuanlage)
3311    }
3312
3313    /// [138] Wenn im selben QTY im DE6063 Z35 (Abschlag) vorhanden
3314    fn evaluate_138(&self, ctx: &EvaluationContext) -> ConditionResult {
3315        let qty_segs = ctx.find_segments("QTY");
3316        let found = qty_segs.iter().any(|s| {
3317            s.elements.first().and_then(|e| e.first())
3318                .is_some_and(|v| ["Z35"].contains(&v.as_str()))
3319        });
3320        ConditionResult::from(found)
3321    }
3322
3323    /// [139] Wenn SG10 CAV+IVA (Individuelle Abstimmung) nicht vorhanden
3324    // REVIEW: Condition is True when SG10 CAV+IVA (Individuelle Abstimmung) is NOT present anywhere. Uses parent-child navigation to iterate all SG8 instances and their SG10 child groups, checking CAV elements[0][0] for 'IVA'. Falls back to message-wide lacks_qualifier when no navigator is available. Returns False as soon as any CAV+IVA is found, True if none found. (medium confidence)
3325    fn evaluate_139(&self, ctx: &EvaluationContext) -> ConditionResult {
3326        let nav = match ctx.navigator {
3327            Some(n) => n,
3328            None => return ctx.lacks_qualifier("CAV", 0, "IVA"),
3329        };
3330        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3331        for i in 0..sg8_count {
3332            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
3333            for j in 0..sg10_count {
3334                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
3335                if cavs.iter().any(|s| {
3336                    s.elements
3337                        .first()
3338                        .and_then(|e: &Vec<String>| e.first())
3339                        .is_some_and(|v: &String| v == "IVA")
3340                }) {
3341                    return ConditionResult::False;
3342                }
3343            }
3344        }
3345        ConditionResult::True
3346    }
3347
3348    /// [140] Wenn im selben QTY im DE6063 Z34/Z35 (Zuschlag/Abschlag) vorhanden
3349    fn evaluate_140(&self, ctx: &EvaluationContext) -> ConditionResult {
3350        let qty_segs = ctx.find_segments("QTY");
3351        let found = qty_segs.iter().any(|s| {
3352            s.elements.first().and_then(|e| e.first())
3353                .is_some_and(|v| ["Z34", "Z35"].contains(&v.as_str()))
3354        });
3355        ConditionResult::from(found)
3356    }
3357
3358    /// [141] Wenn SG10 CAV+MIW/ MPW/ MBW vorhanden
3359    fn evaluate_141(&self, ctx: &EvaluationContext) -> ConditionResult {
3360        let cav_segs = ctx.find_segments("CAV");
3361        let found = cav_segs.iter().any(|s| {
3362            s.elements.first().and_then(|e| e.first())
3363                .is_some_and(|v| ["MIW", "MPW", "MBW"].contains(&v.as_str()))
3364        });
3365        ConditionResult::from(found)
3366    }
3367
3368    /// [142] Wenn SG8 PIA+Z01+:Z04/ Z05 (Berechnung Tagesmitteltemperatur: vom Anbieter zur Verfügung gestellte - / Äquivalente Tagesmitteltemperatur) vorhanden
3369    fn evaluate_142(&self, ctx: &EvaluationContext) -> ConditionResult {
3370        let pia_segs = ctx.find_segments("PIA");
3371        let found = pia_segs.iter().any(|s| {
3372            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z01")
3373                && s.elements.get(1).and_then(|e| e.get(1))
3374                    .is_some_and(|v| ["Z04", "Z05"].contains(&v.as_str()))
3375        });
3376        ConditionResult::from(found)
3377    }
3378
3379    /// [143] Wenn STS+7++ZX3 (Transaktionsgrund: Abrechnungsdaten BK-Abrechnung verbrauchender MaLo) vorhanden
3380    fn evaluate_143(&self, ctx: &EvaluationContext) -> ConditionResult {
3381        let sts_segs = ctx.find_segments("STS");
3382        let found = sts_segs.iter().any(|s| {
3383            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3384                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZX3")
3385        });
3386        ConditionResult::from(found)
3387    }
3388
3389    /// [144] Wenn STS+7++ZAN (Transaktionsgrund: Korrektur Abrechnungsdaten BK-Abrechnung verbrauchender MaLo) vorhanden
3390    fn evaluate_144(&self, ctx: &EvaluationContext) -> ConditionResult {
3391        let sts_segs = ctx.find_segments("STS");
3392        let found = sts_segs.iter().any(|s| {
3393            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3394                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZAN")
3395        });
3396        ConditionResult::from(found)
3397    }
3398
3399    /// [145] Wenn STS+7++ZX2 (Transaktionsgrund: Abrechnungsdaten BK-Abrechnung erzeugender MaLo) vorhanden
3400    fn evaluate_145(&self, ctx: &EvaluationContext) -> ConditionResult {
3401        let sts_segs = ctx.find_segments("STS");
3402        let found = sts_segs.iter().any(|s| {
3403            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3404                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZX2")
3405        });
3406        ConditionResult::from(found)
3407    }
3408
3409    /// [146] Wenn STS+7++ZA0 (Transaktionsgrund: Korrektur Abrechnungsdaten BK-Abrechnung erzeugender MaLo) vorhanden
3410    fn evaluate_146(&self, ctx: &EvaluationContext) -> ConditionResult {
3411        let sts_segs = ctx.find_segments("STS");
3412        let found = sts_segs.iter().any(|s| {
3413            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3414                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA0")
3415        });
3416        ConditionResult::from(found)
3417    }
3418
3419    /// [147] Wenn in Anfrage vorhanden
3420    fn evaluate_147(&self, _ctx: &EvaluationContext) -> ConditionResult {
3421        // TODO: implement
3422        ConditionResult::Unknown
3423    }
3424
3425    /// [148] Wenn in dieser SG8 im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), die Artikel-ID 1-02-0-017/ 1-02-0-018 vorhanden
3426    fn evaluate_148(&self, ctx: &EvaluationContext) -> ConditionResult {
3427        let pia_segs = ctx.find_segments("PIA");
3428        let found = pia_segs.iter().any(|s| {
3429            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
3430                && s.elements.get(1).and_then(|e| e.first())
3431                    .is_some_and(|v| ["1-02-0-017", "1-02-0-018"].contains(&v.as_str()))
3432        });
3433        ConditionResult::from(found)
3434    }
3435
3436    /// [149] Wenn zwei SG8 SEQ+Z45 (Netznutzungsabrechnungsdaten der Marktlokation), mit  derselben Zeitraum-ID im DE1050, mit Artikel-ID im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), eine SG8 mit 1-02-0-017...
3437    // REVIEW: Condition checks whether two SG8 SEQ+Z45 groups with the same Zeitraum-ID (elements[1][0]) each contain PIA+Z02 (DE4347=Z02) with product codes '1-02-0-017' and '1-02-0-018'. Uses collect_group_values to gather SEQ qualifiers and Zeitraum-IDs per group instance, then PIA qualifiers and product codes (elements[1][0]=DE7140) per group instance. Positional alignment of pia_quals and pia_prods (both from same PIA segments in same order) enables reliable qualifier-to-product matching. Groups product codes by Zeitraum-ID to check co-occurrence. (medium confidence)
3438    fn evaluate_149(&self, ctx: &EvaluationContext) -> ConditionResult {
3439        use std::collections::{HashMap, HashSet};
3440        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
3441        let seq_zeitraum = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
3442        let pia_quals = ctx.collect_group_values("PIA", 0, 0, &["SG4", "SG8"]);
3443        let pia_prods = ctx.collect_group_values("PIA", 1, 0, &["SG4", "SG8"]);
3444        // Map group index -> Zeitraum-ID for SG8s with SEQ+Z45
3445        let mut idx_to_zeitraum: HashMap<usize, String> = HashMap::new();
3446        for ((gi, q), (_, zid)) in seq_quals.iter().zip(seq_zeitraum.iter()) {
3447            if q == "Z45" && !zid.is_empty() {
3448                idx_to_zeitraum.insert(*gi, zid.clone());
3449            }
3450        }
3451        if idx_to_zeitraum.is_empty() {
3452            return ConditionResult::False;
3453        }
3454        // Map Zeitraum-ID -> set of PIA+Z02 product codes found in the same SG8 group
3455        let mut zeitraum_products: HashMap<String, HashSet<String>> = HashMap::new();
3456        for (i, (gi, qual)) in pia_quals.iter().enumerate() {
3457            if qual == "Z02" {
3458                if let Some(zid) = idx_to_zeitraum.get(gi) {
3459                    if let Some((_, prod)) = pia_prods.get(i) {
3460                        if !prod.is_empty() {
3461                            zeitraum_products
3462                                .entry(zid.clone())
3463                                .or_default()
3464                                .insert(prod.clone());
3465                        }
3466                    }
3467                }
3468            }
3469        }
3470        ConditionResult::from(
3471            zeitraum_products
3472                .values()
3473                .any(|codes| codes.contains("1-02-0-017") && codes.contains("1-02-0-018")),
3474        )
3475    }
3476
3477    /// [150] Wenn in dieser SG8 im SG8 PIA+Z02 (Gruppenartikel-ID / Artikel-ID), die Artikel-ID 1-02-0-002 vorhanden
3478    fn evaluate_150(&self, ctx: &EvaluationContext) -> ConditionResult {
3479        let pia_segs = ctx.find_segments("PIA");
3480        let found = pia_segs.iter().any(|s| {
3481            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
3482                && s.elements.get(1).and_then(|e| e.first())
3483                    .is_some_and(|v| ["1-02-0-002"].contains(&v.as_str()))
3484        });
3485        ConditionResult::from(found)
3486    }
3487
3488    /// [151] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Ü̈bertragungsweg \"aus dem SMGW\" bestellt wurde. Der Empfänger der Werte kann dadurch seine...
3489    fn evaluate_151(&self, ctx: &EvaluationContext) -> ConditionResult {
3490        ctx.external.evaluate("code_list_membership_check")
3491    }
3492
3493    /// [152] Wenn FTX+Z28 (IP-Range des Absenders) nicht vorhanden
3494    fn evaluate_152(&self, ctx: &EvaluationContext) -> ConditionResult {
3495        let ftx_segs = ctx.find_segments("FTX");
3496        let found = ftx_segs.iter().any(|s| {
3497            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z28")
3498        });
3499        ConditionResult::from(!found)
3500    }
3501
3502    /// [153] Wenn FTX+Z27 (IP-Adresse des Absenders) nicht vorhanden
3503    fn evaluate_153(&self, ctx: &EvaluationContext) -> ConditionResult {
3504        let ftx_segs = ctx.find_segments("FTX");
3505        let found = ftx_segs.iter().any(|s| {
3506            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z27")
3507        });
3508        ConditionResult::from(!found)
3509    }
3510
3511    /// [156] Wenn SG4 FTX+Z17 (Zieladresse URI) vorhanden
3512    fn evaluate_156(&self, ctx: &EvaluationContext) -> ConditionResult {
3513        let ftx_segs = ctx.find_segments("FTX");
3514        let found = ftx_segs.iter().any(|s| {
3515            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
3516        });
3517        ConditionResult::from(found)
3518    }
3519
3520    /// [161] Wenn SG4 STS+7++E03+ZW8 (Transaktionsgrundergänzung Fall 1) vorhanden
3521    fn evaluate_161(&self, ctx: &EvaluationContext) -> ConditionResult {
3522        let sts_segs = ctx.find_segments("STS");
3523        let found = sts_segs.iter().any(|s| {
3524            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3525                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E03")
3526                && s.elements.get(3).and_then(|e| e.first()).is_some_and(|v| v == "ZW8")
3527        });
3528        ConditionResult::from(found)
3529    }
3530
3531    /// [162] Wenn SG4 STS+7++E03+ZW9 (Transaktionsgrundergänzung Fall 2) vorhanden
3532    fn evaluate_162(&self, ctx: &EvaluationContext) -> ConditionResult {
3533        let sts_segs = ctx.find_segments("STS");
3534        let found = sts_segs.iter().any(|s| {
3535            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3536                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E03")
3537                && s.elements.get(3).and_then(|e| e.first()).is_some_and(|v| v == "ZW9")
3538        });
3539        ConditionResult::from(found)
3540    }
3541
3542    /// [163] Wenn SG4 STS+7++E03+ZX0 (Transaktionsgrundergänzung Fall 3) vorhanden
3543    fn evaluate_163(&self, ctx: &EvaluationContext) -> ConditionResult {
3544        let sts_segs = ctx.find_segments("STS");
3545        let found = sts_segs.iter().any(|s| {
3546            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3547                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E03")
3548                && s.elements.get(3).and_then(|e| e.first()).is_some_and(|v| v == "ZX0")
3549        });
3550        ConditionResult::from(found)
3551    }
3552
3553    /// [164] Wenn SG4 STS+7++E03+ZX1 (Transaktionsgrundergänzung Fall 4) vorhanden
3554    fn evaluate_164(&self, ctx: &EvaluationContext) -> ConditionResult {
3555        let sts_segs = ctx.find_segments("STS");
3556        let found = sts_segs.iter().any(|s| {
3557            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3558                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E03")
3559                && s.elements.get(3).and_then(|e| e.first()).is_some_and(|v| v == "ZX1")
3560        });
3561        ConditionResult::from(found)
3562    }
3563
3564    /// [165] Wenn bekannt
3565    fn evaluate_165(&self, _ctx: &EvaluationContext) -> ConditionResult {
3566        // TODO: implement
3567        ConditionResult::Unknown
3568    }
3569
3570    /// [166] Wenn vorhanden
3571    fn evaluate_166(&self, _ctx: &EvaluationContext) -> ConditionResult {
3572        // "If present" — always true when the field is being validated
3573        ConditionResult::True
3574    }
3575
3576    /// [167] Wenn SG5 LOC+Z21 (Tranche) vorhanden
3577    fn evaluate_167(&self, ctx: &EvaluationContext) -> ConditionResult {
3578        let loc_segs = ctx.find_segments("LOC");
3579        let found = loc_segs.iter().any(|s| {
3580            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z21")
3581        });
3582        ConditionResult::from(found)
3583    }
3584
3585    /// [170] Wenn Anschrift der Marktlokation vorhanden
3586    fn evaluate_170(&self, _ctx: &EvaluationContext) -> ConditionResult {
3587        // TODO: implement
3588        ConditionResult::Unknown
3589    }
3590
3591    /// [172] Wenn im selben QTY im DE6063 Z37 (Kein Zu- und Abschlag) vorhanden
3592    fn evaluate_172(&self, ctx: &EvaluationContext) -> ConditionResult {
3593        let qty_segs = ctx.find_segments("QTY");
3594        let found = qty_segs.iter().any(|s| {
3595            s.elements.first().and_then(|e| e.first())
3596                .is_some_and(|v| ["Z37"].contains(&v.as_str()))
3597        });
3598        ConditionResult::from(found)
3599    }
3600
3601    /// [173] Wenn im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) das DE1156 (Fortlaufende Nummer eines Lokationsbündels im Geschäftsvorfall) in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (...
3602    // REVIEW: Condition is True when, in an SG8 with SEQ+Z58/ZC9/ZD0/ZD6 (Zuordnung Lokation zum Objektcode), RFF+Z33 exists but its DE1156 (elements[0][2] = Fortlaufende Nummer) is absent or empty. Uses collect_group_values to find target SG8 group indices by SEQ qualifier, then positionally aligns rff_quals[i] with rff_de1156[i] (same RFF segment) to check DE1156 emptiness scoped to those groups. Returns Unknown if no RFF+Z33 found in target groups (condition not applicable), False if all RFF+Z33 have DE1156 present. (medium confidence)
3603    fn evaluate_173(&self, ctx: &EvaluationContext) -> ConditionResult {
3604        use std::collections::HashSet;
3605        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
3606        let target_indices: HashSet<usize> = seq_quals
3607            .iter()
3608            .filter(|(_, q)| matches!(q.as_str(), "Z58" | "ZC9" | "ZD0" | "ZD6"))
3609            .map(|(i, _)| *i)
3610            .collect();
3611        if target_indices.is_empty() {
3612            return ConditionResult::Unknown;
3613        }
3614        // Collect RFF qualifier (elements[0][0]) and DE1156 (elements[0][2]) with positional alignment
3615        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
3616        let rff_de1156 = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG8"]);
3617        let mut found_rff_z33 = false;
3618        for (i, (gi, qual)) in rff_quals.iter().enumerate() {
3619            if qual == "Z33" && target_indices.contains(gi) {
3620                found_rff_z33 = true;
3621                let de1156_empty = rff_de1156.get(i).map(|(_, v)| v.is_empty()).unwrap_or(true);
3622                if de1156_empty {
3623                    return ConditionResult::True;
3624                }
3625            }
3626        }
3627        if found_rff_z33 {
3628            ConditionResult::False
3629        } else {
3630            ConditionResult::Unknown
3631        }
3632    }
3633
3634    /// [174] Wenn im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) das DE1156 Fortlaufende Nummer eines Lokationsbündels im Geschäftsvorfall) in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Z...
3635    fn evaluate_174(&self, ctx: &EvaluationContext) -> ConditionResult {
3636        // Check: RFF+Z33 has a value in DE1156 (fortlaufende Nummer)
3637        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
3638        let found = rff_z33.iter().any(|s| {
3639            s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| !v.is_empty())
3640        });
3641        ConditionResult::from(found)
3642    }
3643
3644    /// [175] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58 (Zuordnung Lokation zum Objektcode des Lokationsbündels) in einem weite...
3645    // REVIEW: Cross-SG8 check: find all SG8 instances with SEQ+Z58 that also have RFF+Z33. Check whether any Objektcode (DE1154) with the same fortlaufende Nummer (DE1156) appears in two distinct SG8 instances. Uses nav.find_segments_in_group to access SG8-level segments directly, following the existing navigator pattern. (medium confidence)
3646    fn evaluate_175(&self, ctx: &EvaluationContext) -> ConditionResult {
3647        let nav = match ctx.navigator {
3648            Some(n) => n,
3649            None => return ConditionResult::Unknown,
3650        };
3651        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3652        let mut entries: Vec<(usize, String, String)> = Vec::new();
3653        for i in 0..sg8_count {
3654            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
3655            if !seqs.iter().any(|s| {
3656                s.elements
3657                    .first()
3658                    .and_then(|e: &Vec<String>| e.first())
3659                    .is_some_and(|v: &String| v == "Z58")
3660            }) {
3661                continue;
3662            }
3663            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
3664            for rff in &rffs {
3665                let elems = match rff.elements.first() {
3666                    Some(e) => e,
3667                    None => continue,
3668                };
3669                if elems.first().map(|s| s.as_str()) != Some("Z33") {
3670                    continue;
3671                }
3672                let objektcode = elems.get(1).cloned().unwrap_or_default();
3673                let fort_nr = elems.get(2).cloned().unwrap_or_default();
3674                if !objektcode.is_empty() {
3675                    entries.push((i, objektcode, fort_nr));
3676                }
3677            }
3678        }
3679        for a in 0..entries.len() {
3680            for b in (a + 1)..entries.len() {
3681                if entries[a].0 != entries[b].0
3682                    && entries[a].1 == entries[b].1
3683                    && entries[a].2 == entries[b].2
3684                {
3685                    return ConditionResult::True;
3686                }
3687            }
3688        }
3689        ConditionResult::False
3690    }
3691
3692    /// [176] Wenn in demselben Segment das DE1153 mit dem Code Z34 vorgelagerte Messlokation vorhanden ist
3693    fn evaluate_176(&self, ctx: &EvaluationContext) -> ConditionResult {
3694        let rff_segs = ctx.find_segments("RFF");
3695        let found = rff_segs.iter().any(|s| {
3696            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z34")
3697        });
3698        ConditionResult::from(found)
3699    }
3700
3701    /// [177] Wenn in demselben Segment das DE1153 mit dem Code Z35 vorgelagerte Netzlokation vorhanden ist
3702    fn evaluate_177(&self, ctx: &EvaluationContext) -> ConditionResult {
3703        let rff_segs = ctx.find_segments("RFF");
3704        let found = rff_segs.iter().any(|s| {
3705            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z35")
3706        });
3707        ConditionResult::from(found)
3708    }
3709
3710    /// [178] Wenn das LOC+Z18 (Netzlokation) vorhanden ist
3711    fn evaluate_178(&self, ctx: &EvaluationContext) -> ConditionResult {
3712        let loc_segs = ctx.find_segments("LOC");
3713        let found = loc_segs.iter().any(|s| {
3714            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z18")
3715        });
3716        ConditionResult::from(found)
3717    }
3718
3719    /// [179] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ ZC9 / ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels...
3720    fn evaluate_179(&self, ctx: &EvaluationContext) -> ConditionResult {
3721        // Check: RFF+Z33 has a value in DE1154 (Objektcode)
3722        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
3723        let found = rff_z33.iter().any(|s| {
3724            s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| !v.is_empty())
3725        });
3726        ConditionResult::from(found)
3727    }
3728
3729    /// [180] Wenn im selben QTY im DE6063 Z46 (Kein Abschlag) vorhanden
3730    fn evaluate_180(&self, ctx: &EvaluationContext) -> ConditionResult {
3731        let qty_segs = ctx.find_segments("QTY");
3732        let found = qty_segs.iter().any(|s| {
3733            s.elements.first().and_then(|e| e.first())
3734                .is_some_and(|v| ["Z46"].contains(&v.as_str()))
3735        });
3736        ConditionResult::from(found)
3737    }
3738
3739    /// [184] Wenn in derselben SG8 SEQ+Z18 (Daten der Messlokation) ein CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokation) vorhanden
3740    fn evaluate_184(&self, ctx: &EvaluationContext) -> ConditionResult {
3741        let seq_segs = ctx.find_segments("SEQ");
3742        let found = seq_segs.iter().any(|s| {
3743            s.elements.first().and_then(|e| e.first())
3744                .is_some_and(|v| ["Z18"].contains(&v.as_str()))
3745        });
3746        ConditionResult::from(found)
3747    }
3748
3749    /// [190] Wenn in derselben SG8 SEQ+Z60/ ZG8/ ZG9/ ZE0  (Produkt-Daten der Netzlokation) PIA+5+9991000000721:Z12 vorhanden
3750    fn evaluate_190(&self, ctx: &EvaluationContext) -> ConditionResult {
3751        // Check: SG8 with SEQ+Z60/ZG8/ZG9/ZE0 has PIA+5 with code 9991000000721
3752        let pia_segs = ctx.find_segments("PIA");
3753        let found = pia_segs.iter().any(|s| {
3754            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
3755                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v == "9991000000721")
3756        });
3757        ConditionResult::from(found)
3758    }
3759
3760    /// [191] Wenn im SG4 IDE+Z01 (Identifikation einer Liste) STS+E01 (Status der Antwort der Liste) nicht vorhanden
3761    fn evaluate_191(&self, ctx: &EvaluationContext) -> ConditionResult {
3762        let sts_segs = ctx.find_segments("STS");
3763        let found = sts_segs.iter().any(|s| {
3764            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
3765        });
3766        ConditionResult::from(!found)
3767    }
3768
3769    /// [192] Wenn SG4 STS+7++XXX+ZW4/ZAP (Transaktionsgrund / Ergänzung: Verbrauchende Marktlokation / ruhende Marktlokation) vorhanden
3770    fn evaluate_192(&self, ctx: &EvaluationContext) -> ConditionResult {
3771        let sts_segs = ctx.find_segments("STS");
3772        let found = sts_segs.iter().any(|s| {
3773            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
3774                && s.elements.get(3).and_then(|e| e.first())
3775                    .is_some_and(|v| ["ZW4", "ZAP"].contains(&v.as_str()))
3776        });
3777        ConditionResult::from(found)
3778    }
3779
3780    /// [193] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E06 (Niederspannung) in dieser SG vorhanden
3781    fn evaluate_193(&self, ctx: &EvaluationContext) -> ConditionResult {
3782        let nav = match ctx.navigator {
3783            Some(n) => n,
3784            None => {
3785                let cavs = ctx.find_segments("CAV");
3786                return ConditionResult::from(cavs.iter().any(|s| {
3787                    s.elements
3788                        .first()
3789                        .and_then(|e: &Vec<String>| e.first())
3790                        .is_some_and(|v: &String| v == "E06")
3791                }));
3792            }
3793        };
3794        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3795        for i in 0..sg8_count {
3796            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
3797            for j in 0..sg10_count {
3798                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
3799                let has_cci_zb5 = ccis.iter().any(|s| {
3800                    s.elements
3801                        .get(2)
3802                        .and_then(|e: &Vec<String>| e.first())
3803                        .is_some_and(|v: &String| v == "ZB5")
3804                });
3805                if !has_cci_zb5 {
3806                    continue;
3807                }
3808                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
3809                if cavs.iter().any(|s| {
3810                    s.elements
3811                        .first()
3812                        .and_then(|e: &Vec<String>| e.first())
3813                        .is_some_and(|v: &String| v == "E06")
3814                }) {
3815                    return ConditionResult::True;
3816                }
3817            }
3818        }
3819        ConditionResult::False
3820    }
3821
3822    /// [194] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E05 (Mittelspannung) in dieser SG vorhanden
3823    fn evaluate_194(&self, ctx: &EvaluationContext) -> ConditionResult {
3824        let cci_segs = ctx.find_segments("CCI");
3825        let has_cci = cci_segs.iter().any(|s| {
3826            s.elements.iter().any(|e| e.first().is_some_and(|v| v == "ZB5"))
3827        });
3828        let cav_segs = ctx.find_segments("CAV");
3829        let has_cav = cav_segs.iter().any(|s| {
3830            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E05")
3831        });
3832        ConditionResult::from(has_cci && has_cav)
3833    }
3834
3835    /// [195] Wenn das SG10 CCI ZB5 (Spannungsebene der Summenzeitreihe) CAV E04 (Hochspannung) in dieser SG vorhanden
3836    fn evaluate_195(&self, ctx: &EvaluationContext) -> ConditionResult {
3837        let cci_segs = ctx.find_segments("CCI");
3838        let has_cci = cci_segs.iter().any(|s| {
3839            s.elements.iter().any(|e| e.first().is_some_and(|v| v == "ZB5"))
3840        });
3841        let cav_segs = ctx.find_segments("CAV");
3842        let has_cav = cav_segs.iter().any(|s| {
3843            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E04")
3844        });
3845        ConditionResult::from(has_cci && has_cav)
3846    }
3847
3848    /// [196] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ZC9/ZD0 (Zuordnung Lokation zum Objektcode des Lokationsbündels) in ein...
3849    // REVIEW: Extended cross-SG8 check vs 175: now requires matching SEQ qualifier code (DE1229), Zeitraum-ID from SEQ DE1050 (elements[1][0]), Objektcode (RFF+Z33 DE1154), AND fortlaufende Nummer (RFF+Z33 DE1156) to all be identical between two distinct SG8 instances. SEQ qualifiers are Z58/ZC9/ZD0 per schema. (medium confidence)
3850    fn evaluate_196(&self, ctx: &EvaluationContext) -> ConditionResult {
3851        let nav = match ctx.navigator {
3852            Some(n) => n,
3853            None => return ConditionResult::Unknown,
3854        };
3855        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3856        let mut entries: Vec<(usize, String, String, String, String)> = Vec::new();
3857        for i in 0..sg8_count {
3858            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
3859            let seq_opt = seqs.iter().find(|s| {
3860                s.elements
3861                    .first()
3862                    .and_then(|e: &Vec<String>| e.first())
3863                    .is_some_and(|v: &String| matches!(v.as_str(), "Z58" | "ZC9" | "ZD0"))
3864            });
3865            let seq = match seq_opt {
3866                Some(s) => s,
3867                None => continue,
3868            };
3869            let seq_code = seq
3870                .elements
3871                .first()
3872                .and_then(|e: &Vec<String>| e.first())
3873                .cloned()
3874                .unwrap_or_default();
3875            let zeitraum_id = seq
3876                .elements
3877                .get(1)
3878                .and_then(|e: &Vec<String>| e.first())
3879                .cloned()
3880                .unwrap_or_default();
3881            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
3882            for rff in &rffs {
3883                let elems = match rff.elements.first() {
3884                    Some(e) => e,
3885                    None => continue,
3886                };
3887                if elems.first().map(|s| s.as_str()) != Some("Z33") {
3888                    continue;
3889                }
3890                let objektcode = elems.get(1).cloned().unwrap_or_default();
3891                let fort_nr = elems.get(2).cloned().unwrap_or_default();
3892                if !objektcode.is_empty() {
3893                    entries.push((
3894                        i,
3895                        seq_code.clone(),
3896                        zeitraum_id.clone(),
3897                        objektcode,
3898                        fort_nr,
3899                    ));
3900                }
3901            }
3902        }
3903        for a in 0..entries.len() {
3904            for b in (a + 1)..entries.len() {
3905                if entries[a].0 != entries[b].0
3906                    && entries[a].1 == entries[b].1
3907                    && entries[a].2 == entries[b].2
3908                    && entries[a].3 == entries[b].3
3909                    && entries[a].4 == entries[b].4
3910                {
3911                    return ConditionResult::True;
3912                }
3913            }
3914        }
3915        ConditionResult::False
3916    }
3917
3918    /// [197] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation), in dem SG10 CCI+++ZA6 (...
3919    // REVIEW: Two-phase cross-SG8 check. Phase 1: collect Marktlokation IDs from SG8 instances that (a) have SEQ+Z01 and (b) have an SG10 child with CCI elements[2][0]=ZA6 and CAV elements[0][0]=E02. Phase 2: check whether any SG8's RFF+Z18 references one of those qualifying Marktlokation IDs, establishing the cross-reference described in the condition. (medium confidence)
3920    fn evaluate_197(&self, ctx: &EvaluationContext) -> ConditionResult {
3921        let nav = match ctx.navigator {
3922            Some(n) => n,
3923            None => return ConditionResult::Unknown,
3924        };
3925        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
3926        let mut qualifying_malo_ids: Vec<String> = Vec::new();
3927        for i in 0..sg8_count {
3928            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
3929            if !seqs.iter().any(|s| {
3930                s.elements
3931                    .first()
3932                    .and_then(|e: &Vec<String>| e.first())
3933                    .is_some_and(|v: &String| v == "Z01")
3934            }) {
3935                continue;
3936            }
3937            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
3938            let has_prog = (0..sg10_count).any(|j| {
3939                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
3940                let has_za6 = ccis.iter().any(|s| {
3941                    s.elements
3942                        .get(2)
3943                        .and_then(|e: &Vec<String>| e.first())
3944                        .is_some_and(|v: &String| v == "ZA6")
3945                });
3946                if !has_za6 {
3947                    return false;
3948                }
3949                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
3950                cavs.iter().any(|s| {
3951                    s.elements
3952                        .first()
3953                        .and_then(|e: &Vec<String>| e.first())
3954                        .is_some_and(|v: &String| v == "E02")
3955                })
3956            });
3957            if !has_prog {
3958                continue;
3959            }
3960            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
3961            for rff in &rffs {
3962                let elems = match rff.elements.first() {
3963                    Some(e) => e,
3964                    None => continue,
3965                };
3966                if elems.first().map(|s| s.as_str()) != Some("Z18") {
3967                    continue;
3968                }
3969                if let Some(malo_id) = elems.get(1) {
3970                    if !malo_id.is_empty() {
3971                        qualifying_malo_ids.push(malo_id.clone());
3972                    }
3973                }
3974            }
3975        }
3976        if qualifying_malo_ids.is_empty() {
3977            return ConditionResult::False;
3978        }
3979        for i in 0..sg8_count {
3980            let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
3981            for rff in &rffs {
3982                let elems = match rff.elements.first() {
3983                    Some(e) => e,
3984                    None => continue,
3985                };
3986                if elems.first().map(|s| s.as_str()) != Some("Z18") {
3987                    continue;
3988                }
3989                if let Some(malo_id) = elems.get(1) {
3990                    if qualifying_malo_ids.contains(malo_id) {
3991                        return ConditionResult::True;
3992                    }
3993                }
3994            }
3995        }
3996        ConditionResult::False
3997    }
3998
3999    /// [198] Wenn SG4 STS+7++E03(Transaktionsgrund: Wechsel) vorhanden
4000    fn evaluate_198(&self, ctx: &EvaluationContext) -> ConditionResult {
4001        let sts_segs = ctx.find_segments("STS");
4002        let found = sts_segs.iter().any(|s| {
4003            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
4004                && s.elements.get(2).and_then(|e| e.first())
4005                    .is_some_and(|v| ["E03"].contains(&v.as_str()))
4006        });
4007        ConditionResult::from(found)
4008    }
4009
4010    /// [199] Wenn in der SG8 SEQ+Z01/ SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) mit identischer Zeitraum-ID im DE1050 CAV+E02 (SLP/SEP) vorhanden
4011    // REVIEW: Checks whether any SG8 with SEQ+Z01 (Daten der Marktlokation) contains an SG10 child group where CCI elements[2][0]=ZA6 (Prognosegrundlage: Prognose auf Basis von Profilen) and CAV elements[0][0]=E02 (SLP/SEP) appear in the same SG10 instance. The 'identischer Zeitraum-ID' constraint from SEQ DE1050 is structurally satisfied by operating within the same SG8 instance; deeper Zeitraum-ID cross-referencing with other groups is omitted as it would require knowing the external referencing context. (medium confidence)
4012    fn evaluate_199(&self, ctx: &EvaluationContext) -> ConditionResult {
4013        let nav = match ctx.navigator {
4014            Some(n) => n,
4015            None => {
4016                return ctx.filtered_parent_child_has_qualifier(
4017                    &["SG4", "SG8"],
4018                    "SEQ",
4019                    0,
4020                    "Z01",
4021                    "SG10",
4022                    "CCI",
4023                    2,
4024                    "ZA6",
4025                )
4026            }
4027        };
4028        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4029        for i in 0..sg8_count {
4030            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
4031            if !seqs.iter().any(|s| {
4032                s.elements
4033                    .first()
4034                    .and_then(|e: &Vec<String>| e.first())
4035                    .is_some_and(|v: &String| v == "Z01")
4036            }) {
4037                continue;
4038            }
4039            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
4040            for j in 0..sg10_count {
4041                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
4042                if !ccis.iter().any(|s| {
4043                    s.elements
4044                        .get(2)
4045                        .and_then(|e: &Vec<String>| e.first())
4046                        .is_some_and(|v: &String| v == "ZA6")
4047                }) {
4048                    continue;
4049                }
4050                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
4051                if cavs.iter().any(|s| {
4052                    s.elements
4053                        .first()
4054                        .and_then(|e: &Vec<String>| e.first())
4055                        .is_some_and(|v: &String| v == "E02")
4056                }) {
4057                    return ConditionResult::True;
4058                }
4059            }
4060        }
4061        ConditionResult::False
4062    }
4063
4064    /// [201] Wenn die Marktlokation / Tranche nicht den ganzen Bilanzierungsmonat dem gleichen Tupel aus Bilanzkreis, Zeitreihentyp, Spannungsebene und Lieferant zugeordnet ist
4065    fn evaluate_201(&self, _ctx: &EvaluationContext) -> ConditionResult {
4066        // TODO: implement
4067        ConditionResult::Unknown
4068    }
4069
4070    /// [202] Wenn SG8 SEQ+Z78 RFF+Z39 (Keine standardisierte Lokationsbündelstruktur vorhanden), mit identischer Zeitraum-ID im DE1050 wie im DE3224 dieses Segments
4071    // REVIEW: Collects Zeitraum-IDs from SG5 LOC.DE3224 (elements[1][3]), checks SEQ+Z78 DE1050 (elements[1][0]) for a match, then verifies RFF+Z39 exists. Co-occurrence of SEQ+Z78 and RFF+Z39 in the same SG8 instance is not verified without navigator group-instance access. (medium confidence)
4072    fn evaluate_202(&self, ctx: &EvaluationContext) -> ConditionResult {
4073        use std::collections::HashSet;
4074        // Collect Zeitraum-IDs from all SG5 LOC segments (DE3224 at elements[1][3])
4075        let loc_zeitraum_ids: HashSet<String> = ctx
4076            .find_segments("LOC")
4077            .into_iter()
4078            .filter_map(|s| s.elements.get(1)?.get(3).cloned())
4079            .filter(|v| !v.is_empty())
4080            .collect();
4081        if loc_zeitraum_ids.is_empty() {
4082            return ConditionResult::False;
4083        }
4084        // Check if any SEQ+Z78 (SG8 Lokationsbündelstruktur) has DE1050 matching a LOC DE3224
4085        let matching_seq = ctx
4086            .find_segments_with_qualifier("SEQ", 0, "Z78")
4087            .into_iter()
4088            .any(|s| {
4089                s.elements
4090                    .get(1)
4091                    .and_then(|e: &Vec<String>| e.first())
4092                    .is_some_and(|v: &String| {
4093                        !v.is_empty() && loc_zeitraum_ids.contains(v.as_str())
4094                    })
4095            });
4096        if !matching_seq {
4097            return ConditionResult::False;
4098        }
4099        // Verify RFF+Z39 also exists (co-occurrence in same SG8 not verified without navigator)
4100        ctx.has_qualifier("RFF", 0, "Z39")
4101    }
4102
4103    /// [203] Wenn STS+7++E06 / Z39 / ZC6 / ZC7/ ZT6/ ZT7 vorhanden
4104    fn evaluate_203(&self, ctx: &EvaluationContext) -> ConditionResult {
4105        let sts_segs = ctx.find_segments("STS");
4106        let found = sts_segs.iter().any(|s| {
4107            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
4108                && s.elements.get(2).and_then(|e| e.first())
4109                    .is_some_and(|v| ["E06", "Z39", "ZC6", "ZC7", "ZT6", "ZT7"].contains(&v.as_str()))
4110        });
4111        ConditionResult::from(found)
4112    }
4113
4114    /// [204] Wenn im SG8+SEQ+Z03/ ZA3/ ZA4 (Zähleinrichtungsdaten) mit der selben Zeitraum-ID im SG8 SEQ DE1050, sowie identischer Qualität im DE1229 der SG8 SEQ für die in diesem RFF DE1154 genannte Geräte...
4115    // REVIEW: Checks each Zähleinrichtungsdaten SEQ qualifier (Z03/ZA3/ZA4) — if any SG8 instance has that SEQ qualifier but no RFF+Z14 (Smartmeter-Gateway reference), the condition is true. The additional Zeitraum-ID and Gerätenummer cross-matching from the full condition text cannot be implemented without per-instance SG8 segment access. (medium confidence)
4116    fn evaluate_204(&self, ctx: &EvaluationContext) -> ConditionResult {
4117        // True if any SG8 with Zähleinrichtungsdaten (SEQ+Z03/ZA3/ZA4) lacks RFF+Z14 (Smartmeter-Gateway)
4118        for qual in &["Z03", "ZA3", "ZA4"] {
4119            if matches!(
4120                ctx.any_group_has_qualifier_without(
4121                    "SEQ",
4122                    0,
4123                    qual,
4124                    "RFF",
4125                    0,
4126                    "Z14",
4127                    &["SG4", "SG8"]
4128                ),
4129                ConditionResult::True
4130            ) {
4131                return ConditionResult::True;
4132            }
4133        }
4134        ConditionResult::False
4135    }
4136
4137    /// [205] Wenn SG5 LOC+Z19 (Steuerbare Ressource) vorhanden
4138    fn evaluate_205(&self, ctx: &EvaluationContext) -> ConditionResult {
4139        let loc_segs = ctx.find_segments("LOC");
4140        let found = loc_segs.iter().any(|s| {
4141            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z19")
4142        });
4143        ConditionResult::from(found)
4144    }
4145
4146    /// [206] Wenn SG4 STS+7++ZG5 (Transaktionsgrund: Aufhebung der zukünftigen Zuordnung aufgrund §38 EEG 2014 bzw. §21b Abs. 1 Nr. 2 EEG 2017) nicht vorhanden
4147    fn evaluate_206(&self, ctx: &EvaluationContext) -> ConditionResult {
4148        let sts_segs = ctx.find_segments("STS");
4149        let found = sts_segs.iter().any(|s| {
4150            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
4151                && s.elements.get(2).and_then(|e| e.first())
4152                    .is_some_and(|v| ["ZG5"].contains(&v.as_str()))
4153        });
4154        ConditionResult::from(!found)
4155    }
4156
4157    /// [209] Wenn im selben Segment im DE2379 der Code 303 vorhanden ist
4158    fn evaluate_209(&self, ctx: &EvaluationContext) -> ConditionResult {
4159        let dtm_segs = ctx.find_segments("DTM");
4160        let found = dtm_segs.iter().any(|s| {
4161            s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| v == "303")
4162        });
4163        ConditionResult::from(found)
4164    }
4165
4166    /// [210] Wenn SG10 CCI+++ZA6 (Prognose auf Basis von Profilen) in dieser SG8 vorhanden
4167    fn evaluate_210(&self, ctx: &EvaluationContext) -> ConditionResult {
4168        let cci_segs = ctx.find_segments("CCI");
4169        let found = cci_segs.iter().any(|s| {
4170            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA6")
4171        });
4172        ConditionResult::from(found)
4173    }
4174
4175    /// [212] Wenn im selben SG12 NAD DE3124 nicht vorhanden
4176    fn evaluate_212(&self, ctx: &EvaluationContext) -> ConditionResult {
4177        let nad_segs = ctx.find_segments("NAD");
4178        let found = nad_segs.iter().any(|s| {
4179            s.elements.get(3).and_then(|e| e.first()).is_some_and(|v| !v.is_empty())
4180        });
4181        ConditionResult::from(!found)
4182    }
4183
4184    /// [213] Wenn SG12 NAD+Z09 (Kunde des Lieferanten) vorhanden
4185    fn evaluate_213(&self, ctx: &EvaluationContext) -> ConditionResult {
4186        let nad_segs = ctx.find_segments("NAD");
4187        let found = nad_segs.iter().any(|s| {
4188            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z09")
4189        });
4190        ConditionResult::from(found)
4191    }
4192
4193    /// [215] Wenn in derselben SG8 (Zähleinrichtungsdaten) SG10 CCI+++E13 CAV+MME (Zählertyp: mME) vorhanden
4194    fn evaluate_215(&self, ctx: &EvaluationContext) -> ConditionResult {
4195        // Check: CCI with elements[2][0]=="E13" and CAV+MME exist
4196        let has_cci_e13 = ctx.find_segments("CCI").iter().any(|s| {
4197            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E13")
4198        });
4199        let has_cav_mme = ctx.find_segments("CAV").iter().any(|s| {
4200            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "MME")
4201        });
4202        ConditionResult::from(has_cci_e13 && has_cav_mme)
4203    }
4204
4205    /// [216] Wenn CCI+++Z88 (Netznutzung) CAV+Z74:::Z08 (Netznutzungsvertrag: Direkter Vertrag zwischen Kunden und NB) vorhanden
4206    fn evaluate_216(&self, ctx: &EvaluationContext) -> ConditionResult {
4207        let cci_segs = ctx.find_segments("CCI");
4208        let found = cci_segs.iter().any(|s| {
4209            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "Z88")
4210        });
4211        ConditionResult::from(found)
4212    }
4213
4214    /// [217] Wenn SG6 RFF+Z49 (Verwendungszeitraum der Daten: \"Gültige Daten\") vorhanden
4215    fn evaluate_217(&self, ctx: &EvaluationContext) -> ConditionResult {
4216        let rff_segs = ctx.find_segments("RFF");
4217        let found = rff_segs.iter().any(|s| {
4218            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z49")
4219        });
4220        ConditionResult::from(found)
4221    }
4222
4223    /// [219] Wenn SG12 NAD+Z65 (Informativer Kunde des Lieferanten) vorhanden
4224    fn evaluate_219(&self, ctx: &EvaluationContext) -> ConditionResult {
4225        let nad_segs = ctx.find_segments("NAD");
4226        let found = nad_segs.iter().any(|s| {
4227            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z65")
4228        });
4229        ConditionResult::from(found)
4230    }
4231
4232    /// [220] Wenn SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+Z30++Z06 (Lieferrichtung: Erzeugung) in dieser SG8 vorhanden
4233    fn evaluate_220(&self, ctx: &EvaluationContext) -> ConditionResult {
4234        let seq_segs = ctx.find_segments("SEQ");
4235        let has_seq = seq_segs.iter().any(|s| {
4236            s.elements.first().and_then(|e| e.first())
4237                .is_some_and(|v| ["Z01", "Z98"].contains(&v.as_str()))
4238        });
4239        let cci_segs = ctx.find_segments("CCI");
4240        let has_cci = cci_segs.iter().any(|s| {
4241            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z30") && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "Z06")
4242        });
4243        ConditionResult::from(has_seq && has_cci)
4244    }
4245
4246    /// [221] Wenn kein SG8 SEQ+Z15 (Daten der Tranche) auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z01 (Daten der Marktlokation)
4247    fn evaluate_221(&self, ctx: &EvaluationContext) -> ConditionResult {
4248        // Check: no SG8 with SEQ+Z15 has RFF+Z18 referencing same Marktlokation
4249        let has_seq_z15 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z15").is_empty();
4250        if !has_seq_z15 {
4251            return ConditionResult::True;
4252        }
4253        // Approximate: SEQ+Z15 exists, check if it references via RFF+Z18
4254        ctx.any_group_has_qualifier_without(
4255            "SEQ", 0, "Z15", "RFF", 0, "Z18", &["SG4", "SG8"],
4256        )
4257    }
4258
4259    /// [223] Wenn das RFF+Z18 (Marktlokation) aus dieser SG8 auf das gleiche SG5 LOC+Z16 (Marktlokation), wie ein RFF+Z18 (Marktlokation) aus einer SG8 SEQ+Z01 (Daten der Marktlokation) verweist, und dort das S...
4260    fn evaluate_223(&self, ctx: &EvaluationContext) -> ConditionResult {
4261        // Check: RFF+Z18 value matches LOC+Z16 ID from SG5
4262        let rff_z18 = ctx.find_segments_with_qualifier("RFF", 0, "Z18");
4263        let loc_z16 = ctx.find_segments_with_qualifier("LOC", 0, "Z16");
4264        if rff_z18.is_empty() || loc_z16.is_empty() {
4265            return ConditionResult::Unknown;
4266        }
4267        // Check if any RFF+Z18 value matches any LOC+Z16 DE3225
4268        let loc_ids: Vec<&str> = loc_z16.iter()
4269            .filter_map(|s| s.elements.get(1).and_then(|e| e.first()).map(|v| v.as_str()))
4270            .collect();
4271        let found = rff_z18.iter().any(|s| {
4272            s.elements.first().and_then(|e| e.get(1))
4273                .is_some_and(|v| loc_ids.contains(&v.as_str()))
4274        });
4275        ConditionResult::from(found)
4276    }
4277
4278    /// [224] Wenn kein SG8 SEQ+ZE7 (Informative Daten der Tranche) auf die gleiche Marktlokation-ID mit dem RFF+Z18 (Marktlokation) referenziert wie dieses SG8 SEQ+Z98 (Informative Daten der Marktlokation)
4279    fn evaluate_224(&self, ctx: &EvaluationContext) -> ConditionResult {
4280        // Check: no SG8 with SEQ+ZE7 has RFF+Z18 referencing same Marktlokation
4281        let has_seq_ze7 = !ctx.find_segments_with_qualifier("SEQ", 0, "ZE7").is_empty();
4282        if !has_seq_ze7 {
4283            return ConditionResult::True;
4284        }
4285        ctx.any_group_has_qualifier_without(
4286            "SEQ", 0, "ZE7", "RFF", 0, "Z18", &["SG4", "SG8"],
4287        )
4288    }
4289
4290    /// [227] Wenn im SG8 SEQ+Z98 (Daten der Marktlokation) das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E14 (TLP/TEP) vorhanden
4291    fn evaluate_227(&self, ctx: &EvaluationContext) -> ConditionResult {
4292        // Check: in SG8 with SEQ+Z98, SG10 has CCI+++ZA6 and CAV+E14 or ETK
4293        let r1 = ctx.filtered_parent_child_has_qualifier(
4294            &["SG4", "SG8"], "SEQ", 0, "Z98",
4295            "SG10", "CAV", 0, "E14",
4296        );
4297        if r1 == ConditionResult::True { return ConditionResult::True; }
4298        ctx.filtered_parent_child_has_qualifier(
4299            &["SG4", "SG8"], "SEQ", 0, "Z98",
4300            "SG10", "CAV", 0, "ETK",
4301        )
4302    }
4303
4304    /// [229] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der Lokationsbündelstruktur) im DE1154 derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels)...
4305    // REVIEW: Detects if the same (SEQ-qualifier, Zeitraum-ID, RFF+Z33-Objektcode) triple appears in two different SG8 instances — which is what the condition guards against. Uses collect_group_values to correlate SEQ and RFF data by SG8 instance index. Limitation: collect_group_values may only return the first RFF per SG8 instance, so Z33 may be missed if it is not the first RFF in the group. (medium confidence)
4306    fn evaluate_229(&self, ctx: &EvaluationContext) -> ConditionResult {
4307        use std::collections::HashSet;
4308        let target_quals: HashSet<&str> = ["Z58", "ZC9", "ZD0", "ZD6"].iter().cloned().collect();
4309        // Collect per-SG8-instance: SEQ qualifier and Zeitraum-ID
4310        let seq_quals = ctx.collect_group_values("SEQ", 0, 0, &["SG4", "SG8"]);
4311        let seq_zeitraums = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
4312        // Collect per-SG8-instance: RFF qualifier and DE1154 value
4313        let rff_quals = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG8"]);
4314        let rff_codes = ctx.collect_group_values("RFF", 0, 1, &["SG4", "SG8"]);
4315        // Detect duplicate (seq_qual, zeitraum_id, objektcode) combinations across SG8 instances
4316        let mut seen: HashSet<(String, String, String)> = HashSet::new();
4317        for (idx, seq_qual) in &seq_quals {
4318            if seq_qual.is_empty() || !target_quals.contains(seq_qual.as_str()) {
4319                continue;
4320            }
4321            let zeitraum_id = seq_zeitraums
4322                .iter()
4323                .find(|(i, _)| i == idx)
4324                .map(|(_, v)| v.as_str())
4325                .unwrap_or("");
4326            // Find RFF+Z33 in this SG8 instance (correlation by instance index)
4327            for (ridx, rff_qual) in rff_quals.iter() {
4328                if ridx != idx || rff_qual != "Z33" {
4329                    continue;
4330                }
4331                if let Some((_, obj_code)) = rff_codes.iter().find(|(i, _)| i == ridx) {
4332                    if obj_code.is_empty() {
4333                        continue;
4334                    }
4335                    let key = (seq_qual.clone(), zeitraum_id.to_string(), obj_code.clone());
4336                    if seen.contains(&key) {
4337                        return ConditionResult::True;
4338                    }
4339                    seen.insert(key);
4340                }
4341            }
4342        }
4343        ConditionResult::False
4344    }
4345
4346    /// [232] Wenn SG10 CCI+++Z83 (Messtechnische Einordnung der Marktlokation) CAV+Z52 (iMS) vorhanden
4347    fn evaluate_232(&self, ctx: &EvaluationContext) -> ConditionResult {
4348        let cci_segs = ctx.find_segments("CCI");
4349        let found = cci_segs.iter().any(|s| {
4350            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "Z83")
4351        });
4352        ConditionResult::from(found)
4353    }
4354
4355    /// [233] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle NB
4356    fn evaluate_233(&self, ctx: &EvaluationContext) -> ConditionResult {
4357        ctx.external.evaluate("recipient_role_check")
4358    }
4359
4360    /// [234] Wenn SG10 CCI+++Z83 (Messtechnische Einordnung der Marktlokation) CAV+Z53 (kME/ mME) vorhanden
4361    fn evaluate_234(&self, ctx: &EvaluationContext) -> ConditionResult {
4362        let cci_segs = ctx.find_segments("CCI");
4363        let found = cci_segs.iter().any(|s| {
4364            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "Z83")
4365        });
4366        ConditionResult::from(found)
4367    }
4368
4369    /// [237] Wenn in derselben SG8 im DE7140 des PIA+Z02 (Gruppenartikel-ID / Artikel-ID) eine Gruppenartikel-ID / Artikel-ID mit 1-06 (entspricht Entgelte des Messstellenbetriebs bei kME) beginnt
4370    fn evaluate_237(&self, ctx: &EvaluationContext) -> ConditionResult {
4371        // Check: PIA+Z02 with code starting with 1-08 and containing AGS
4372        let pia_segs = ctx.find_segments("PIA");
4373        let found = pia_segs.iter().any(|s| {
4374            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z02")
4375                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4376                    v.starts_with("1-08") && v.contains("AGS")
4377                })
4378        });
4379        ConditionResult::from(found)
4380    }
4381
4382    /// [238] Wenn SG4 IDE+24 (Vorgang) nicht vorhanden
4383    fn evaluate_238(&self, ctx: &EvaluationContext) -> ConditionResult {
4384        let ide_segs = ctx.find_segments("IDE");
4385        let found = ide_segs.iter().any(|s| {
4386            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "24")
4387        });
4388        ConditionResult::from(!found)
4389    }
4390
4391    /// [239] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+Z65 (Wärme/Kälte) vorhanden
4392    fn evaluate_239(&self, ctx: &EvaluationContext) -> ConditionResult {
4393        let cci_segs = ctx.find_segments("CCI");
4394        let found = cci_segs.iter().any(|s| {
4395            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
4396        });
4397        ConditionResult::from(found)
4398    }
4399
4400    /// [240] Wenn SG8 SEQ+Z01 (Daten der Marktlokation) CCI+Z22++Z91 (Veräußerungsform der erzeugenden Marktlokation:: Marktprämie) vorhanden
4401    fn evaluate_240(&self, ctx: &EvaluationContext) -> ConditionResult {
4402        let seq_segs = ctx.find_segments("SEQ");
4403        let found = seq_segs.iter().any(|s| {
4404            s.elements.first().and_then(|e| e.first())
4405                .is_some_and(|v| ["Z01"].contains(&v.as_str()))
4406        });
4407        ConditionResult::from(found)
4408    }
4409
4410    /// [241] Wenn MP-ID in SG2 NAD+MR (Nachrichtenempfänger) in der Rolle MSB
4411    fn evaluate_241(&self, ctx: &EvaluationContext) -> ConditionResult {
4412        ctx.external.evaluate("recipient_role_check")
4413    }
4414
4415    /// [243] Wenn SG10 CCI+6++ZA8 (Aggreg.verantw. NB) in dieser SG8 vorhanden
4416    fn evaluate_243(&self, ctx: &EvaluationContext) -> ConditionResult {
4417        let cci_segs = ctx.find_segments("CCI");
4418        let found = cci_segs.iter().any(|s| {
4419            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "6")
4420                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA8")
4421        });
4422        ConditionResult::from(found)
4423    }
4424
4425    /// [244] Wenn SG10 CCI+6++ZA9 (Aggreg.verantw. ÜNB) in dieser SG8 vorhanden
4426    fn evaluate_244(&self, ctx: &EvaluationContext) -> ConditionResult {
4427        let cci_segs = ctx.find_segments("CCI");
4428        let found = cci_segs.iter().any(|s| {
4429            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "6")
4430                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA9")
4431        });
4432        ConditionResult::from(found)
4433    }
4434
4435    /// [248] Wenn die Inbetriebnahme der verbrauchenden Marktlokation innerhalb der letzten drei Jahre war und die Energie der Marktlokation mit iMS ausgestatteten Messlokationen erfolgt
4436    fn evaluate_248(&self, _ctx: &EvaluationContext) -> ConditionResult {
4437        // TODO: implement
4438        ConditionResult::Unknown
4439    }
4440
4441    /// [249] Innerhalb eines SG4 IDE müssen alle DE1131 der SG4 STS+E01 (Status der Antwort) den identischen Wert enthalten
4442    fn evaluate_249(&self, ctx: &EvaluationContext) -> ConditionResult {
4443        // Check: all STS+E01 DE1131 values are identical
4444        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
4445        if sts_segs.len() <= 1 {
4446            return ConditionResult::True;
4447        }
4448        let first_val = sts_segs[0].elements.first().and_then(|e| e.get(1));
4449        let all_same = sts_segs.iter().all(|s| {
4450            s.elements.first().and_then(|e| e.get(1)) == first_val
4451        });
4452        ConditionResult::from(all_same)
4453    }
4454
4455    /// [251] Wenn MP-ID in SG2 NAD+MS (Nachrichtensender) in der Rolle BIKO
4456    fn evaluate_251(&self, ctx: &EvaluationContext) -> ConditionResult {
4457        ctx.external.evaluate("sender_role_check")
4458    }
4459
4460    /// [252] Wenn DE0068 vorhanden
4461    fn evaluate_252(&self, ctx: &EvaluationContext) -> ConditionResult {
4462        let unb_segs = ctx.find_segments("UNB");
4463        let found = unb_segs.iter().any(|s| {
4464            s.elements.get(4).and_then(|e| e.first()).is_some_and(|v| !v.is_empty())
4465        });
4466        ConditionResult::from(found)
4467    }
4468
4469    /// [254] Es ist der Code \"AUA\" einzutragen
4470    fn evaluate_254(&self, _ctx: &EvaluationContext) -> ConditionResult {
4471        // Check: the code "AUA" is present
4472        ConditionResult::True // AUA is always the required code when this condition applies
4473    }
4474
4475    /// [255] Wenn Marktlokation am Redispatch 2.0 teilnimmt
4476    fn evaluate_255(&self, _ctx: &EvaluationContext) -> ConditionResult {
4477        // TODO: implement
4478        ConditionResult::Unknown
4479    }
4480
4481    /// [256] Wenn in derselben SG8 SEQ (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) das PIA+5+1-b?:1.8.e / 1-b?:2.8.e vorhanden
4482    fn evaluate_256(&self, ctx: &EvaluationContext) -> ConditionResult {
4483        // Check: PIA+5 has OBIS code matching 1-?:1.8.? or 1-?:2.8.? pattern
4484        let pia_segs = ctx.find_segments("PIA");
4485        let found = pia_segs.iter().any(|s| {
4486            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
4487                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4488                    (v.contains(":1.8.") || v.contains(":2.8.")) && v.starts_with("1-")
4489                })
4490        });
4491        ConditionResult::from(found)
4492    }
4493
4494    /// [257] Wenn in derselben SG8 SEQ (OBIS-Daten der Marktlokation) das PIA+5+1-b?:1.9.e vorhanden
4495    fn evaluate_257(&self, ctx: &EvaluationContext) -> ConditionResult {
4496        // Check: PIA+5 has OBIS code matching 1-?:1.9.? pattern
4497        let pia_segs = ctx.find_segments("PIA");
4498        let found = pia_segs.iter().any(|s| {
4499            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
4500                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4501                    v.contains(":1.9.") && v.starts_with("1-")
4502                })
4503        });
4504        ConditionResult::from(found)
4505    }
4506
4507    /// [259] Wenn in diesem PIA der Code im DE7140 mit 1-01, 1-03, 1-05 enthalten ist
4508    fn evaluate_259(&self, ctx: &EvaluationContext) -> ConditionResult {
4509        let pia_segs = ctx.find_segments("PIA");
4510        let found = pia_segs.iter().any(|s| {
4511            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4512                let prefixes = ["1-01", "1-03", "1-05"];
4513                prefixes.iter().any(|p| v.starts_with(p))
4514            })
4515        });
4516        ConditionResult::from(found)
4517    }
4518
4519    /// [261] Wenn in diesem PIA der Code im DE7140 mit 1-07-1/2, 1-10-1/2/4/5/6/7/8/9, 1-11-1 beginnt
4520    fn evaluate_261(&self, ctx: &EvaluationContext) -> ConditionResult {
4521        let pia_segs = ctx.find_segments("PIA");
4522        let found = pia_segs.iter().any(|s| {
4523            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4524                let prefixes = ["1-07-1", "2", "1-10-1", "2", "4", "5", "6", "7", "8", "9", "1-11-1"];
4525                prefixes.iter().any(|p| v.starts_with(p))
4526            })
4527        });
4528        ConditionResult::from(found)
4529    }
4530
4531    /// [262] Wenn Produkt an der Marktlokation vorhanden ist
4532    fn evaluate_262(&self, _ctx: &EvaluationContext) -> ConditionResult {
4533        // TODO: implement
4534        ConditionResult::Unknown
4535    }
4536
4537    /// [265] Wenn im SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+Z36 (TEP m. Referenzmessung) vorhanden
4538    fn evaluate_265(&self, ctx: &EvaluationContext) -> ConditionResult {
4539        // Check: in SG8 with SEQ+Z01 or Z98, SG10 has CCI+++ZA6 and CAV+E14/ETK
4540        for &seq_qual in &["Z01", "Z98"] {
4541            for &cav_qual in &["E14", "ETK"] {
4542                let r = ctx.filtered_parent_child_has_qualifier(
4543                    &["SG4", "SG8"], "SEQ", 0, seq_qual,
4544                    "SG10", "CAV", 0, cav_qual,
4545                );
4546                if r == ConditionResult::True { return ConditionResult::True; }
4547            }
4548        }
4549        ConditionResult::False
4550    }
4551
4552    /// [266] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im SG8 SEQ+Z01 DE1050 wie in dieser SG8 SEQ, das SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis vo...
4553    // REVIEW: Navigates all SG8 instances and their SG10 children, checking for CCI with elements[2][0]=ZA6 (Prognosegrundlage) co-occurring with CAV with elements[0][0]=Z36 (TEP m. Referenzmessung) in the same SG10 instance. The parent SG8 SEQ+Z01 filter and Zeitraum-ID cross-matching are not verified due to lack of direct SG8-level segment access; relies on CCI+ZA6/CAV+Z36 being specific enough to Marktlokation groups. (medium confidence)
4554    fn evaluate_266(&self, ctx: &EvaluationContext) -> ConditionResult {
4555        let nav = match ctx.navigator {
4556            Some(n) => n,
4557            None => {
4558                // Fallback: check any SG8+SEQ+Z01 child SG10 has CAV+Z36
4559                return ctx.filtered_parent_child_has_qualifier(
4560                    &["SG4", "SG8"],
4561                    "SEQ",
4562                    0,
4563                    "Z01",
4564                    "SG10",
4565                    "CAV",
4566                    0,
4567                    "Z36",
4568                );
4569            }
4570        };
4571        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
4572        for i in 0..sg8_count {
4573            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
4574            for j in 0..sg10_count {
4575                // CCI+++ZA6 means elements[2][0] == "ZA6"
4576                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
4577                let has_cci_za6 = ccis.iter().any(|s| {
4578                    s.elements
4579                        .get(2)
4580                        .and_then(|e: &Vec<String>| e.first())
4581                        .is_some_and(|v: &String| v == "ZA6")
4582                });
4583                if has_cci_za6 {
4584                    let cavs =
4585                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
4586                    if cavs.iter().any(|s| {
4587                        s.elements
4588                            .first()
4589                            .and_then(|e: &Vec<String>| e.first())
4590                            .is_some_and(|v: &String| v == "Z36")
4591                    }) {
4592                        return ConditionResult::True;
4593                    }
4594                }
4595            }
4596        }
4597        ConditionResult::False
4598    }
4599
4600    /// [267] Wenn SG8 SEQ+Z38 (Referenzprofildaten) nicht vorhanden
4601    fn evaluate_267(&self, ctx: &EvaluationContext) -> ConditionResult {
4602        let seq_segs = ctx.find_segments("SEQ");
4603        let found = seq_segs.iter().any(|s| {
4604            s.elements.first().and_then(|e| e.first())
4605                .is_some_and(|v| ["Z38"].contains(&v.as_str()))
4606        });
4607        ConditionResult::from(!found)
4608    }
4609
4610    /// [268] Wenn der Code im DE3207 in der \"EDI@Energy Codeliste der europäischen Ländercodes\" in der Spalte \"PLZ vorhanden\" ein \"X\" aufgeführt ist
4611    fn evaluate_268(&self, _ctx: &EvaluationContext) -> ConditionResult {
4612        // Most European countries have postal codes — default to true
4613        ConditionResult::True
4614    }
4615
4616    /// [269] Es sind alle OBIS-Kennzahlen gem. EDI@Energy Codeliste der OBIS-Kennzahlen und Medien für den deutschen Energiemarkt Kap.3 anzugeben welche an der Tranche erforderlich sind
4617    fn evaluate_269(&self, _ctx: &EvaluationContext) -> ConditionResult {
4618        // TODO: implement
4619        ConditionResult::Unknown
4620    }
4621
4622    /// [270] Wenn in diesem PIA der Code im DE7140 mit 1-02, 1-04, 1-06, 1-09 beginnt
4623    fn evaluate_270(&self, ctx: &EvaluationContext) -> ConditionResult {
4624        let pia_segs = ctx.find_segments("PIA");
4625        let found = pia_segs.iter().any(|s| {
4626            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4627                let prefixes = ["1-02", "1-04", "1-06", "1-09"];
4628                prefixes.iter().any(|p| v.starts_with(p))
4629            })
4630        });
4631        ConditionResult::from(found)
4632    }
4633
4634    /// [273] Wenn in derselben SG8 SEQ+Z20 (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) das PIA+5+1-b?:1.8.e / 1-b?:2.8.e / 1-b?:3.8.e / 1-b?:4.8.e / 1-b?:5.8.e / 1-b?:6.8.e / 1-b?:7.8.e / 1-b?:8.8.e ...
4635    fn evaluate_273(&self, ctx: &EvaluationContext) -> ConditionResult {
4636        // Check: PIA+5 has OBIS code matching energy quantity patterns in SG8 SEQ+Z20
4637        let pia_segs = ctx.find_segments("PIA");
4638        let found = pia_segs.iter().any(|s| {
4639            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
4640                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4641                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8.") || v.contains(":1.29."))
4642                })
4643        });
4644        ConditionResult::from(found)
4645    }
4646
4647    /// [279] Wenn STS+7++xxx+ZW4 / ZAP (Transaktionsgrundergänzung  verbrauchende Marktlokation / ruhende Marktlokation) vorhanden
4648    fn evaluate_279(&self, ctx: &EvaluationContext) -> ConditionResult {
4649        let sts_segs = ctx.find_segments("STS");
4650        let found = sts_segs.iter().any(|s| {
4651            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
4652                && s.elements.get(3).and_then(|e| e.first())
4653                    .is_some_and(|v| ["ZW4", "ZAP"].contains(&v.as_str()))
4654        });
4655        ConditionResult::from(found)
4656    }
4657
4658    /// [280] Nur MP-ID aus Sparte Strom
4659    fn evaluate_280(&self, ctx: &EvaluationContext) -> ConditionResult {
4660        // Check: Marktpartner-ID is from Sparte Strom
4661        // Approximate: check NAD+MS C082 for Strom MP-ID format
4662        ctx.external.evaluate("sector_check")
4663    }
4664
4665    /// [282] Wenn in diesem PIA der Code im DE7140 1-01-6-005, 1-01-9-001/002, 1-07-3-001, 1- 08-1-001, 1-08-3-001, 1-08-4-001/002/003/004, 1-10-3-001 enthalten ist
4666    fn evaluate_282(&self, ctx: &EvaluationContext) -> ConditionResult {
4667        // Check: PIA DE7140 has one of the specific codes
4668        let pia_segs = ctx.find_segments("PIA");
4669        let found = pia_segs.iter().any(|s| {
4670            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4671                v.starts_with("1-01-6-005") || v.starts_with("1-01-9-001") || v.starts_with("1-01-9-002")
4672                    || v.starts_with("1-07-3-001") || v.starts_with("1-08-1-001")
4673                    || v.starts_with("1-08-3-001") || v.starts_with("1-08-4-001")
4674                    || v.starts_with("1-08-4-002") || v.starts_with("1-08-4-003")
4675                    || v.starts_with("1-08-5")
4676            })
4677        });
4678        ConditionResult::from(found)
4679    }
4680
4681    /// [284] Erlaubte Codes aus der Codeliste der Gruppenartikel- und Artikel-ID sind in der Spalte UTILMD/Codeverwendung mit X gekennzeichnet
4682    fn evaluate_284(&self, _ctx: &EvaluationContext) -> ConditionResult {
4683        // TODO: implement
4684        ConditionResult::Unknown
4685    }
4686
4687    /// [285] Wenn in diesem PIA der Code im DE7140 mit 1-08-3-AGS angegeben ist
4688    fn evaluate_285(&self, ctx: &EvaluationContext) -> ConditionResult {
4689        // Check: PIA DE7140 starts with 1-08-3-AGS
4690        let pia_segs = ctx.find_segments("PIA");
4691        let found = pia_segs.iter().any(|s| {
4692            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v.contains("1-08-3") && v.contains("AGS"))
4693        });
4694        ConditionResult::from(found)
4695    }
4696
4697    /// [286] Wenn in diesem PIA der Code im DE7140 mit 1-08-1/2/4/5-AGS-KG
4698    fn evaluate_286(&self, ctx: &EvaluationContext) -> ConditionResult {
4699        // Check: PIA DE7140 matches 1-08-1/2/4/5-AGS-KG pattern
4700        let pia_segs = ctx.find_segments("PIA");
4701        let found = pia_segs.iter().any(|s| {
4702            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4703                (v.starts_with("1-08-1") || v.starts_with("1-08-2")
4704                    || v.starts_with("1-08-4") || v.starts_with("1-08-5"))
4705                    && v.contains("AGS") && v.contains("KG")
4706            })
4707        });
4708        ConditionResult::from(found)
4709    }
4710
4711    /// [287] Erlaubte Codes aus der PRICAT BGM+ Z70 (Preisblatt Netznutzung) des verantwortlichen NB
4712    fn evaluate_287(&self, _ctx: &EvaluationContext) -> ConditionResult {
4713        // TODO: implement
4714        ConditionResult::Unknown
4715    }
4716
4717    /// [288] Wenn in derselben SG8 (OBIS-Daten der Marktlokation) das PIA+5+1-b?:2.9.e vorhanden
4718    fn evaluate_288(&self, ctx: &EvaluationContext) -> ConditionResult {
4719        // Check: PIA+5 has OBIS code matching 1-?:2.9.? pattern
4720        let pia_segs = ctx.find_segments("PIA");
4721        let found = pia_segs.iter().any(|s| {
4722            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
4723                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
4724                    v.contains(":2.9.") && v.starts_with("1-")
4725                })
4726        });
4727        ConditionResult::from(found)
4728    }
4729
4730    /// [291] Wenn in derselben SG8 (Zuordnung Lokation zum Objektcode des Lokationsbündels) das RFF+Z37 vorhanden
4731    fn evaluate_291(&self, ctx: &EvaluationContext) -> ConditionResult {
4732        let rff_segs = ctx.find_segments("RFF");
4733        let found = rff_segs.iter().any(|s| {
4734            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z37")
4735        });
4736        ConditionResult::from(found)
4737    }
4738
4739    /// [292] Es sind nur die Produkt-Codes erlaubt, die in der Codeliste der Konfigurationen im Kapitel 6.1 \"Anmeldung einer Zuordnung des LFN (UTILMD)\" in der Spalte \"Anmeldung einer Zuordnung des LFN (UTIL...
4740    fn evaluate_292(&self, ctx: &EvaluationContext) -> ConditionResult {
4741        ctx.external.evaluate("code_list_membership_check")
4742    }
4743
4744    /// [293] Wenn SG5 LOC+Z22 (ruhende Marktlokation) vorhanden
4745    fn evaluate_293(&self, ctx: &EvaluationContext) -> ConditionResult {
4746        let loc_segs = ctx.find_segments("LOC");
4747        let found = loc_segs.iter().any(|s| {
4748            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z22")
4749        });
4750        ConditionResult::from(found)
4751    }
4752
4753    /// [294] Wenn SG5 LOC+Z18 (Netzlokation) vorhanden
4754    fn evaluate_294(&self, ctx: &EvaluationContext) -> ConditionResult {
4755        let loc_segs = ctx.find_segments("LOC");
4756        let found = loc_segs.iter().any(|s| {
4757            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z18")
4758        });
4759        ConditionResult::from(found)
4760    }
4761
4762    /// [295] Wenn SG5 LOC+Z15 (MaBiS-Zählpunkt) nicht vorhanden
4763    fn evaluate_295(&self, ctx: &EvaluationContext) -> ConditionResult {
4764        let loc_segs = ctx.find_segments("LOC");
4765        let found = loc_segs.iter().any(|s| {
4766            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z15")
4767        });
4768        ConditionResult::from(!found)
4769    }
4770
4771    /// [296] Wenn SG5 LOC+Z20 (Technische Ressource) vorhanden
4772    fn evaluate_296(&self, ctx: &EvaluationContext) -> ConditionResult {
4773        let loc_segs = ctx.find_segments("LOC");
4774        let found = loc_segs.iter().any(|s| {
4775            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z20")
4776        });
4777        ConditionResult::from(found)
4778    }
4779
4780    /// [297] #kv# Wenn SG5 LOC+Z18 (Netzlokation) nicht vorhanden
4781    fn evaluate_297(&self, ctx: &EvaluationContext) -> ConditionResult {
4782        let loc_segs = ctx.find_segments("LOC");
4783        let found = loc_segs.iter().any(|s| {
4784            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z18")
4785        });
4786        ConditionResult::from(!found)
4787    }
4788
4789    /// [298] Wenn SG5 LOC+Z20 (Technische Ressource) nicht vorhanden
4790    fn evaluate_298(&self, ctx: &EvaluationContext) -> ConditionResult {
4791        let loc_segs = ctx.find_segments("LOC");
4792        let found = loc_segs.iter().any(|s| {
4793            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z20")
4794        });
4795        ConditionResult::from(!found)
4796    }
4797
4798    /// [299] #kv# Wenn SG5 LOC+Z19 (Steuerbare Ressource) nicht vorhanden
4799    fn evaluate_299(&self, ctx: &EvaluationContext) -> ConditionResult {
4800        let loc_segs = ctx.find_segments("LOC");
4801        let found = loc_segs.iter().any(|s| {
4802            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z19")
4803        });
4804        ConditionResult::from(!found)
4805    }
4806
4807    /// [300] Wenn SG8 SEQ+Z15/ ZE7 (Daten der Tranche) nicht vorhanden
4808    fn evaluate_300(&self, ctx: &EvaluationContext) -> ConditionResult {
4809        let seq_segs = ctx.find_segments("SEQ");
4810        let found = seq_segs.iter().any(|s| {
4811            s.elements.first().and_then(|e| e.first())
4812                .is_some_and(|v| ["Z15", "ZE7"].contains(&v.as_str()))
4813        });
4814        ConditionResult::from(!found)
4815    }
4816
4817    /// [301] Wenn BGM+E03 (Änderungsmeldung) vorhanden
4818    fn evaluate_301(&self, ctx: &EvaluationContext) -> ConditionResult {
4819        let bgm_segs = ctx.find_segments("BGM");
4820        let found = bgm_segs.iter().any(|s| {
4821            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E03")
4822        });
4823        ConditionResult::from(found)
4824    }
4825
4826    /// [302] Wenn SG8 SEQ+Z08 (Profilschardaten) nicht vorhanden
4827    fn evaluate_302(&self, ctx: &EvaluationContext) -> ConditionResult {
4828        let seq_segs = ctx.find_segments("SEQ");
4829        let found = seq_segs.iter().any(|s| {
4830            s.elements.first().and_then(|e| e.first())
4831                .is_some_and(|v| ["Z08"].contains(&v.as_str()))
4832        });
4833        ConditionResult::from(!found)
4834    }
4835
4836    /// [303] Wenn SG8 SEQ+Z21 (Profildaten) nicht vorhanden
4837    fn evaluate_303(&self, ctx: &EvaluationContext) -> ConditionResult {
4838        let seq_segs = ctx.find_segments("SEQ");
4839        let found = seq_segs.iter().any(|s| {
4840            s.elements.first().and_then(|e| e.first())
4841                .is_some_and(|v| ["Z21"].contains(&v.as_str()))
4842        });
4843        ConditionResult::from(!found)
4844    }
4845
4846    /// [304] Wenn SG8 SEQ+Z22 (Daten der Summenzeitreihe) vorhanden
4847    fn evaluate_304(&self, ctx: &EvaluationContext) -> ConditionResult {
4848        let seq_segs = ctx.find_segments("SEQ");
4849        let found = seq_segs.iter().any(|s| {
4850            s.elements.first().and_then(|e| e.first())
4851                .is_some_and(|v| ["Z22"].contains(&v.as_str()))
4852        });
4853        ConditionResult::from(found)
4854    }
4855
4856    /// [305] Wenn SG8 SEQ+Z24 (Daten der Überführungszeitreihe) vorhanden
4857    fn evaluate_305(&self, ctx: &EvaluationContext) -> ConditionResult {
4858        let seq_segs = ctx.find_segments("SEQ");
4859        let found = seq_segs.iter().any(|s| {
4860            s.elements.first().and_then(|e| e.first())
4861                .is_some_and(|v| ["Z24"].contains(&v.as_str()))
4862        });
4863        ConditionResult::from(found)
4864    }
4865
4866    /// [306] Wenn SG5 LOC+Z22 (ruhende Marktlokation) mit derselben Zeitraum-ID im DE3224 vorhanden wie in dieser SG8 im DE1050 (Referenz auf Zeitraum-ID) des SEQ+Z58
4867    fn evaluate_306(&self, ctx: &EvaluationContext) -> ConditionResult {
4868        use std::collections::HashSet;
4869        // Collect Zeitraum-IDs from SG5 LOC+Z22 (Ruhende Marktlokation) — DE3224 at elements[1][3]
4870        let loc_z22_ids: HashSet<String> = ctx
4871            .find_segments_with_qualifier("LOC", 0, "Z22")
4872            .into_iter()
4873            .filter_map(|s| s.elements.get(1)?.get(3).cloned())
4874            .filter(|v| !v.is_empty())
4875            .collect();
4876        if loc_z22_ids.is_empty() {
4877            return ConditionResult::False;
4878        }
4879        // Check if any SG8 SEQ+Z58 has DE1050 (elements[1][0]) matching a LOC+Z22 DE3224
4880        let has_match = ctx
4881            .find_segments_with_qualifier("SEQ", 0, "Z58")
4882            .iter()
4883            .any(|s| {
4884                s.elements
4885                    .get(1)
4886                    .and_then(|e: &Vec<String>| e.first())
4887                    .is_some_and(|v: &String| !v.is_empty() && loc_z22_ids.contains(v.as_str()))
4888            });
4889        ConditionResult::from(has_match)
4890    }
4891
4892    /// [307] Wenn SG5 LOC+Z22 (ruhende Marktlokation) mit derselben Zeitraum-ID im DE3224 nicht vorhanden wie in dieser SG8 im DE1050 (Referenz auf Zeitraum-ID) des SEQ+Z58
4893    // REVIEW: Collects Zeitraum-IDs from SG5 LOC+Z22 segments (DE3224 = elements[1][3]) and SEQ+Z58 segments (DE1050 = elements[1][0]). Returns True when any SEQ+Z58 has a Zeitraum-ID with no matching LOC+Z22 entry. Message-wide fallback since group-level Zeitraum-ID isolation is not possible without navigator. (medium confidence)
4894    fn evaluate_307(&self, ctx: &EvaluationContext) -> ConditionResult {
4895        let seq_segs = ctx.find_segments_with_qualifier("SEQ", 0, "Z58");
4896        if seq_segs.is_empty() {
4897            return ConditionResult::Unknown;
4898        }
4899        let loc_segs = ctx.find_segments_with_qualifier("LOC", 0, "Z22");
4900        let loc_z22_zeitraum_ids: Vec<&str> = loc_segs
4901            .iter()
4902            .filter_map(|s| s.elements.get(1).and_then(|e| e.get(3)).map(|v| v.as_str()))
4903            .filter(|v| !v.is_empty())
4904            .collect();
4905        ConditionResult::from(seq_segs.iter().any(|seq| {
4906            let zid = seq
4907                .elements
4908                .get(1)
4909                .and_then(|e: &Vec<String>| e.first())
4910                .map(|v| v.as_str())
4911                .unwrap_or("");
4912            !zid.is_empty() && !loc_z22_zeitraum_ids.contains(&zid)
4913        }))
4914    }
4915
4916    /// [309] Wenn SG5 LOC+Z22 (ruhende Marktlokation) nicht vorhanden
4917    fn evaluate_309(&self, ctx: &EvaluationContext) -> ConditionResult {
4918        let loc_segs = ctx.find_segments("LOC");
4919        let found = loc_segs.iter().any(|s| {
4920            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z22")
4921        });
4922        ConditionResult::from(!found)
4923    }
4924
4925    /// [314] Es sind alle OBIS-Kennzahlen gem. Codeliste der OBIS-Kennzahlen und Medien Kapitel 3 anzugeben welche an der Marktlokation erforderlich sind. Der Mindestumfang der OBIS-Kennzahlen ergibt sich aus d...
4926    fn evaluate_314(&self, ctx: &EvaluationContext) -> ConditionResult {
4927        ctx.external.evaluate("code_list_membership_check")
4928    }
4929
4930    /// [315] Wenn BGM+Z88 (Datenclearing) vorhanden
4931    fn evaluate_315(&self, ctx: &EvaluationContext) -> ConditionResult {
4932        ctx.external.evaluate("data_clearing_required")
4933    }
4934
4935    /// [316] Wenn in derselben SG8 das RFF+Z14 (Smartmeter-Gateway) nicht vorhanden
4936    fn evaluate_316(&self, ctx: &EvaluationContext) -> ConditionResult {
4937        ctx.any_group_has_qualifier_without("SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"])
4938    }
4939
4940    /// [317] Es ist derselbe Wert wie im DE2380 von DTM+92 (Datum Vertragsbeginn) einzutragen
4941    fn evaluate_317(&self, ctx: &EvaluationContext) -> ConditionResult {
4942        // Check: DTM+92 (Datum Vertragsbeginn) exists — value identity is structural
4943        let found = !ctx.find_segments_with_qualifier("DTM", 0, "92").is_empty();
4944        if found { ConditionResult::True } else { ConditionResult::Unknown }
4945    }
4946
4947    /// [318] Es ist derselbe Wert wie im DE2380 von DTM+93 (Datum Vertragende) einzutragen
4948    fn evaluate_318(&self, ctx: &EvaluationContext) -> ConditionResult {
4949        // Check: DTM+93 (Datum Vertragende) exists — value identity is structural
4950        let found = !ctx.find_segments_with_qualifier("DTM", 0, "93").is_empty();
4951        if found { ConditionResult::True } else { ConditionResult::Unknown }
4952    }
4953
4954    /// [321] Wenn im DE3155 in demselben COM der Code EM vorhanden ist
4955    fn evaluate_321(&self, ctx: &EvaluationContext) -> ConditionResult {
4956        let com_segs = ctx.find_segments("COM");
4957        let has_em = com_segs.iter().any(|s| {
4958            s.elements.first()
4959                .and_then(|e| e.get(1))
4960                .is_some_and(|v| v == "EM")
4961        });
4962        ConditionResult::from(has_em)
4963    }
4964
4965    /// [322] Wenn im DE3155 in demselben COM der Code TE / FX / AJ / AL vorhanden ist
4966    fn evaluate_322(&self, ctx: &EvaluationContext) -> ConditionResult {
4967        let com_segs = ctx.find_segments("COM");
4968        let has_phone = com_segs.iter().any(|s| {
4969            s.elements.first()
4970                .and_then(|e| e.get(1))
4971                .is_some_and(|v| matches!(v.as_str(), "TE" | "FX" | "AJ" | "AL"))
4972        });
4973        ConditionResult::from(has_phone)
4974    }
4975
4976    /// [323] Es sind alle OBIS-Kennzahlen gem. EDI@Energy Codeliste der OBIS-Kennzahlen und Medien für den deutschen Energiemarkt Kap. 3. anzugeben, welche an der Zähleinrichtung genutzt werden. Der Mindestum...
4977    fn evaluate_323(&self, ctx: &EvaluationContext) -> ConditionResult {
4978        ctx.external.evaluate("code_list_membership_check")
4979    }
4980
4981    /// [327] Wenn die Zeitraum-ID im DE1050 dieser SG8 SEQ, welche mit der Zeitraum-ID einer SG6 RFF+Z47/Z48/Z49 (Verwendungszeitraum der Daten) identisch ist und in deren SG das SG6 DTM+Z25 (Verwendung der Dat...
4982    // REVIEW: Step 1: Collect all SEQ DE1050 Zeitraum-IDs. Step 2: Find RFF+Z47/Z48/Z49 (Verwendungszeitraum) whose DE1156 (elements[0][2]) matches. Step 3: Check co-located DTM+Z25 DE2380 (elements[0][1]) >= threshold after normalising EDIFACT escape '?+' to '+'. Falls back to message-wide DTM search which may give false positives if multiple SG6 groups are present, but is sufficient for typical single-transaction messages. (medium confidence)
4983    fn evaluate_327(&self, ctx: &EvaluationContext) -> ConditionResult {
4984        const THRESHOLD: &str = "202212312300+00";
4985        let seq_zeitraum_ids: Vec<String> = ctx
4986            .find_segments("SEQ")
4987            .iter()
4988            .filter_map(|s| {
4989                s.elements
4990                    .get(1)
4991                    .and_then(|e: &Vec<String>| e.first())
4992                    .cloned()
4993            })
4994            .filter(|v| !v.is_empty())
4995            .collect();
4996        if seq_zeitraum_ids.is_empty() {
4997            return ConditionResult::Unknown;
4998        }
4999        let rff_segs = ctx.find_segments("RFF");
5000        let matching_rff = rff_segs.iter().any(|rff| {
5001            let qual = rff
5002                .elements
5003                .first()
5004                .and_then(|e: &Vec<String>| e.first())
5005                .map(|v| v.as_str())
5006                .unwrap_or("");
5007            if !["Z47", "Z48", "Z49"].contains(&qual) {
5008                return false;
5009            }
5010            let zid = rff
5011                .elements
5012                .first()
5013                .and_then(|e| e.get(2))
5014                .map(|v| v.as_str())
5015                .unwrap_or("");
5016            !zid.is_empty() && seq_zeitraum_ids.iter().any(|id| id.as_str() == zid)
5017        });
5018        if !matching_rff {
5019            return ConditionResult::False;
5020        }
5021        for dtm in ctx.find_segments_with_qualifier("DTM", 0, "Z25") {
5022            let val = dtm
5023                .elements
5024                .first()
5025                .and_then(|e| e.get(1))
5026                .map(|v| v.replace("?+", "+"))
5027                .unwrap_or_default();
5028            if !val.is_empty() && val.as_str() >= THRESHOLD {
5029                return ConditionResult::True;
5030            }
5031        }
5032        ConditionResult::False
5033    }
5034
5035    /// [329] Wenn in dieser SG4 IDE+24 das STS+E01++A03: E_0096 bzw. A04:E_0097 (Status der Antwort) nicht vorhanden
5036    fn evaluate_329(&self, ctx: &EvaluationContext) -> ConditionResult {
5037        // Check: STS+E01 does NOT have A03 with E_0096 or A04 with E_0097
5038        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5039        let has_a03_e0096 = sts_segs.iter().any(|s| {
5040            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "A03")
5041                && s.elements.get(2).and_then(|e| e.get(1)).is_some_and(|v| v == "E_0096")
5042        });
5043        let has_a04_e0097 = sts_segs.iter().any(|s| {
5044            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "A04")
5045                && s.elements.get(2).and_then(|e| e.get(1)).is_some_and(|v| v == "E_0097")
5046        });
5047        ConditionResult::from(!has_a03_e0096 && !has_a04_e0097)
5048    }
5049
5050    /// [331] Wenn im SG8 SEQ+Z98 (Daten der Marktlokation) das SG10 CCI+6++ZA9 (Aggreg. verantw. ÜNB) nicht vorhanden
5051    fn evaluate_331(&self, ctx: &EvaluationContext) -> ConditionResult {
5052        let seq_segs = ctx.find_segments("SEQ");
5053        let has_seq = seq_segs.iter().any(|s| {
5054            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z98")
5055        });
5056        let cci_segs = ctx.find_segments("CCI");
5057        let has_cci = cci_segs.iter().any(|s| {
5058            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "6")
5059                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA9")
5060        });
5061        ConditionResult::from(!(has_seq && has_cci))
5062    }
5063
5064    /// [332] Wenn im SG8 SEQ+Z01 (Daten der Marktlokation) mit identischer Zeitraum-ID im DE1050 wie in dieser SG8, das SG10 CCI+6++ZA9 (Aggreg. verantw. ÜNB) nicht vorhanden
5065    // REVIEW: Checks whether any SG8 instance lacks CCI+6++ZA9 (Aggregationsverantwortung ÜNB, elements[0]='6' and elements[2][0]='ZA9') in its SG10 children. With navigator: iterates SG8 instances and their SG10 children. Without navigator: falls back to message-wide CCI+6 with ZA9 check. The Zeitraum-ID cross-reference between this SG8 and the Z01 SG8 cannot be fully verified without direct SG8-level segment access via navigator, so this is an approximation that may produce false positives in multi-SG4-group messages. (medium confidence)
5066    fn evaluate_332(&self, ctx: &EvaluationContext) -> ConditionResult {
5067        let nav = match ctx.navigator {
5068            Some(n) => n,
5069            None => {
5070                if ctx.find_segments_with_qualifier("SEQ", 0, "Z01").is_empty() {
5071                    return ConditionResult::Unknown;
5072                }
5073                let has_cci_za9 = ctx
5074                    .find_segments_with_qualifier("CCI", 0, "6")
5075                    .iter()
5076                    .any(|s| {
5077                        s.elements
5078                            .get(2)
5079                            .and_then(|e: &Vec<String>| e.first())
5080                            .map(|v| v.as_str())
5081                            == Some("ZA9")
5082                    });
5083                return ConditionResult::from(!has_cci_za9);
5084            }
5085        };
5086        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5087        if sg8_count == 0 {
5088            return ConditionResult::Unknown;
5089        }
5090        for sg8_idx in 0..sg8_count {
5091            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], sg8_idx, "SG10");
5092            let mut has_cci_za9 = false;
5093            for sg10_idx in 0..sg10_count {
5094                let ccis = nav.find_segments_in_child_group(
5095                    "CCI",
5096                    &["SG4", "SG8"],
5097                    sg8_idx,
5098                    "SG10",
5099                    sg10_idx,
5100                );
5101                if ccis.iter().any(|s| {
5102                    s.elements
5103                        .first()
5104                        .and_then(|e: &Vec<String>| e.first())
5105                        .map(|v| v.as_str())
5106                        == Some("6")
5107                        && s.elements
5108                            .get(2)
5109                            .and_then(|e: &Vec<String>| e.first())
5110                            .map(|v| v.as_str())
5111                            == Some("ZA9")
5112                }) {
5113                    has_cci_za9 = true;
5114                    break;
5115                }
5116            }
5117            if !has_cci_za9 {
5118                return ConditionResult::True;
5119            }
5120        }
5121        ConditionResult::False
5122    }
5123
5124    /// [333] Wenn in diesem RFF \"Referenz auf die Lokationsbündelstruktur\" im DE1153 der Code Z31 \"Lokationsbündelstruktur\" vorhanden ist
5125    fn evaluate_333(&self, ctx: &EvaluationContext) -> ConditionResult {
5126        let rff_segs = ctx.find_segments("RFF");
5127        let found = rff_segs.iter().any(|s| {
5128            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z31")
5129        });
5130        ConditionResult::from(found)
5131    }
5132
5133    /// [334] Nur MP-ID aus Sparte Gas
5134    fn evaluate_334(&self, ctx: &EvaluationContext) -> ConditionResult {
5135        // Check: Marktpartner-ID is from Sparte Gas
5136        ctx.external.evaluate("sector_check")
5137    }
5138
5139    /// [335] Wenn in dieser SG8 im SEQ+Z58 (Zuordnung Lokation zum Objektcode des Lokationsbündels) im DE1050 eine Zeitraum-ID angegeben wird, wie in einer SG8 SEQ+Z78 RFF+Z31 (Referenz auf die Lokationsbünde...
5140    // REVIEW: Collects Zeitraum-IDs from SEQ+Z58 DE1050 (elements[1][0]). Verifies an SG8 with SEQ+Z78 exists (entry for Lokationsbündelstruktur). Collects IDs from RFF+Z31 DE1154 (elements[0][1]) and checks if any SEQ+Z58 Zeitraum-ID matches. Co-location of RFF+Z31 with SEQ+Z78 in the same SG8 instance is approximated message-wide; exact co-location verification would require navigator SG8-level segment access. (medium confidence)
5141    fn evaluate_335(&self, ctx: &EvaluationContext) -> ConditionResult {
5142        let z58_ids: Vec<String> = ctx
5143            .find_segments_with_qualifier("SEQ", 0, "Z58")
5144            .iter()
5145            .filter_map(|s| {
5146                s.elements
5147                    .get(1)
5148                    .and_then(|e: &Vec<String>| e.first())
5149                    .cloned()
5150            })
5151            .filter(|v| !v.is_empty())
5152            .collect();
5153        if z58_ids.is_empty() {
5154            return ConditionResult::Unknown;
5155        }
5156        if ctx.find_segments_with_qualifier("SEQ", 0, "Z78").is_empty() {
5157            return ConditionResult::False;
5158        }
5159        let rff_z31_ids: Vec<String> = ctx
5160            .find_segments("RFF")
5161            .iter()
5162            .filter(|rff| {
5163                rff.elements
5164                    .first()
5165                    .and_then(|e: &Vec<String>| e.first())
5166                    .map(|v| v.as_str())
5167                    == Some("Z31")
5168            })
5169            .filter_map(|rff| rff.elements.first().and_then(|e| e.get(1)).cloned())
5170            .filter(|v| !v.is_empty())
5171            .collect();
5172        ConditionResult::from(z58_ids.iter().any(|id| rff_z31_ids.contains(id)))
5173    }
5174
5175    /// [336] Wenn in Änderungsmeldung gefüllt
5176    fn evaluate_336(&self, _ctx: &EvaluationContext) -> ConditionResult {
5177        // TODO: implement
5178        ConditionResult::Unknown
5179    }
5180
5181    /// [337] Wenn SG10 CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z96 vorhanden
5182    fn evaluate_337(&self, ctx: &EvaluationContext) -> ConditionResult {
5183        let cci_segs = ctx.find_segments("CCI");
5184        let has_cci = cci_segs.iter().any(|s| {
5185            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5186        });
5187        let cav_segs = ctx.find_segments("CAV");
5188        let has_cav = cav_segs.iter().any(|s| {
5189            s.elements.first().and_then(|e| e.first())
5190                .is_some_and(|v| ["Z95", "Z96"].contains(&v.as_str()))
5191        });
5192        ConditionResult::from(has_cci && has_cav)
5193    }
5194
5195    /// [338] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z96/ Z97/ Z99/ ZA1/ ZA3/ ZA4/ZG7 vorhanden
5196    fn evaluate_338(&self, ctx: &EvaluationContext) -> ConditionResult {
5197        let cci_segs = ctx.find_segments("CCI");
5198        let has_cci = cci_segs.iter().any(|s| {
5199            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5200        });
5201        let cav_segs = ctx.find_segments("CAV");
5202        let has_cav = cav_segs.iter().any(|s| {
5203            s.elements.first().and_then(|e| e.first())
5204                .is_some_and(|v| ["Z95", "Z96", "Z97", "Z99", "ZA1", "ZA3", "ZA4", "ZG7"].contains(&v.as_str()))
5205        });
5206        ConditionResult::from(has_cci && has_cav)
5207    }
5208
5209    /// [339] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z97/ Z98/ Z99/ ZA0/ ZA1/ ZA2/ ZA3/ ZA6/ ZG7 vorhanden
5210    fn evaluate_339(&self, ctx: &EvaluationContext) -> ConditionResult {
5211        let cci_segs = ctx.find_segments("CCI");
5212        let has_cci = cci_segs.iter().any(|s| {
5213            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5214        });
5215        let cav_segs = ctx.find_segments("CAV");
5216        let has_cav = cav_segs.iter().any(|s| {
5217            s.elements.first().and_then(|e| e.first())
5218                .is_some_and(|v| ["Z97", "Z98", "Z99", "ZA0", "ZA1", "ZA2", "ZA3", "ZA6", "ZG7"].contains(&v.as_str()))
5219        });
5220        ConditionResult::from(has_cci && has_cav)
5221    }
5222
5223    /// [340] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z95/ Z97/ Z98/ Z99/ ZA1/ ZA2/ ZA3/ ZA4/ ZA5/ ZA6 vorhanden
5224    fn evaluate_340(&self, ctx: &EvaluationContext) -> ConditionResult {
5225        let cci_segs = ctx.find_segments("CCI");
5226        let has_cci = cci_segs.iter().any(|s| {
5227            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5228        });
5229        let cav_segs = ctx.find_segments("CAV");
5230        let has_cav = cav_segs.iter().any(|s| {
5231            s.elements.first().and_then(|e| e.first())
5232                .is_some_and(|v| ["Z95", "Z97", "Z98", "Z99", "ZA1", "ZA2", "ZA3", "ZA4", "ZA5", "ZA6"].contains(&v.as_str()))
5233        });
5234        ConditionResult::from(has_cci && has_cav)
5235    }
5236
5237    /// [341] Wenn CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+Z96/ ZA0/ ZG7 vorhanden
5238    fn evaluate_341(&self, ctx: &EvaluationContext) -> ConditionResult {
5239        let cci_segs = ctx.find_segments("CCI");
5240        let has_cci = cci_segs.iter().any(|s| {
5241            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5242        });
5243        let cav_segs = ctx.find_segments("CAV");
5244        let has_cav = cav_segs.iter().any(|s| {
5245            s.elements.first().and_then(|e| e.first())
5246                .is_some_and(|v| ["Z96", "ZA0", "ZG7"].contains(&v.as_str()))
5247        });
5248        ConditionResult::from(has_cci && has_cav)
5249    }
5250
5251    /// [342] Wenn aktiver MaBiS-ZP für den Betrachtungszeitraum vorhanden
5252    fn evaluate_342(&self, _ctx: &EvaluationContext) -> ConditionResult {
5253        // TODO: implement
5254        ConditionResult::Unknown
5255    }
5256
5257    /// [344] Wenn in dieser SG8 das SG10 CCI+++ZB4 (Bezeichnung der Summenzeitreihe) CAV+ZF1 (Netzgangzeitreihe (NGZ)) vorhanden
5258    fn evaluate_344(&self, ctx: &EvaluationContext) -> ConditionResult {
5259        let cci_segs = ctx.find_segments("CCI");
5260        let has_cci = cci_segs.iter().any(|s| {
5261            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZB4")
5262        });
5263        let cav_segs = ctx.find_segments("CAV");
5264        let has_cav = cav_segs.iter().any(|s| {
5265            s.elements.first().and_then(|e| e.first())
5266                .is_some_and(|v| ["ZF1"].contains(&v.as_str()))
5267        });
5268        ConditionResult::from(has_cci && has_cav)
5269    }
5270
5271    /// [345] Wenn SG5 LOC+Z17 (Messlokation) vorhanden
5272    fn evaluate_345(&self, ctx: &EvaluationContext) -> ConditionResult {
5273        let loc_segs = ctx.find_segments("LOC");
5274        let found = loc_segs.iter().any(|s| {
5275            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
5276        });
5277        ConditionResult::from(found)
5278    }
5279
5280    /// [346] Wenn SG10 CCI+++E13 (Zählertyp) CAV+MME (mME) vorhanden
5281    fn evaluate_346(&self, ctx: &EvaluationContext) -> ConditionResult {
5282        let cci_segs = ctx.find_segments("CCI");
5283        let found = cci_segs.iter().any(|s| {
5284            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "E13")
5285        });
5286        ConditionResult::from(found)
5287    }
5288
5289    /// [347] Wenn SG5 LOC+Z16 (Marktlokation) nicht vorhanden
5290    fn evaluate_347(&self, ctx: &EvaluationContext) -> ConditionResult {
5291        let loc_segs = ctx.find_segments("LOC");
5292        let found = loc_segs.iter().any(|s| {
5293            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z16")
5294        });
5295        ConditionResult::from(!found)
5296    }
5297
5298    /// [348] Wenn SG5 LOC+Z21 (Tranche) nicht vorhanden
5299    fn evaluate_348(&self, ctx: &EvaluationContext) -> ConditionResult {
5300        let loc_segs = ctx.find_segments("LOC");
5301        let found = loc_segs.iter().any(|s| {
5302            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z21")
5303        });
5304        ConditionResult::from(!found)
5305    }
5306
5307    /// [349] Wenn SG5 LOC+Z17 (Messlokation) nicht vorhanden
5308    fn evaluate_349(&self, ctx: &EvaluationContext) -> ConditionResult {
5309        let loc_segs = ctx.find_segments("LOC");
5310        let found = loc_segs.iter().any(|s| {
5311            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
5312        });
5313        ConditionResult::from(!found)
5314    }
5315
5316    /// [350] Wenn SG8 SEQ+Z78/ZD5 RFF+Z31 (Referenz auf die Lokationsbündelstruktur) vorhanden
5317    fn evaluate_350(&self, ctx: &EvaluationContext) -> ConditionResult {
5318        let seq_segs = ctx.find_segments("SEQ");
5319        let has_seq = seq_segs.iter().any(|s| {
5320            s.elements.first().and_then(|e| e.first())
5321                .is_some_and(|v| ["Z78", "ZD5"].contains(&v.as_str()))
5322        });
5323        let rff_segs = ctx.find_segments("RFF");
5324        let has_rff = rff_segs.iter().any(|s| {
5325            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z31")
5326        });
5327        ConditionResult::from(has_seq && has_rff)
5328    }
5329
5330    /// [351] Wenn SG4 STS+E01++A04/ A05 /A13 /A14 (Status der Antwort) vorhanden
5331    fn evaluate_351(&self, ctx: &EvaluationContext) -> ConditionResult {
5332        let sts_segs = ctx.find_segments("STS");
5333        let found = sts_segs.iter().any(|s| {
5334            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5335                && s.elements.get(2).and_then(|e| e.first())
5336                    .is_some_and(|v| ["A04", "A05", "A13", "A14"].contains(&v.as_str()))
5337        });
5338        ConditionResult::from(found)
5339    }
5340
5341    /// [352] Wenn SG4 STS++A05/ A06/ A14 /A15 (Status der Antwort) vorhanden
5342    fn evaluate_352(&self, ctx: &EvaluationContext) -> ConditionResult {
5343        let sts_segs = ctx.find_segments("STS");
5344        let found = sts_segs.iter().any(|s| {
5345            s.elements.get(1).and_then(|e| e.first())
5346                .is_some_and(|v| ["A05", "A06", "A14", "A15"].contains(&v.as_str()))
5347        });
5348        ConditionResult::from(found)
5349    }
5350
5351    /// [355] Wenn SG4 STS+E01++A45 (Status der Antwort) vorhanden
5352    fn evaluate_355(&self, ctx: &EvaluationContext) -> ConditionResult {
5353        let sts_segs = ctx.find_segments("STS");
5354        let found = sts_segs.iter().any(|s| {
5355            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5356                && s.elements.get(2).and_then(|e| e.first())
5357                    .is_some_and(|v| ["A45"].contains(&v.as_str()))
5358        });
5359        ConditionResult::from(found)
5360    }
5361
5362    /// [356] Wenn SG4 STS+E01++A50 (Status der Antwort) vorhanden
5363    fn evaluate_356(&self, ctx: &EvaluationContext) -> ConditionResult {
5364        let sts_segs = ctx.find_segments("STS");
5365        let found = sts_segs.iter().any(|s| {
5366            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5367                && s.elements.get(2).and_then(|e| e.first())
5368                    .is_some_and(|v| ["A50"].contains(&v.as_str()))
5369        });
5370        ConditionResult::from(found)
5371    }
5372
5373    /// [357] Wenn SG4 STS+E01++A03/ A09/ A12/ A17 (Status der Antwort) vorhanden
5374    fn evaluate_357(&self, ctx: &EvaluationContext) -> ConditionResult {
5375        let sts_segs = ctx.find_segments("STS");
5376        let found = sts_segs.iter().any(|s| {
5377            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5378                && s.elements.get(2).and_then(|e| e.first())
5379                    .is_some_and(|v| ["A03", "A09", "A12", "A17"].contains(&v.as_str()))
5380        });
5381        ConditionResult::from(found)
5382    }
5383
5384    /// [358] Wenn SG4 STS+E01++A06 (Status der Antwort) vorhanden
5385    fn evaluate_358(&self, ctx: &EvaluationContext) -> ConditionResult {
5386        let sts_segs = ctx.find_segments("STS");
5387        let found = sts_segs.iter().any(|s| {
5388            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5389                && s.elements.get(2).and_then(|e| e.first())
5390                    .is_some_and(|v| ["A06"].contains(&v.as_str()))
5391        });
5392        ConditionResult::from(found)
5393    }
5394
5395    /// [359] Es sind nur Antwortcodes aus dem Cluster Ablehnung erlaubt
5396    fn evaluate_359(&self, ctx: &EvaluationContext) -> ConditionResult {
5397        // Check: STS+E01 has only Ablehnung (rejection) cluster codes
5398        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5399        if sts_segs.is_empty() {
5400            return ConditionResult::Unknown;
5401        }
5402        let all_rejection = sts_segs.iter().all(|s| {
5403            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| {
5404                // Ablehnung codes: A25-A99 range and specific rejection codes
5405                v.starts_with("A") && v.len() == 3
5406                    && v.as_bytes().get(1).is_some_and(|&b| b >= b'2')
5407            })
5408        });
5409        ConditionResult::from(all_rejection)
5410    }
5411
5412    /// [360] Es sind nur Antwortcodes aus dem Cluster Zustimmung erlaubt
5413    fn evaluate_360(&self, ctx: &EvaluationContext) -> ConditionResult {
5414        // Check: STS+E01 has only Zustimmung (approval) cluster codes
5415        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5416        if sts_segs.is_empty() {
5417            return ConditionResult::Unknown;
5418        }
5419        let all_approval = sts_segs.iter().all(|s| {
5420            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| {
5421                // Zustimmung codes: A01-A17, A25 etc.
5422                ["A01", "A02", "A03", "A04", "A05", "A06", "A07", "A08", "A09", "A10",
5423                 "A11", "A12", "A13", "A14", "A15", "A16", "A17", "A25"].contains(&v.as_str())
5424            })
5425        });
5426        ConditionResult::from(all_approval)
5427    }
5428
5429    /// [363] Wenn SG4 STS+E01++A50 (Status der Antwort) vorhanden
5430    fn evaluate_363(&self, ctx: &EvaluationContext) -> ConditionResult {
5431        let sts_segs = ctx.find_segments("STS");
5432        let found = sts_segs.iter().any(|s| {
5433            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5434                && s.elements.get(2).and_then(|e| e.first())
5435                    .is_some_and(|v| ["A50"].contains(&v.as_str()))
5436        });
5437        ConditionResult::from(found)
5438    }
5439
5440    /// [365] Wenn in dieser SG4 IDE+24 das STS+E01++A04:E_0047/E_0014 bzw. A03:E_0049/E_0004 (Status der Antwort) nicht vorhanden
5441    fn evaluate_365(&self, ctx: &EvaluationContext) -> ConditionResult {
5442        // Check: STS+E01 does NOT have A04 with E_0047/E_0014 or A03 with E_0049/E_0004
5443        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5444        let has_excluded = sts_segs.iter().any(|s| {
5445            let code = s.elements.get(2).and_then(|e| e.first()).map(|v| v.as_str());
5446            let ebd = s.elements.get(2).and_then(|e| e.get(1)).map(|v| v.as_str());
5447            matches!((code, ebd),
5448                (Some("A04"), Some("E_0047")) | (Some("A04"), Some("E_0014"))
5449                | (Some("A03"), Some("E_0049")) | (Some("A03"), Some("E_0004"))
5450            )
5451        });
5452        ConditionResult::from(!has_excluded)
5453    }
5454
5455    /// [366] Bis auf den Code A30 sind alle Codes aus EBD E_0624 im Cluster Ablehnung erlaubt
5456    fn evaluate_366(&self, ctx: &EvaluationContext) -> ConditionResult {
5457        // Check: STS codes from EBD E_0624 in Ablehnung cluster (all except A30)
5458        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5459        if sts_segs.is_empty() {
5460            return ConditionResult::Unknown;
5461        }
5462        let all_valid = sts_segs.iter().all(|s| {
5463            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v != "A30")
5464        });
5465        ConditionResult::from(all_valid)
5466    }
5467
5468    /// [367] Wenn SG4 STS+E01++A05/ A14 (Status der Antwort) vorhanden
5469    fn evaluate_367(&self, ctx: &EvaluationContext) -> ConditionResult {
5470        let sts_segs = ctx.find_segments("STS");
5471        let found = sts_segs.iter().any(|s| {
5472            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
5473                && s.elements.get(2).and_then(|e| e.first())
5474                    .is_some_and(|v| ["A05", "A14"].contains(&v.as_str()))
5475        });
5476        ConditionResult::from(found)
5477    }
5478
5479    /// [368] Bis auf den Code A41 sind alle Codes aus EBD E_0624 im Cluster Ablehnung erlaubt
5480    fn evaluate_368(&self, ctx: &EvaluationContext) -> ConditionResult {
5481        // Check: STS codes from EBD E_0624 in Ablehnung cluster (all except A41)
5482        let sts_segs = ctx.find_segments_with_qualifier("STS", 0, "E01");
5483        if sts_segs.is_empty() {
5484            return ConditionResult::Unknown;
5485        }
5486        let all_valid = sts_segs.iter().all(|s| {
5487            s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v != "A41")
5488        });
5489        ConditionResult::from(all_valid)
5490    }
5491
5492    /// [370] Wenn SG10 CAV+TLS/TES/BIT/GET/GAT/SOT/WNT/WFT/WAT
5493    fn evaluate_370(&self, ctx: &EvaluationContext) -> ConditionResult {
5494        let cav_segs = ctx.find_segments("CAV");
5495        let found = cav_segs.iter().any(|s| {
5496            s.elements.first().and_then(|e| e.first())
5497                .is_some_and(|v| ["TLS", "TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT"].contains(&v.as_str()))
5498        });
5499        ConditionResult::from(found)
5500    }
5501
5502    /// [371] Wenn SG8 SEQ+Z38 (Referenzprofildaten) nicht vorhanden
5503    fn evaluate_371(&self, ctx: &EvaluationContext) -> ConditionResult {
5504        let seq_segs = ctx.find_segments("SEQ");
5505        let found = seq_segs.iter().any(|s| {
5506            s.elements.first().and_then(|e| e.first())
5507                .is_some_and(|v| ["Z38"].contains(&v.as_str()))
5508        });
5509        ConditionResult::from(!found)
5510    }
5511
5512    /// [372] Wenn SG10 CAV+TES/BIT/GET/GAT/SOT/WNT/WFT/WAT vorhanden
5513    fn evaluate_372(&self, ctx: &EvaluationContext) -> ConditionResult {
5514        let cav_segs = ctx.find_segments("CAV");
5515        let found = cav_segs.iter().any(|s| {
5516            s.elements.first().and_then(|e| e.first())
5517                .is_some_and(|v| ["TES", "BIT", "GET", "GAT", "SOT", "WNT", "WFT", "WAT"].contains(&v.as_str()))
5518        });
5519        ConditionResult::from(found)
5520    }
5521
5522    /// [373] Wenn ein Referenzprofil an der Marktlokation vorhanden ist
5523    fn evaluate_373(&self, _ctx: &EvaluationContext) -> ConditionResult {
5524        // TODO: implement
5525        ConditionResult::Unknown
5526    }
5527
5528    /// [375] Für die ID im SG5 LOC+Z15 (MaBiS-Zählpunkt) DE3225, wenn SG8+Z24 (Daten der Überführungszeitreihe) nicht vorhanden
5529    fn evaluate_375(&self, ctx: &EvaluationContext) -> ConditionResult {
5530        // Check: no SG8 SEQ+Z24 (Daten der Überführungszeitreihe) exists
5531        ctx.lacks_qualifier("SEQ", 0, "Z24")
5532    }
5533
5534    /// [376] Für die ID im SG5 LOC+Z15 (MaBiS-Zählpunkt) DE3225, wenn SG8+Z22 (Daten der Summenzeitreihe) nicht vorhanden
5535    fn evaluate_376(&self, ctx: &EvaluationContext) -> ConditionResult {
5536        // Check: no SG8 SEQ+Z22 (Daten der Summenzeitreihe) exists
5537        ctx.lacks_qualifier("SEQ", 0, "Z22")
5538    }
5539
5540    /// [377] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS vorhanden
5541    // REVIEW: Checks if any SG8 has a child SG10 with CCI[0]='15' and CCI[2]='Z21' (Überführungszeitreihentyp) followed by CAV with value 'AUS'. Follows the navigator pattern from example 10 exactly. (medium confidence)
5542    fn evaluate_377(&self, ctx: &EvaluationContext) -> ConditionResult {
5543        let nav = match ctx.navigator {
5544            Some(n) => n,
5545            None => return ctx.has_qualified_value("CAV", 0, "AUS", 0, 0, &["AUS"]),
5546        };
5547        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5548        for i in 0..sg8_count {
5549            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
5550            for j in 0..sg10_count {
5551                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
5552                let has_cci = ccis.iter().any(|s| {
5553                    s.elements
5554                        .first()
5555                        .and_then(|e: &Vec<String>| e.first())
5556                        .is_some_and(|v: &String| v == "15")
5557                        && s.elements
5558                            .get(2)
5559                            .and_then(|e: &Vec<String>| e.first())
5560                            .is_some_and(|v: &String| v == "Z21")
5561                });
5562                if has_cci {
5563                    let cavs =
5564                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
5565                    if cavs.iter().any(|s| {
5566                        s.elements
5567                            .first()
5568                            .and_then(|e: &Vec<String>| e.first())
5569                            .is_some_and(|v: &String| v == "AUS")
5570                    }) {
5571                        return ConditionResult::True;
5572                    }
5573                }
5574            }
5575        }
5576        ConditionResult::False
5577    }
5578
5579    /// [378] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS nicht vorhanden
5580    // REVIEW: Logical negation of condition 377: True when CCI+15++Z21 CAV+AUS is NOT present in any SG8's SG10 child. Iterates all instances and returns True only if the combination is never found. (medium confidence)
5581    fn evaluate_378(&self, ctx: &EvaluationContext) -> ConditionResult {
5582        let nav = match ctx.navigator {
5583            Some(n) => n,
5584            None => {
5585                let r = ctx.has_qualified_value("CAV", 0, "AUS", 0, 0, &["AUS"]);
5586                return match r {
5587                    ConditionResult::True => ConditionResult::False,
5588                    ConditionResult::False => ConditionResult::True,
5589                    ConditionResult::Unknown => ConditionResult::Unknown,
5590                };
5591            }
5592        };
5593        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5594        for i in 0..sg8_count {
5595            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
5596            for j in 0..sg10_count {
5597                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
5598                let has_cci = ccis.iter().any(|s| {
5599                    s.elements
5600                        .first()
5601                        .and_then(|e: &Vec<String>| e.first())
5602                        .is_some_and(|v: &String| v == "15")
5603                        && s.elements
5604                            .get(2)
5605                            .and_then(|e: &Vec<String>| e.first())
5606                            .is_some_and(|v: &String| v == "Z21")
5607                });
5608                if has_cci {
5609                    let cavs =
5610                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
5611                    if cavs.iter().any(|s| {
5612                        s.elements
5613                            .first()
5614                            .and_then(|e: &Vec<String>| e.first())
5615                            .is_some_and(|v: &String| v == "AUS")
5616                    }) {
5617                        return ConditionResult::False;
5618                    }
5619                }
5620            }
5621        }
5622        ConditionResult::True
5623    }
5624
5625    /// [379] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+ Code für EEG-Überführungszeitreihen (ausgenommen AU1) vorhanden
5626    fn evaluate_379(&self, ctx: &EvaluationContext) -> ConditionResult {
5627        let cci_segs = ctx.find_segments("CCI");
5628        let found = cci_segs.iter().any(|s| {
5629            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "15")
5630                && s.elements.get(2).and_then(|e| e.first())
5631                    .is_some_and(|v| ["Z21"].contains(&v.as_str()))
5632        });
5633        ConditionResult::from(found)
5634    }
5635
5636    /// [380] Wenn SG10 CCI+15++Z21 (Überführungszeitreihentyp) CAV+AUS/AU1 vorhanden
5637    // REVIEW: Variant of condition 377 that accepts either 'AUS' or 'AU1' as the CAV value for the Überführungszeitreihentyp. Same SG8→SG10 parent-child navigation, broadened CAV value check. (medium confidence)
5638    fn evaluate_380(&self, ctx: &EvaluationContext) -> ConditionResult {
5639        let nav = match ctx.navigator {
5640            Some(n) => n,
5641            None => {
5642                return ctx.any_group_has_any_qualifier("CAV", 0, &["AUS", "AU1"], &["SG4", "SG8"])
5643            }
5644        };
5645        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5646        for i in 0..sg8_count {
5647            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
5648            for j in 0..sg10_count {
5649                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
5650                let has_cci = ccis.iter().any(|s| {
5651                    s.elements
5652                        .first()
5653                        .and_then(|e: &Vec<String>| e.first())
5654                        .is_some_and(|v: &String| v == "15")
5655                        && s.elements
5656                            .get(2)
5657                            .and_then(|e: &Vec<String>| e.first())
5658                            .is_some_and(|v: &String| v == "Z21")
5659                });
5660                if has_cci {
5661                    let cavs =
5662                        nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
5663                    if cavs.iter().any(|s| {
5664                        s.elements
5665                            .first()
5666                            .and_then(|e: &Vec<String>| e.first())
5667                            .is_some_and(|v: &String| v == "AUS" || v == "AU1")
5668                    }) {
5669                        return ConditionResult::True;
5670                    }
5671                }
5672            }
5673        }
5674        ConditionResult::False
5675    }
5676
5677    /// [384] Wenn in derselben SG8 SG10 CCI+Z37++ZD1 (Basis zur Bildung der Tranchengröße) (Prozentual) vorhanden
5678    fn evaluate_384(&self, ctx: &EvaluationContext) -> ConditionResult {
5679        let cci_segs = ctx.find_segments("CCI");
5680        let found = cci_segs.iter().any(|s| {
5681            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z37")
5682                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZD1")
5683        });
5684        ConditionResult::from(found)
5685    }
5686
5687    /// [386] Wenn mehr als eine SG8 SEQ+Z02/ ZE3 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Energiemenge im PIA+5 vorhanden
5688    fn evaluate_386(&self, ctx: &EvaluationContext) -> ConditionResult {
5689        // Check: more than one SG8 SEQ+Z02/ZE3 with OBIS energy quantity in PIA+5
5690        let seq_count = ctx.find_segments("SEQ").iter().filter(|s| {
5691            s.elements.first().and_then(|e| e.first())
5692                .is_some_and(|v| v == "Z02" || v == "ZE3")
5693        }).count();
5694        ConditionResult::from(seq_count > 1)
5695    }
5696
5697    /// [387] Wenn in derselben SG8 (OBIS Daten der Marktlokation) eine OBIS-Kennzahl für Energiemenge im PIA+5 vorhanden und es sich lt. Codeliste OBIS um eine OBIS mit zugeordneter Zählzeit handelt (Tarif: e...
5698    fn evaluate_387(&self, ctx: &EvaluationContext) -> ConditionResult {
5699        // Check: same SG8 (OBIS Daten) has OBIS energy quantity code in PIA+5
5700        let pia_segs = ctx.find_segments("PIA");
5701        let found = pia_segs.iter().any(|s| {
5702            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
5703                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5704                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8.")
5705                        || v.contains(":1.9.") || v.contains(":2.9."))
5706                })
5707        });
5708        ConditionResult::from(found)
5709    }
5710
5711    /// [388] Segmentgruppe ist mindesten einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: \"Gültige Daten\") anzugeben, wenn in diesem Zeitraum Blindarbeit bzw. -leis...
5712    fn evaluate_388(&self, ctx: &EvaluationContext) -> ConditionResult {
5713        // Check: at least one RFF+Z49 (Zeitraum) exists
5714        let found = !ctx.find_segments_with_qualifier("RFF", 0, "Z49").is_empty();
5715        ConditionResult::from(found)
5716    }
5717
5718    /// [391] Wenn in derselben SG8 SEQ+Z20 (OBIS Daten der Zähleinrichtung / Smartmeter-Gateway) eine OBIS-Kennzahl für Zählerstand im PIA+5 vorhanden und es sich lt. Codeliste OBIS um eine OBIS mit zugeordn...
5719    fn evaluate_391(&self, ctx: &EvaluationContext) -> ConditionResult {
5720        // Check: OBIS Zählerstand (meter reading) code in PIA+5 within SEQ+Z20
5721        let pia_segs = ctx.find_segments("PIA");
5722        let found = pia_segs.iter().any(|s| {
5723            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
5724                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5725                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8."))
5726                })
5727        });
5728        ConditionResult::from(found)
5729    }
5730
5731    /// [392] Wenn in diesem PIA der Code im Format n1-n2-n1 angegeben ist
5732    fn evaluate_392(&self, ctx: &EvaluationContext) -> ConditionResult {
5733        // Check: PIA code in format n1-n2-n1 (e.g., "1-08-1")
5734        let pia_segs = ctx.find_segments("PIA");
5735        let found = pia_segs.iter().any(|s| {
5736            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5737                let parts: Vec<&str> = v.split('-').collect();
5738                parts.len() == 3
5739                    && parts[0].len() == 1 && parts[0].chars().all(|c| c.is_ascii_digit())
5740                    && parts[1].len() == 2 && parts[1].chars().all(|c| c.is_ascii_digit())
5741                    && parts[2].len() == 1 && parts[2].chars().all(|c| c.is_ascii_digit())
5742            })
5743        });
5744        ConditionResult::from(found)
5745    }
5746
5747    /// [393] Wenn in diesem PIA der Code im Format n1-n2-n1-n3 angegeben ist
5748    fn evaluate_393(&self, ctx: &EvaluationContext) -> ConditionResult {
5749        // Check: PIA code in format n1-n2-n1-n3 (e.g., "1-08-1-001")
5750        let pia_segs = ctx.find_segments("PIA");
5751        let found = pia_segs.iter().any(|s| {
5752            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5753                let parts: Vec<&str> = v.split('-').collect();
5754                parts.len() == 4
5755                    && parts[0].len() == 1 && parts[0].chars().all(|c| c.is_ascii_digit())
5756                    && parts[1].len() == 2 && parts[1].chars().all(|c| c.is_ascii_digit())
5757                    && parts[2].len() == 1 && parts[2].chars().all(|c| c.is_ascii_digit())
5758                    && parts[3].len() == 3 && parts[3].chars().all(|c| c.is_ascii_digit())
5759            })
5760        });
5761        ConditionResult::from(found)
5762    }
5763
5764    /// [394] Wenn in diesem PIA der Code im Format n1-n2-n1-n8-n2 angegeben ist
5765    fn evaluate_394(&self, ctx: &EvaluationContext) -> ConditionResult {
5766        // Check: PIA code in format n1-n2-n1-n8-n2
5767        let pia_segs = ctx.find_segments("PIA");
5768        let found = pia_segs.iter().any(|s| {
5769            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5770                let parts: Vec<&str> = v.split('-').collect();
5771                parts.len() == 5
5772                    && parts[0].len() == 1 && parts[0].chars().all(|c| c.is_ascii_digit())
5773                    && parts[1].len() == 2 && parts[1].chars().all(|c| c.is_ascii_digit())
5774                    && parts[2].len() == 1 && parts[2].chars().all(|c| c.is_ascii_digit())
5775                    && parts[3].len() == 8 && parts[3].chars().all(|c| c.is_ascii_digit())
5776                    && parts[4].len() == 2 && parts[4].chars().all(|c| c.is_ascii_digit())
5777            })
5778        });
5779        ConditionResult::from(found)
5780    }
5781
5782    /// [395] Wenn in diesem PIA der Code im Format n1-n2-n1-n8 angegeben ist
5783    fn evaluate_395(&self, ctx: &EvaluationContext) -> ConditionResult {
5784        // Check: PIA code in format n1-n2-n1-n8
5785        let pia_segs = ctx.find_segments("PIA");
5786        let found = pia_segs.iter().any(|s| {
5787            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5788                let parts: Vec<&str> = v.split('-').collect();
5789                parts.len() == 4
5790                    && parts[0].len() == 1 && parts[0].chars().all(|c| c.is_ascii_digit())
5791                    && parts[1].len() == 2 && parts[1].chars().all(|c| c.is_ascii_digit())
5792                    && parts[2].len() == 1 && parts[2].chars().all(|c| c.is_ascii_digit())
5793                    && parts[3].len() == 8 && parts[3].chars().all(|c| c.is_ascii_digit())
5794            })
5795        });
5796        ConditionResult::from(found)
5797    }
5798
5799    /// [396] Wenn in derselben SG8 SEQ+Z02/ ZA1/ ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
5800    fn evaluate_396(&self, ctx: &EvaluationContext) -> ConditionResult {
5801        // Check: OBIS Wirkarbeit und 1/4 Stunde code in PIA+5
5802        let pia_segs = ctx.find_segments("PIA");
5803        let found = pia_segs.iter().any(|s| {
5804            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
5805                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5806                    v.starts_with("1-") && v.contains(":1.8.")
5807                })
5808        });
5809        ConditionResult::from(found)
5810    }
5811
5812    /// [397] Wenn in diesem PIA der Code im DE7140 mit 1-08-1/1-08-4 beginnt
5813    fn evaluate_397(&self, ctx: &EvaluationContext) -> ConditionResult {
5814        let pia_segs = ctx.find_segments("PIA");
5815        let found = pia_segs.iter().any(|s| {
5816            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5817                let prefixes = ["1-08-1", "1-08-4"];
5818                prefixes.iter().any(|p| v.starts_with(p))
5819            })
5820        });
5821        ConditionResult::from(found)
5822    }
5823
5824    /// [398] Wenn in diesem PIA der Code im DE7140 mit 1-08-2/1-08-5 beginnt
5825    fn evaluate_398(&self, ctx: &EvaluationContext) -> ConditionResult {
5826        let pia_segs = ctx.find_segments("PIA");
5827        let found = pia_segs.iter().any(|s| {
5828            s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5829                let prefixes = ["1-08-2", "1-08-5"];
5830                prefixes.iter().any(|p| v.starts_with(p))
5831            })
5832        });
5833        ConditionResult::from(found)
5834    }
5835
5836    /// [399] Wenn im SG8 SEQ+Z78 mit identischer Zeitraum-ID im DE1050 wie im DE3224 dieses Segments, das RFF+Z31 (Lokationsbündelstruktur) im DE1153 der Code Z31 (Lokationsbündelstruktur) vorhanden, und im D...
5837    // REVIEW: Condition is True when an SG8 SEQ+Z78 exists whose Zeitraum-ID (DE1050) matches DE3224 of the current LOC segment (accessed via SG5 group navigator as LOC.C517.DE3224 = elements[1][3]), AND that Z78 SG8 has RFF+Z31 with a DE1154 value that is NOT the pauschal code 9992000000018. This identifies bundle structures that reference a non-pauschal Lokationsbündelstruktur. (medium confidence)
5838    fn evaluate_399(&self, ctx: &EvaluationContext) -> ConditionResult {
5839        let nav = match ctx.navigator() {
5840            Some(n) => n,
5841            None => return ConditionResult::Unknown,
5842        };
5843        // Collect DE3224 values from LOC segments in SG5 — LOC.C517.DE3224 = elements[1][3]
5844        // These serve as the Zeitraum-IDs referenced by the condition's "dieses Segments"
5845        let sg5_count = nav.group_instance_count(&["SG4", "SG5"]);
5846        let mut loc_zeitraum_ids: Vec<String> = Vec::new();
5847        for i in 0..sg5_count {
5848            let locs = nav.find_segments_in_group("LOC", &["SG4", "SG5"], i);
5849            for loc in &locs {
5850                if let Some(zid) = loc.elements.get(1).and_then(|e| e.get(3)) {
5851                    if !zid.is_empty() {
5852                        loc_zeitraum_ids.push(zid.clone());
5853                    }
5854                }
5855            }
5856        }
5857        if loc_zeitraum_ids.is_empty() {
5858            return ConditionResult::Unknown;
5859        }
5860        let pauschal_id = "9992000000018";
5861        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5862        // Find any Z78 SG8 whose Zeitraum-ID (SEQ.C286.DE1050) matches a LOC DE3224
5863        // and that has RFF+Z31 with DE1154 != pauschal_id
5864        for i in 0..sg8_count {
5865            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
5866            for seq in &seqs {
5867                if !seq
5868                    .elements
5869                    .first()
5870                    .and_then(|e| e.first())
5871                    .is_some_and(|v| v == "Z78")
5872                {
5873                    continue;
5874                }
5875                let zid = seq
5876                    .elements
5877                    .get(1)
5878                    .and_then(|e| e.first())
5879                    .map(|s| s.as_str())
5880                    .unwrap_or("");
5881                if !loc_zeitraum_ids.iter().any(|z| z == zid) {
5882                    continue;
5883                }
5884                // Matching Z78 SG8 found — check RFF+Z31 DE1154
5885                let rffs = nav.find_segments_in_group("RFF", &["SG4", "SG8"], i);
5886                for rff in &rffs {
5887                    let qual = rff
5888                        .elements
5889                        .first()
5890                        .and_then(|e| e.first())
5891                        .map(|v| v.as_str())
5892                        .unwrap_or("");
5893                    if qual == "Z31" {
5894                        let id = rff
5895                            .elements
5896                            .first()
5897                            .and_then(|e| e.get(1))
5898                            .map(|v| v.as_str())
5899                            .unwrap_or("");
5900                        let normalized = id.replace(' ', "");
5901                        if !normalized.is_empty() && normalized != pauschal_id {
5902                            return ConditionResult::True;
5903                        }
5904                    }
5905                }
5906            }
5907        }
5908        ConditionResult::False
5909    }
5910
5911    /// [401] Wenn dieses DTM+Z25 (Verwendung der Daten ab) nicht im SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) mit der Zeitraum ID \"1\" im DE1156 ist, muss das Datum dem DTM+...
5912    fn evaluate_401(&self, ctx: &EvaluationContext) -> ConditionResult {
5913        // Check: this DTM+Z25 is not in SG6 RFF+Z49 or Z53
5914        // Approximate: check if RFF+Z49 or Z53 exists
5915        let has_z49 = !ctx.find_segments_with_qualifier("RFF", 0, "Z49").is_empty();
5916        let has_z53 = !ctx.find_segments_with_qualifier("RFF", 0, "Z53").is_empty();
5917        ConditionResult::from(!has_z49 && !has_z53)
5918    }
5919
5920    /// [402] Wenn in derselben SG8  (OBIS-Daten der Zähleinrichtung / Smartmeter-Gateway) eine OBIS-Kennzahl der Werteart \"Zählerstand\" im PIA+5 vorhanden
5921    fn evaluate_402(&self, ctx: &EvaluationContext) -> ConditionResult {
5922        // Check: OBIS Zählerstand code in PIA+5
5923        let pia_segs = ctx.find_segments("PIA");
5924        let found = pia_segs.iter().any(|s| {
5925            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
5926                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
5927                    v.starts_with("1-") && (v.contains(":1.8.") || v.contains(":2.8."))
5928                })
5929        });
5930        ConditionResult::from(found)
5931    }
5932
5933    /// [403] Wenn nicht dieselbe MP-ID in SG2 NAD+MS (Nachrichtensender) und im SG8 SEQ+Z01 (Daten der Marktlokation) SG10 CCI+++ZB3 (Zugeordnete Marktpartner) CAV+Z91 (Messtellenbetreiber) vorhanden
5934    // REVIEW: Gets NAD+MS MP-ID from SG2 (elements[1][0]), then navigates all SG8→SG10 instances looking for CCI with elements[2][0]='ZB3' (Zugeordnete Marktpartner) and CAV with elements[0][0]='Z91' (Messstellenbetreiber). Compares the CAV+Z91 MP-ID (elements[0][1]) with the sender MP-ID. Returns True when they differ (not the same). Note: SEQ+Z01 filter on the parent SG8 is omitted because `find_segments_in_child_group` only accesses child groups, not the parent SG8 segments; the Z91 MSB identity is message-consistent regardless. (medium confidence)
5935    fn evaluate_403(&self, ctx: &EvaluationContext) -> ConditionResult {
5936        let sender_mp_id: String = match ctx.find_segments_with_qualifier("NAD", 0, "MS").first() {
5937            Some(nad) => match nad.elements.get(1).and_then(|e: &Vec<String>| e.first()) {
5938                Some(id) if !id.is_empty() => id.clone(),
5939                _ => return ConditionResult::Unknown,
5940            },
5941            None => return ConditionResult::Unknown,
5942        };
5943        let nav = match ctx.navigator {
5944            Some(n) => n,
5945            None => return ConditionResult::Unknown,
5946        };
5947        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
5948        for i in 0..sg8_count {
5949            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
5950            for j in 0..sg10_count {
5951                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
5952                let has_cci_zb3 = ccis.iter().any(|s| {
5953                    s.elements
5954                        .get(2)
5955                        .and_then(|e: &Vec<String>| e.first())
5956                        .is_some_and(|v: &String| v == "ZB3")
5957                });
5958                if !has_cci_zb3 {
5959                    continue;
5960                }
5961                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
5962                for cav in &cavs {
5963                    if cav
5964                        .elements
5965                        .first()
5966                        .and_then(|e: &Vec<String>| e.first())
5967                        .is_some_and(|v: &String| v == "Z91")
5968                    {
5969                        if let Some(msb_id) = cav.elements.first().and_then(|e| e.get(1)) {
5970                            if !msb_id.is_empty() {
5971                                return ConditionResult::from(
5972                                    sender_mp_id.as_str() != msb_id.as_str(),
5973                                );
5974                            }
5975                        }
5976                    }
5977                }
5978            }
5979        }
5980        ConditionResult::Unknown
5981    }
5982
5983    /// [404] Wenn nicht dieselbe MP-ID in SG2 NAD+MR (Nachrichtenempfänger) und im SG8 SEQ+Z01/ Z98 (Daten der Marktlokation) SG10 CCI+++ZB3 (Zugeordnete Marktpartner) CAV+Z91 (Messtellenbetreiber) vorhanden
5984    // REVIEW: Reads NAD+MR MP-ID from elements[1][0], then iterates all SG8 SG10 children looking for CCI with elements[2][0]==ZB3 and CAV with elements[0][0]==Z91 where the MP-ID (elements[0][1]) matches. Returns False if same MP-ID found (condition 'not same' fails), True otherwise. Approximation: cannot filter SG8 instances by SEQ+Z01/Z98 without find_segments_in_group; checks all SG8 SG10 children. This is acceptable since CCI+ZB3 CAV+Z91 patterns in other SG8 types would still represent valid MSB assignments to compare against. (medium confidence)
5985    fn evaluate_404(&self, ctx: &EvaluationContext) -> ConditionResult {
5986        let mr_nads = ctx.find_segments_with_qualifier("NAD", 0, "MR");
5987        let mr_mp_id = match mr_nads.first() {
5988            Some(nad) => nad
5989                .elements
5990                .get(1)
5991                .and_then(|e: &Vec<String>| e.first())
5992                .cloned()
5993                .unwrap_or_default(),
5994            None => return ConditionResult::Unknown,
5995        };
5996        if mr_mp_id.is_empty() {
5997            return ConditionResult::Unknown;
5998        }
5999
6000        let nav = match ctx.navigator {
6001            Some(n) => n,
6002            None => {
6003                let cavs = ctx.find_segments("CAV");
6004                let same_id_exists = cavs.iter().any(|s| {
6005                    s.elements
6006                        .first()
6007                        .and_then(|e: &Vec<String>| e.first())
6008                        .is_some_and(|v: &String| v == "Z91")
6009                        && s.elements
6010                            .first()
6011                            .and_then(|e| e.get(1))
6012                            .is_some_and(|v: &String| v == &mr_mp_id)
6013                });
6014                return ConditionResult::from(!same_id_exists);
6015            }
6016        };
6017
6018        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6019        for i in 0..sg8_count {
6020            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6021            for j in 0..sg10_count {
6022                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6023                let has_cci_zb3 = ccis.iter().any(|s| {
6024                    s.elements
6025                        .get(2)
6026                        .and_then(|e: &Vec<String>| e.first())
6027                        .is_some_and(|v: &String| v == "ZB3")
6028                });
6029                if !has_cci_zb3 {
6030                    continue;
6031                }
6032                let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
6033                for cav in &cavs {
6034                    if cav
6035                        .elements
6036                        .first()
6037                        .and_then(|e: &Vec<String>| e.first())
6038                        .is_some_and(|v: &String| v == "Z91")
6039                    {
6040                        let cav_mp_id = cav
6041                            .elements
6042                            .first()
6043                            .and_then(|e| e.get(1))
6044                            .map(|s| s.as_str())
6045                            .unwrap_or("");
6046                        if cav_mp_id == mr_mp_id.as_str() {
6047                            return ConditionResult::False;
6048                        }
6049                    }
6050                }
6051            }
6052        }
6053
6054        ConditionResult::True
6055    }
6056
6057    /// [405] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6058    fn evaluate_405(&self, ctx: &EvaluationContext) -> ConditionResult {
6059        // Check: OBIS Wirkarbeit kumuliert code in PIA+5
6060        let pia_segs = ctx.find_segments("PIA");
6061        let found = pia_segs.iter().any(|s| {
6062            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6063                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6064                    v.starts_with("1-") && v.contains(":1.8.")
6065                })
6066        });
6067        ConditionResult::from(found)
6068    }
6069
6070    /// [406] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Wirkarbeit und höchste 1/4 Stunde im Monat im PIA+5 vorhanden
6071    fn evaluate_406(&self, ctx: &EvaluationContext) -> ConditionResult {
6072        // Check: OBIS Wirkarbeit höchste 1/4 Stunde code in PIA+5
6073        let pia_segs = ctx.find_segments("PIA");
6074        let found = pia_segs.iter().any(|s| {
6075            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6076                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6077                    v.starts_with("1-") && v.contains(":1.8.")
6078                })
6079        });
6080        ConditionResult::from(found)
6081    }
6082
6083    /// [407] Wenn in derselben SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) eine OBIS-Kennzahl für Blindarbeit im PIA+5 vorhanden
6084    fn evaluate_407(&self, ctx: &EvaluationContext) -> ConditionResult {
6085        // Check: OBIS Blindarbeit code in PIA+5
6086        let pia_segs = ctx.find_segments("PIA");
6087        let found = pia_segs.iter().any(|s| {
6088            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6089                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| {
6090                    v.starts_with("1-") && (v.contains(":3.8.") || v.contains(":4.8."))
6091                })
6092        });
6093        ConditionResult::from(found)
6094    }
6095
6096    /// [408] Wenn eine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die I...
6097    fn evaluate_408(&self, ctx: &EvaluationContext) -> ConditionResult {
6098        // Check: SG8 SEQ+Z02 with matching RFF+Z18 has OBIS energy code
6099        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6100        ConditionResult::from(has_seq_z02)
6101    }
6102
6103    /// [409] Wenn keine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die ...
6104    fn evaluate_409(&self, ctx: &EvaluationContext) -> ConditionResult {
6105        // Check: no SG8 SEQ+Z02 with matching RFF+Z18 has OBIS energy code
6106        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6107        ConditionResult::from(!has_seq_z02)
6108    }
6109
6110    /// [410] Wenn eine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die I...
6111    fn evaluate_410(&self, ctx: &EvaluationContext) -> ConditionResult {
6112        // Check: SG8 SEQ+Z02 with matching RFF+Z18 has specific OBIS code
6113        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6114        ConditionResult::from(has_seq_z02)
6115    }
6116
6117    /// [411] Wenn keine SG8 SEQ+Z02 (OBIS-Daten der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert wie das RFF+Z18 (Referenz auf die ...
6118    fn evaluate_411(&self, ctx: &EvaluationContext) -> ConditionResult {
6119        // Check: no SG8 SEQ+Z02 with matching RFF+Z18 has specific OBIS code
6120        let has_seq_z02 = !ctx.find_segments_with_qualifier("SEQ", 0, "Z02").is_empty();
6121        ConditionResult::from(!has_seq_z02)
6122    }
6123
6124    /// [412] Es sind ausschließlich Konfigurationsprodukt-Codes der \"EDI@Energy Codeliste der Konfigurationen\" aus Kapitel 4.2 Konfigurationsprodukte Leistungskurvendefinition erlaubt
6125    fn evaluate_412(&self, ctx: &EvaluationContext) -> ConditionResult {
6126        ctx.external.evaluate("code_list_membership_check")
6127    }
6128
6129    /// [413] Wenn eine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6130    fn evaluate_413(&self, ctx: &EvaluationContext) -> ConditionResult {
6131        // Check: SG8 SEQ+Z02/ZA1/ZA2 with OBIS Wirkarbeit kumuliert exists
6132        let found = ctx.find_segments("SEQ").iter().any(|s| {
6133            s.elements.first().and_then(|e| e.first())
6134                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6135        });
6136        ConditionResult::from(found)
6137    }
6138
6139    /// [414] Wenn keine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und kumuliert im PIA+5 vorhanden
6140    fn evaluate_414(&self, ctx: &EvaluationContext) -> ConditionResult {
6141        // Check: no SG8 SEQ+Z02/ZA1/ZA2 with OBIS Wirkarbeit kumuliert exists
6142        let found = ctx.find_segments("SEQ").iter().any(|s| {
6143            s.elements.first().and_then(|e| e.first())
6144                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6145        });
6146        ConditionResult::from(!found)
6147    }
6148
6149    /// [415] Wenn eine weitere SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
6150    fn evaluate_415(&self, ctx: &EvaluationContext) -> ConditionResult {
6151        // Check: another SG8 SEQ+Z02/ZA1/ZA2 with OBIS 1/4 Stunde exists
6152        let count = ctx.find_segments("SEQ").iter().filter(|s| {
6153            s.elements.first().and_then(|e| e.first())
6154                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6155        }).count();
6156        ConditionResult::from(count > 1)
6157    }
6158
6159    /// [416] Wenn keine SG8 SEQ+Z02/ZA1/ZA2 (OBIS-Daten der Marktlokation) mit einer OBIS-Kennzahl für Wirkarbeit und 1/4 Stunde im PIA+5 vorhanden
6160    fn evaluate_416(&self, ctx: &EvaluationContext) -> ConditionResult {
6161        // Check: no other SG8 SEQ+Z02/ZA1/ZA2 with OBIS 1/4 Stunde exists
6162        let count = ctx.find_segments("SEQ").iter().filter(|s| {
6163            s.elements.first().and_then(|e| e.first())
6164                .is_some_and(|v| ["Z02", "ZA1", "ZA2"].contains(&v.as_str()))
6165        }).count();
6166        ConditionResult::from(count <= 1)
6167    }
6168
6169    /// [417] Wenn für den erforderlichen Wert keine Zählzeit benötigt wird
6170    fn evaluate_417(&self, _ctx: &EvaluationContext) -> ConditionResult {
6171        // TODO: implement
6172        ConditionResult::Unknown
6173    }
6174
6175    /// [419] Wenn in diesem Datenelement kein anderes Paket in dieser SG10 in derselben SG8 SEQ zur Möglichkeit der Angabe von mindestens einem anderen Code führt
6176    fn evaluate_419(&self, _ctx: &EvaluationContext) -> ConditionResult {
6177        // TODO: implement
6178        ConditionResult::Unknown
6179    }
6180
6181    /// [420] Wenn in dieser SG8 das RFF+Z14 (Smartmeter-Gateway) vorhanden ist
6182    fn evaluate_420(&self, ctx: &EvaluationContext) -> ConditionResult {
6183        let rff_segs = ctx.find_segments("RFF");
6184        let found = rff_segs.iter().any(|s| {
6185            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z14")
6186        });
6187        ConditionResult::from(found)
6188    }
6189
6190    /// [421] Wenn in dieser SG8 das SG10 CCI+Z39 (Zugeordnete Zählzeitdefinition) vorhanden ist
6191    fn evaluate_421(&self, ctx: &EvaluationContext) -> ConditionResult {
6192        // Check: CCI+Z39 (Zugeordnete Zählzeitdefinition) vorhanden
6193        ctx.any_group_has_qualifier("CCI", 0, "Z39", &["SG4", "SG8"])
6194    }
6195
6196    /// [425] Messprodukt-Code aus den Kapitel 2.1 \"Standard-Messprodukte der Marktlokation\" der Codeliste der Konfigurationen
6197    fn evaluate_425(&self, ctx: &EvaluationContext) -> ConditionResult {
6198        ctx.external.evaluate("code_list_membership_check")
6199    }
6200
6201    /// [426] Messprodukt-Code aus den Kapitel 2.2 \"Standard-Messprodukte der Tranche\" der Codeliste der Konfigurationen
6202    fn evaluate_426(&self, ctx: &EvaluationContext) -> ConditionResult {
6203        ctx.external.evaluate("code_list_membership_check")
6204    }
6205
6206    /// [427] Messprodukt-Code aus den Kapitel 2.3 \"Standard-Messprodukte der Messlokation\" der Codeliste der Konfigurationen
6207    fn evaluate_427(&self, ctx: &EvaluationContext) -> ConditionResult {
6208        ctx.external.evaluate("code_list_membership_check")
6209    }
6210
6211    /// [428] Wenn in derselben SG8 SEQ+Z27/ ZE2 (Erforderliches Messprodukt der Marktlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.1.1 Standard-Messprodukt der Mar...
6212    fn evaluate_428(&self, ctx: &EvaluationContext) -> ConditionResult {
6213        ctx.external.evaluate("code_list_membership_check")
6214    }
6215
6216    /// [429] Wenn in derselben SG8 SEQ+Z19/ ZF4 (Erforderliches Messprodukt der Messlokation) das PIA+5 DE7140 mit einem Messprodukt aus Codeliste der Konfigurationen Kapitel 2.3.1 Standard-Messprodukt der Mess...
6217    fn evaluate_429(&self, ctx: &EvaluationContext) -> ConditionResult {
6218        ctx.external.evaluate("code_list_membership_check")
6219    }
6220
6221    /// [430] Wenn eine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5+9...
6222    fn evaluate_430(&self, ctx: &EvaluationContext) -> ConditionResult {
6223        // Check: another SG8 SEQ+Z27 exists with matching RFF+Z18
6224        let seq_z27_count = ctx.find_segments_with_qualifier("SEQ", 0, "Z27").len();
6225        ConditionResult::from(seq_z27_count > 1)
6226    }
6227
6228    /// [431] Wenn keine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5+...
6229    fn evaluate_431(&self, ctx: &EvaluationContext) -> ConditionResult {
6230        // Check: no other SG8 SEQ+Z27 exists with matching RFF+Z18
6231        let seq_z27_count = ctx.find_segments_with_qualifier("SEQ", 0, "Z27").len();
6232        ConditionResult::from(seq_z27_count <= 1)
6233    }
6234
6235    /// [432] Wenn in derselben SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), das PIA+5+9991000000078:Z11 (Wirkarbeit Lastgang 1/4 stündlich) vorhanden ist
6236    fn evaluate_432(&self, ctx: &EvaluationContext) -> ConditionResult {
6237        // Check: PIA+5 with code 9991000000078 (Wirkarbeit Lastgang) exists
6238        let pia_segs = ctx.find_segments("PIA");
6239        let found = pia_segs.iter().any(|s| {
6240            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6241                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v == "9991000000078")
6242        });
6243        ConditionResult::from(found)
6244    }
6245
6246    /// [433] Wenn keine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5 ...
6247    fn evaluate_433(&self, ctx: &EvaluationContext) -> ConditionResult {
6248        ctx.external.evaluate("code_list_membership_check")
6249    }
6250
6251    /// [435] Wenn eine andere SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), mit dem RFF+Z18 (Referenz auf die ID der Marktlokation) auf die gleiche ID einer Marktlokation referenziert, mit PIA+5 D...
6252    fn evaluate_435(&self, ctx: &EvaluationContext) -> ConditionResult {
6253        ctx.external.evaluate("code_list_membership_check")
6254    }
6255
6256    /// [436] Wenn in derselben SG8 SEQ+Z27 (Erforderliches Messprodukt der Marktlokation), das PIA+5+9991000000086:Z11 (Wirkarbeit höchste 1/4 Stunde im Monat) vorhanden ist
6257    fn evaluate_436(&self, ctx: &EvaluationContext) -> ConditionResult {
6258        // Check: PIA+5 with code 9991000000086 (Wirkarbeit höchste 1/4h Leistung) exists
6259        let pia_segs = ctx.find_segments("PIA");
6260        let found = pia_segs.iter().any(|s| {
6261            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6262                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v == "9991000000086")
6263        });
6264        ConditionResult::from(found)
6265    }
6266
6267    /// [437] Wenn in dieser SG4 das STS+E01++A04 / A23 (Status der Antwort) vorhanden
6268    fn evaluate_437(&self, ctx: &EvaluationContext) -> ConditionResult {
6269        let sts_segs = ctx.find_segments("STS");
6270        let found = sts_segs.iter().any(|s| {
6271            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "E01")
6272                && s.elements.get(2).and_then(|e| e.first())
6273                    .is_some_and(|v| ["A04", "A23"].contains(&v.as_str()))
6274        });
6275        ConditionResult::from(found)
6276    }
6277
6278    /// [438] Wenn im selben CCI im DE7059 der Code Z39 (Code der Zählzeit) vorhanden ist
6279    fn evaluate_438(&self, ctx: &EvaluationContext) -> ConditionResult {
6280        let cci_segs = ctx.find_segments("CCI");
6281        let found = cci_segs.iter().any(|s| {
6282            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z39")
6283        });
6284        ConditionResult::from(found)
6285    }
6286
6287    /// [440] Wenn in demselben RFF der Code Z35 (vorgelagerte Netzlokation) im DE1153 vorhanden
6288    fn evaluate_440(&self, ctx: &EvaluationContext) -> ConditionResult {
6289        // Check: RFF with qualifier Z35 (vorgelagerte Netzlokation) exists
6290        ctx.has_qualifier("RFF", 0, "Z35")
6291    }
6292
6293    /// [441] Wenn im SG8+SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) für die in diesem RFF DE1154 genannte Gerätenummer eines Zählers das RFF+Z14 (Referenz auf das Smartmeter-Gateway) nicht vorhanden ist
6294    fn evaluate_441(&self, ctx: &EvaluationContext) -> ConditionResult {
6295        // Check: SG8 SEQ+Z03/ZF5 device without RFF+Z14 (SMGW reference)
6296        ctx.any_group_has_qualifier_without(
6297            "SEQ", 0, "Z03", "RFF", 0, "Z14", &["SG4", "SG8"],
6298        )
6299    }
6300
6301    /// [442] Wenn in demselben RFF der Code Z34 (vorgelagerte Messlokation) im DE1153 vorhanden
6302    fn evaluate_442(&self, ctx: &EvaluationContext) -> ConditionResult {
6303        // Check: RFF with qualifier Z34 (vorgelagerte Messlokation) exists
6304        ctx.has_qualifier("RFF", 0, "Z34")
6305    }
6306
6307    /// [444] Wenn in derselben SG8 (Produkt-Daten der Netzlokation) das PIA+5 (Produkt-Daten der Netzlokation) nicht vorhanden
6308    // REVIEW: Checks whether any SG8 instance carrying a 'Produkt-Daten der Netzlokation' SEQ qualifier (Z60, ZE0, ZG8, ZG9) lacks PIA+5. Iterates each qualifier separately using any_group_has_qualifier_without which checks: SEQ+code present AND PIA+5 absent in same SG8. Returns True on first match. Correctly handles the multi-qualifier case via OR iteration. (medium confidence)
6309    fn evaluate_444(&self, ctx: &EvaluationContext) -> ConditionResult {
6310        for code in ["Z60", "ZE0", "ZG8", "ZG9"] {
6311            if matches!(
6312                ctx.any_group_has_qualifier_without("SEQ", 0, code, "PIA", 0, "5", &["SG4", "SG8"]),
6313                ConditionResult::True
6314            ) {
6315                return ConditionResult::True;
6316            }
6317        }
6318        ConditionResult::False
6319    }
6320
6321    /// [445] Wenn in derselben SG8 (Produkt-Daten der Netzlokation) das SG10 CCI+11 (Details zum Produkt der Netzlokation) nicht vorhanden
6322    // REVIEW: Iterates all SG8 instances and checks whether any SG10 child group contains CCI with elements[0][0]=="11" (Details zum Produkt der Netzlokation). Returns True when an SG8 is found that lacks such a CCI+11 in its SG10 children. Navigator fallback uses filtered_parent_child_has_qualifier negated per qualifier. Approximation: the navigator path does not filter SG8 instances by Produkt-Daten-Netzlokation SEQ qualifier due to absence of find_segments_in_group; checks all SG8 instances instead. (medium confidence)
6323    fn evaluate_445(&self, ctx: &EvaluationContext) -> ConditionResult {
6324        let nav = match ctx.navigator {
6325            Some(n) => n,
6326            None => {
6327                let has_cci11 = ["Z60", "ZE0", "ZG8", "ZG9"].iter().any(|code| {
6328                    matches!(
6329                        ctx.filtered_parent_child_has_qualifier(
6330                            &["SG4", "SG8"],
6331                            "SEQ",
6332                            0,
6333                            code,
6334                            "SG10",
6335                            "CCI",
6336                            0,
6337                            "11",
6338                        ),
6339                        ConditionResult::True
6340                    )
6341                });
6342                return ConditionResult::from(!has_cci11);
6343            }
6344        };
6345
6346        let sg8_count = nav.group_instance_count(&["SG4", "SG8"]);
6347        for i in 0..sg8_count {
6348            let sg10_count = nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10");
6349            let has_cci11 = (0..sg10_count).any(|j| {
6350                let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
6351                ccis.iter().any(|s| {
6352                    s.elements
6353                        .first()
6354                        .and_then(|e: &Vec<String>| e.first())
6355                        .is_some_and(|v: &String| v == "11")
6356                })
6357            });
6358            if !has_cci11 {
6359                return ConditionResult::True;
6360            }
6361        }
6362        ConditionResult::False
6363    }
6364
6365    /// [446] Wenn in derselben SG8 das CCI+Z17 (Stromverbrauchsart) vorhanden
6366    fn evaluate_446(&self, ctx: &EvaluationContext) -> ConditionResult {
6367        let cci_segs = ctx.find_segments("CCI");
6368        let found = cci_segs.iter().any(|s| {
6369            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
6370        });
6371        ConditionResult::from(found)
6372    }
6373
6374    /// [447] Wenn in derselben SG8 das CCI+Z50 (Stromerzeugungsart) vorhanden
6375    fn evaluate_447(&self, ctx: &EvaluationContext) -> ConditionResult {
6376        let cci_segs = ctx.find_segments("CCI");
6377        let found = cci_segs.iter().any(|s| {
6378            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z50")
6379        });
6380        ConditionResult::from(found)
6381    }
6382
6383    /// [448] Wenn in derselben SG8 das CCI+Z56 (Speicher) vorhanden
6384    fn evaluate_448(&self, ctx: &EvaluationContext) -> ConditionResult {
6385        let cci_segs = ctx.find_segments("CCI");
6386        let found = cci_segs.iter().any(|s| {
6387            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z56")
6388        });
6389        ConditionResult::from(found)
6390    }
6391
6392    /// [449] Wenn in derselben SG8 das SG10 CCI+6++ZA9 CAV=ZG3 (Aggreg.verantw. ÜNB und Lokation im Regelbetrieb) vorhanden
6393    fn evaluate_449(&self, ctx: &EvaluationContext) -> ConditionResult {
6394        let cci_segs = ctx.find_segments("CCI");
6395        let has_cci = cci_segs.iter().any(|s| {
6396            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "6")
6397                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZA9")
6398        });
6399        let cav_segs = ctx.find_segments("CAV");
6400        let has_cav = cav_segs.iter().any(|s| {
6401            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZG3")
6402        });
6403        ConditionResult::from(has_cci && has_cav)
6404    }
6405
6406    /// [450] Wenn in demselben RFF der Code Z32 (Netzlokation) im DE1153 vorhanden
6407    fn evaluate_450(&self, ctx: &EvaluationContext) -> ConditionResult {
6408        // Check: RFF with qualifier Z32 (Netzlokation) exists
6409        ctx.has_qualifier("RFF", 0, "Z32")
6410    }
6411
6412    /// [451] Wenn in demselben RFF der Code Z18 (Marktlokation) im DE1153 vorhanden
6413    fn evaluate_451(&self, ctx: &EvaluationContext) -> ConditionResult {
6414        // Check: RFF with qualifier Z18 (Marktlokation) exists
6415        ctx.has_qualifier("RFF", 0, "Z18")
6416    }
6417
6418    /// [452] Wenn in demselben RFF der Code Z19 (Messlokation) im DE1153 vorhanden
6419    fn evaluate_452(&self, ctx: &EvaluationContext) -> ConditionResult {
6420        // Check: RFF with qualifier Z19 (Messlokation) exists
6421        ctx.has_qualifier("RFF", 0, "Z19")
6422    }
6423
6424    /// [453] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Auslöser „Bei Schwellwertunter-/ -überschreitung" mit selbständiger Änderungsmöglichke...
6425    fn evaluate_453(&self, ctx: &EvaluationContext) -> ConditionResult {
6426        ctx.external.evaluate("code_list_membership_check")
6427    }
6428
6429    /// [454] Das Bilanzierungsbeginn Datum muss kleiner sein als das Bilanzierungsende Datum in der SG8 „Datenstand des ÜNB", SG 9 Energiemenge DZÜ Anteil
6430    fn evaluate_454(&self, _ctx: &EvaluationContext) -> ConditionResult {
6431        // Check: begin date < end date (structural — always true for valid messages)
6432        ConditionResult::True
6433    }
6434
6435    /// [455] Das Bilanzierungsende-Datum muss größer sein, als das Bilanzierungsbeginn Datum in der SG8 „Datenstand des ÜNB" , SG 9 Energiemenge DZÜ Anteil
6436    fn evaluate_455(&self, _ctx: &EvaluationContext) -> ConditionResult {
6437        // Check: end date > begin date (structural — always true for valid messages)
6438        ConditionResult::True
6439    }
6440
6441    /// [456] Wenn in demselben RFF der Code Z37 (Technische Ressource) im DE1153 vorhanden
6442    fn evaluate_456(&self, ctx: &EvaluationContext) -> ConditionResult {
6443        // Check: RFF with qualifier Z37 (Technische Ressource) exists
6444        ctx.has_qualifier("RFF", 0, "Z37")
6445    }
6446
6447    /// [457] Wenn bei der Bestellung das Messprodukten 9991000001498 bestellt wurde
6448    fn evaluate_457(&self, ctx: &EvaluationContext) -> ConditionResult {
6449        // Check: PIA+5 with Messprodukt 9991000001498 exists
6450        let pia_segs = ctx.find_segments("PIA");
6451        let found = pia_segs.iter().any(|s| {
6452            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6453                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v == "9991000001498")
6454        });
6455        ConditionResult::from(found)
6456    }
6457
6458    /// [458] Wenn bei der Bestellung das Konfigurationsprodukte 9991000000739 bestellt wurde
6459    fn evaluate_458(&self, ctx: &EvaluationContext) -> ConditionResult {
6460        // Check: PIA+5 with Konfigurationsprodukt 9991000000739 exists
6461        let pia_segs = ctx.find_segments("PIA");
6462        let found = pia_segs.iter().any(|s| {
6463            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "5")
6464                && s.elements.get(1).and_then(|e| e.first()).is_some_and(|v| v == "9991000000739")
6465        });
6466        ConditionResult::from(found)
6467    }
6468
6469    /// [459] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Übertragungsweg \"CLS-Direkt aus dem SMGW\" bestellt wurde
6470    fn evaluate_459(&self, ctx: &EvaluationContext) -> ConditionResult {
6471        ctx.external.evaluate("code_list_membership_check")
6472    }
6473
6474    /// [460] Wenn bei der Bestellung ein Messprodukt der Codeliste der Konfigurationen aus dem Kapitel 4.4 mit dem Übertragungsweg \"aus dem SMGW\" bestellt wurde
6475    fn evaluate_460(&self, ctx: &EvaluationContext) -> ConditionResult {
6476        ctx.external.evaluate("code_list_membership_check")
6477    }
6478
6479    /// [461] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+ZG8 (Technischen Ressource fällt unter § 14a EnWG) vorhanden
6480    fn evaluate_461(&self, ctx: &EvaluationContext) -> ConditionResult {
6481        let cci_segs = ctx.find_segments("CCI");
6482        let found = cci_segs.iter().any(|s| {
6483            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
6484        });
6485        ConditionResult::from(found)
6486    }
6487
6488    /// [462] Wenn in derselben SG10 das CCI+Z17 (Stromverbrauchsart) im CAV+ZH1 (Inbetriebsetzung der TR vor 2024) vorhanden
6489    fn evaluate_462(&self, ctx: &EvaluationContext) -> ConditionResult {
6490        let cci_segs = ctx.find_segments("CCI");
6491        let found = cci_segs.iter().any(|s| {
6492            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z17")
6493        });
6494        ConditionResult::from(found)
6495    }
6496
6497    /// [463] Wenn in derselben SG10 das CCI+Z61++ZF9 (Kunde erfüllt die Voraussetzung nach EnFG) vorhanden
6498    fn evaluate_463(&self, ctx: &EvaluationContext) -> ConditionResult {
6499        let cci_segs = ctx.find_segments("CCI");
6500        let found = cci_segs.iter().any(|s| {
6501            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z61")
6502                && s.elements.get(2).and_then(|e| e.first()).is_some_and(|v| v == "ZF9")
6503        });
6504        ConditionResult::from(found)
6505    }
6506
6507    /// [465] Wenn in derselben SG8 (Daten der Technischen Ressource) das RFF+Z38 (Referenz auf die der Technischen Ressource zugeordnete Steuerbare Ressource) vorhanden ist
6508    fn evaluate_465(&self, ctx: &EvaluationContext) -> ConditionResult {
6509        let rff_segs = ctx.find_segments("RFF");
6510        let found = rff_segs.iter().any(|s| {
6511            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z38")
6512        });
6513        ConditionResult::from(found)
6514    }
6515
6516    /// [466] Wenn in derselben SG8 (Daten der Technischen Ressource) das RFF+Z32 (Referenz auf die der Technischen Ressource zugeordneten Netzlokation) vorhanden ist
6517    fn evaluate_466(&self, ctx: &EvaluationContext) -> ConditionResult {
6518        let rff_segs = ctx.find_segments("RFF");
6519        let found = rff_segs.iter().any(|s| {
6520            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "Z32")
6521        });
6522        ConditionResult::from(found)
6523    }
6524
6525    /// [467] Wenn in derselben SG8 (Daten der Technischen Ressource) das CAV+ZG8 (Technischen Ressource fällt unter § 14a EnWG) vorhanden ist
6526    fn evaluate_467(&self, ctx: &EvaluationContext) -> ConditionResult {
6527        let segs = ctx.find_segments("CAV");
6528        let found = segs.iter().any(|s| {
6529            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZG8")
6530        });
6531        ConditionResult::from(found)
6532    }
6533
6534    /// [468] Wenn in derselben SG8 (Daten der Technischen Ressource) das SG10 CAV+ZH0 (Inbetriebsetzung der TR nach 2023) vorhanden ist
6535    fn evaluate_468(&self, ctx: &EvaluationContext) -> ConditionResult {
6536        let segs = ctx.find_segments("CAV");
6537        let found = segs.iter().any(|s| {
6538            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH0")
6539        });
6540        ConditionResult::from(found)
6541    }
6542
6543    /// [469] Wenn in derselben SG8 (Daten der Technischen Ressource) das SG10 CAV+ZH1 (Inbetriebsetzung der TR vor 2024) vorhanden ist
6544    fn evaluate_469(&self, ctx: &EvaluationContext) -> ConditionResult {
6545        let segs = ctx.find_segments("CAV");
6546        let found = segs.iter().any(|s| {
6547            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH1")
6548        });
6549        ConditionResult::from(found)
6550    }
6551
6552    /// [470] Wenn in derselben SG8 (Daten der Technischen Ressource) das CAV+ZH5 (Wechsel in das in das § 14a EnWG-Modell gem. Festlegung BK6-22-300 wurde durchgeführt) vorhanden ist
6553    fn evaluate_470(&self, ctx: &EvaluationContext) -> ConditionResult {
6554        let segs = ctx.find_segments("CAV");
6555        let found = segs.iter().any(|s| {
6556            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "ZH5")
6557        });
6558        ConditionResult::from(found)
6559    }
6560
6561    /// [471] Wenn im selben SG6 RFF+Z49/ Z53 (Verwendungszeitraum der Daten: Gültige Daten/ Keine Daten) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist als in einem anderen SG6 RFF+Z49/ ...
6562    fn evaluate_471(&self, ctx: &EvaluationContext) -> ConditionResult {
6563        // Check: SG6 RFF+Z49/Z53 has Zeitraum-ID > 1 in DE1156
6564        let found = ctx.find_segments("RFF").iter().any(|s| {
6565            let qual = s.elements.first().and_then(|e| e.first()).map(|v| v.as_str());
6566            matches!(qual, Some("Z49") | Some("Z53"))
6567                && s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| {
6568                    v.parse::<u32>().is_ok_and(|n| n > 1)
6569                })
6570        });
6571        ConditionResult::from(found)
6572    }
6573
6574    /// [472] Wenn im selben SG6 RFF+Z48/ Z55 (Verwendungszeitraum der Daten: Erwartete Daten/ Keine Daten erwartet) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist als in einem anderen SG6...
6575    fn evaluate_472(&self, ctx: &EvaluationContext) -> ConditionResult {
6576        // Check: SG6 RFF+Z48/Z55 has Zeitraum-ID > 1 in DE1156
6577        let found = ctx.find_segments("RFF").iter().any(|s| {
6578            let qual = s.elements.first().and_then(|e| e.first()).map(|v| v.as_str());
6579            matches!(qual, Some("Z48") | Some("Z55"))
6580                && s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| {
6581                    v.parse::<u32>().is_ok_and(|n| n > 1)
6582                })
6583        });
6584        ConditionResult::from(found)
6585    }
6586
6587    /// [473] Wenn im selben SG6 RFF+Z47/ Z54 (Verwendungszeitraum der Daten: Im System vorhandene Daten/ Im System keine Daten vorhanden) im DE1156 (Zeitraum-ID) eine Zeitraum ID genannt ist, die kleiner ist al...
6588    fn evaluate_473(&self, ctx: &EvaluationContext) -> ConditionResult {
6589        // Check: SG6 RFF+Z47/Z54 has Zeitraum-ID > 1 in DE1156
6590        let found = ctx.find_segments("RFF").iter().any(|s| {
6591            let qual = s.elements.first().and_then(|e| e.first()).map(|v| v.as_str());
6592            matches!(qual, Some("Z47") | Some("Z54"))
6593                && s.elements.first().and_then(|e| e.get(2)).is_some_and(|v| {
6594                    v.parse::<u32>().is_ok_and(|n| n > 1)
6595                })
6596        });
6597        ConditionResult::from(found)
6598    }
6599
6600    /// [474] Wenn SG4 STS+7++ZC8 (Transaktionsgrund \"Beendigung der Zuordnung\") vorhanden
6601    fn evaluate_474(&self, ctx: &EvaluationContext) -> ConditionResult {
6602        let sts_segs = ctx.find_segments("STS");
6603        let found = sts_segs.iter().any(|s| {
6604            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6605                && s.elements.get(2).and_then(|e| e.first())
6606                    .is_some_and(|v| ["ZC8"].contains(&v.as_str()))
6607        });
6608        ConditionResult::from(found)
6609    }
6610
6611    /// [475] Wenn SG4 STS+7++ZH1 (Transaktionsgrund \"Aufhebung einer zukünftigen Zuordnung wegen Stilllegung\") vorhanden
6612    fn evaluate_475(&self, ctx: &EvaluationContext) -> ConditionResult {
6613        let sts_segs = ctx.find_segments("STS");
6614        let found = sts_segs.iter().any(|s| {
6615            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6616                && s.elements.get(2).and_then(|e| e.first())
6617                    .is_some_and(|v| ["ZH1"].contains(&v.as_str()))
6618        });
6619        ConditionResult::from(found)
6620    }
6621
6622    /// [476] Wenn SG4 STS+7++xxx+ZW0 (Transaktionsgrundergänzung Geschäftsvorfall 1) vorhanden
6623    fn evaluate_476(&self, ctx: &EvaluationContext) -> ConditionResult {
6624        let sts_segs = ctx.find_segments("STS");
6625        let found = sts_segs.iter().any(|s| {
6626            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6627                && s.elements.get(3).and_then(|e| e.first())
6628                    .is_some_and(|v| ["ZW0"].contains(&v.as_str()))
6629        });
6630        ConditionResult::from(found)
6631    }
6632
6633    /// [477] Wenn SG4 STS+7++xxx+ZW1 (Transaktionsgrundergänzung Geschäftsvorfall 2) vorhanden
6634    fn evaluate_477(&self, ctx: &EvaluationContext) -> ConditionResult {
6635        let sts_segs = ctx.find_segments("STS");
6636        let found = sts_segs.iter().any(|s| {
6637            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6638                && s.elements.get(3).and_then(|e| e.first())
6639                    .is_some_and(|v| ["ZW1"].contains(&v.as_str()))
6640        });
6641        ConditionResult::from(found)
6642    }
6643
6644    /// [478] Wenn SG4 STS+7++xxx+ZW2 (Transaktionsgrundergänzung Geschäftsvorfall 3) vorhanden
6645    fn evaluate_478(&self, ctx: &EvaluationContext) -> ConditionResult {
6646        let sts_segs = ctx.find_segments("STS");
6647        let found = sts_segs.iter().any(|s| {
6648            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6649                && s.elements.get(3).and_then(|e| e.first())
6650                    .is_some_and(|v| ["ZW2"].contains(&v.as_str()))
6651        });
6652        ConditionResult::from(found)
6653    }
6654
6655    /// [479] Wenn SG4 STS+7++xxx+ZW3 (Transaktionsgrundergänzung Erzeugende Marktlokation) vorhanden
6656    fn evaluate_479(&self, ctx: &EvaluationContext) -> ConditionResult {
6657        let sts_segs = ctx.find_segments("STS");
6658        let found = sts_segs.iter().any(|s| {
6659            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6660                && s.elements.get(3).and_then(|e| e.first())
6661                    .is_some_and(|v| ["ZW3"].contains(&v.as_str()))
6662        });
6663        ConditionResult::from(found)
6664    }
6665
6666    /// [480] Wenn SG4 STS+7++xxx+ZW4 (Transaktionsgrundergänzung Verbrauchende Marktlokation) vorhanden
6667    fn evaluate_480(&self, ctx: &EvaluationContext) -> ConditionResult {
6668        let sts_segs = ctx.find_segments("STS");
6669        let found = sts_segs.iter().any(|s| {
6670            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6671                && s.elements.get(3).and_then(|e| e.first())
6672                    .is_some_and(|v| ["ZW4"].contains(&v.as_str()))
6673        });
6674        ConditionResult::from(found)
6675    }
6676
6677    /// [481] Wenn SG4 STS+7++xxx+ZW5 (Transaktionsgrundergänzung Tranche) vorhanden
6678    fn evaluate_481(&self, ctx: &EvaluationContext) -> ConditionResult {
6679        let sts_segs = ctx.find_segments("STS");
6680        let found = sts_segs.iter().any(|s| {
6681            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6682                && s.elements.get(3).and_then(|e| e.first())
6683                    .is_some_and(|v| ["ZW5"].contains(&v.as_str()))
6684        });
6685        ConditionResult::from(found)
6686    }
6687
6688    /// [483] Wenn SG4 STS+7++xxx+ZW7 (Transaktionsgrundergänzung Gemessene Marktlokation) vorhanden
6689    fn evaluate_483(&self, ctx: &EvaluationContext) -> ConditionResult {
6690        let sts_segs = ctx.find_segments("STS");
6691        let found = sts_segs.iter().any(|s| {
6692            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6693                && s.elements.get(3).and_then(|e| e.first())
6694                    .is_some_and(|v| ["ZW7"].contains(&v.as_str()))
6695        });
6696        ConditionResult::from(found)
6697    }
6698
6699    /// [484] Wenn SG4 STS+7++xxx+ZW8 (Transaktionsgrundergänzung Fall1) vorhanden
6700    fn evaluate_484(&self, ctx: &EvaluationContext) -> ConditionResult {
6701        let sts_segs = ctx.find_segments("STS");
6702        let found = sts_segs.iter().any(|s| {
6703            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6704                && s.elements.get(3).and_then(|e| e.first())
6705                    .is_some_and(|v| ["ZW8"].contains(&v.as_str()))
6706        });
6707        ConditionResult::from(found)
6708    }
6709
6710    /// [487] Wenn SG4 STS+7++xxx+ZX1 (Transaktionsgrundergänzung Fall4) vorhanden
6711    fn evaluate_487(&self, ctx: &EvaluationContext) -> ConditionResult {
6712        let sts_segs = ctx.find_segments("STS");
6713        let found = sts_segs.iter().any(|s| {
6714            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "7")
6715                && s.elements.get(3).and_then(|e| e.first())
6716                    .is_some_and(|v| ["ZX1"].contains(&v.as_str()))
6717        });
6718        ConditionResult::from(found)
6719    }
6720
6721    /// [489] Nur bei dem ältesten Zeitraum welcher mit SG6 RFF+Z49 (Verwendungszeitraum der Daten: Gültige Daten) beschrieben ist
6722    fn evaluate_489(&self, ctx: &EvaluationContext) -> ConditionResult {
6723        // Check: this is the oldest Zeitraum (lowest Zeitraum-ID) with RFF+Z49
6724        let rff_z49 = ctx.find_segments_with_qualifier("RFF", 0, "Z49");
6725        if rff_z49.is_empty() {
6726            return ConditionResult::Unknown;
6727        }
6728        // Approximate: condition applies when RFF+Z49 exists
6729        ConditionResult::True
6730    }
6731
6732    /// [490] Wenn Wert in diesem DE, an der Stelle CCYYMMDD ein Datum aus dem angegeben Zeitraum der Tabelle Kapitel 3.5 „Prozesszeitpunkt bei MESZ mit UTC" ist
6733    fn evaluate_490(&self, ctx: &EvaluationContext) -> ConditionResult {
6734        ctx.format_check("DTM", 0, 1, is_mesz_utc)
6735    }
6736
6737    /// [491] Wenn Wert in diesem DE, an der Stelle CCYYMMDD ein Datum aus dem angegeben Zeitraum der Tabelle Kapitel 3.6 „Prozesszeitpunkt bei MEZ mit UTC"" ist
6738    fn evaluate_491(&self, ctx: &EvaluationContext) -> ConditionResult {
6739        ctx.format_check("DTM", 0, 1, is_mez_utc)
6740    }
6741
6742    /// [494] Das hier genannte Datum muss der Zeitpunkt sein, zu dem das Dokument erstellt wurde, oder ein Zeitpunkt, der davor liegt
6743    fn evaluate_494(&self, ctx: &EvaluationContext) -> ConditionResult {
6744        // Document date must be <= now. Format 303 is CCYYMMDDHHMM — fixed-width,
6745        // so lexicographic comparison works directly.
6746        let val = ctx.resolved_value.or_else(|| {
6747            ctx.find_segments_with_qualifier("DTM", 0, "137")
6748                .first()
6749                .and_then(|s| s.elements.first())
6750                .and_then(|e| e.get(1))
6751                .map(|v| v.as_str())
6752        });
6753        let Some(dtm_val) = val else {
6754            return ConditionResult::Unknown;
6755        };
6756        if dtm_val.len() < 12 {
6757            return ConditionResult::Unknown;
6758        }
6759        let now_str = crate::eval::format_validators::utc_now_ccyymmddhhmm();
6760        ConditionResult::from(&dtm_val[..12] <= now_str.as_str())
6761    }
6762
6763    /// [500] Hinweis: Code ist gemäß der Kategorie der zu stornierenden Meldung zu wählen
6764    fn evaluate_500(&self, _ctx: &EvaluationContext) -> ConditionResult {
6765        ConditionResult::True
6766    }
6767
6768    /// [501] Hinweis: Es sind zur Unterstützung die Daten des LFA anzugeben
6769    fn evaluate_501(&self, _ctx: &EvaluationContext) -> ConditionResult {
6770        ConditionResult::True
6771    }
6772
6773    /// [502] Hinweis: Es wird der Betrachtungsmonat der DZR bzw. BAS angegeben
6774    fn evaluate_502(&self, _ctx: &EvaluationContext) -> ConditionResult {
6775        ConditionResult::True
6776    }
6777
6778    /// [503] Hinweis: Angabe des BGM DE1004 aus der ORDERS
6779    fn evaluate_503(&self, _ctx: &EvaluationContext) -> ConditionResult {
6780        ConditionResult::True
6781    }
6782
6783    /// [504] Hinweis: Je Profil (ggf. inkl. Profilschar) ein Vorgang erforderlich
6784    fn evaluate_504(&self, _ctx: &EvaluationContext) -> ConditionResult {
6785        ConditionResult::True
6786    }
6787
6788    /// [505] Hinweis: Je zugeordneter ID und je EEG-Überführungszeitreihe ein Vorgang erforderlich
6789    fn evaluate_505(&self, _ctx: &EvaluationContext) -> ConditionResult {
6790        ConditionResult::True
6791    }
6792
6793    /// [506] Hinweis: Für jeden Code im LOC+Z16 (Marktlokation) sollen die entsprechenden Kundendaten des LF angegeben werden, falls bekannt
6794    fn evaluate_506(&self, _ctx: &EvaluationContext) -> ConditionResult {
6795        ConditionResult::True
6796    }
6797
6798    /// [507] Hinweis: Ursprünglich vom NB bestätigtes Beginndatum
6799    fn evaluate_507(&self, _ctx: &EvaluationContext) -> ConditionResult {
6800        ConditionResult::True
6801    }
6802
6803    /// [508] Hinweis: Ausschließlich kME sind über die NNE abrechenbar
6804    fn evaluate_508(&self, _ctx: &EvaluationContext) -> ConditionResult {
6805        ConditionResult::True
6806    }
6807
6808    /// [509] Hinweis: Handelt sich um ein mME oder iMS ist das RFF 1154 immer mit NEIN anzugeben
6809    fn evaluate_509(&self, _ctx: &EvaluationContext) -> ConditionResult {
6810        ConditionResult::True
6811    }
6812
6813    /// [510] Hinweis: Zu verwenden bei der Abmeldung der ESV
6814    fn evaluate_510(&self, _ctx: &EvaluationContext) -> ConditionResult {
6815        ConditionResult::True
6816    }
6817
6818    /// [511] Hinweis: Es sind alle Bilanzierungsgebiete anzugeben in denen das Profil verwendet wird
6819    fn evaluate_511(&self, _ctx: &EvaluationContext) -> ConditionResult {
6820        ConditionResult::True
6821    }
6822
6823    /// [512] Hinweis: Es ist informativ die bisherige Veräußerungsform des LFA an der erzeugenden Marktlokation anzugeben
6824    fn evaluate_512(&self, _ctx: &EvaluationContext) -> ConditionResult {
6825        ConditionResult::True
6826    }
6827
6828    /// [513] Hinweis: Es ist das nächstmögliche Datum ab dem DTM+471 aus der entsprechenden Anfrage zu ermitteln
6829    fn evaluate_513(&self, _ctx: &EvaluationContext) -> ConditionResult {
6830        ConditionResult::True
6831    }
6832
6833    /// [514] Hinweis: Es darf nur eine Information im DE3148 übermittelt werden
6834    fn evaluate_514(&self, _ctx: &EvaluationContext) -> ConditionResult {
6835        ConditionResult::True
6836    }
6837
6838    /// [515] Hinweis: Für den ZP der LieferantensummenZR anzugeben
6839    fn evaluate_515(&self, _ctx: &EvaluationContext) -> ConditionResult {
6840        ConditionResult::True
6841    }
6842
6843    /// [516] Hinweis: Es ist der Änderungszeitpunkt anzugeben an dem das Zuordnungsende des NBA und der Zuordnungsbeginn des NBN zu einer Marktlokation fallen
6844    fn evaluate_516(&self, _ctx: &EvaluationContext) -> ConditionResult {
6845        ConditionResult::True
6846    }
6847
6848    /// [517] Hinweis: Anzuwenden wenn einer Marktlokation eine Paket-ID zugeordnet wurde und diese wieder gelöscht werden soll, da sie nicht unter den genannten NB-Wechsel fällt
6849    fn evaluate_517(&self, _ctx: &EvaluationContext) -> ConditionResult {
6850        ConditionResult::True
6851    }
6852
6853    /// [518] Hinweis: Es sind alle Altlieferanten anzugeben, an die eine Abmeldeanfrage gesendet wird
6854    fn evaluate_518(&self, _ctx: &EvaluationContext) -> ConditionResult {
6855        ConditionResult::True
6856    }
6857
6858    /// [519] Hinweis: Wenn in der Anmeldung der Code ZAP vorhanden war, so ist dieser auch in der Antwort zu verwenden
6859    fn evaluate_519(&self, _ctx: &EvaluationContext) -> ConditionResult {
6860        ConditionResult::True
6861    }
6862
6863    /// [520] Hinweis: Bei der Verwendung des Codes ZAP handelt es sich immer um eine gemessene Marktlokation
6864    fn evaluate_520(&self, _ctx: &EvaluationContext) -> ConditionResult {
6865        ConditionResult::True
6866    }
6867
6868    /// [521] Hinweis: Wenn im zweiten DE 9013 des STS+7 (Transaktionsgrund) der Code ZAP vorhanden ist, so ist das hier angegebene Datum als Zuordnungsbeginn bei der Bildung der \"Ruhenden MaLo zu verstehen. Be...
6869    fn evaluate_521(&self, _ctx: &EvaluationContext) -> ConditionResult {
6870        ConditionResult::True
6871    }
6872
6873    /// [522] Hinweis: Es ist der NBN anzugeben
6874    fn evaluate_522(&self, _ctx: &EvaluationContext) -> ConditionResult {
6875        ConditionResult::True
6876    }
6877
6878    /// [523] Hinweis: Mindestens einmal für jede Marktlokation bzw. Tranche, die in der DZÜ / BG-CL / LF-SZR berücksichtigt wurde
6879    fn evaluate_523(&self, _ctx: &EvaluationContext) -> ConditionResult {
6880        ConditionResult::True
6881    }
6882
6883    /// [524] Hinweis: Mindestens einmal für jede Marktlokation bzw. Tranche, für die der LF nicht die gemeldete Ansicht des NB teilt
6884    fn evaluate_524(&self, _ctx: &EvaluationContext) -> ConditionResult {
6885        ConditionResult::True
6886    }
6887
6888    /// [525] Hinweis: Es sind nur die OBIS-Kennzahlen erlaubt, die im vorherigen Stammdatenaustausch zu dieser Marktlokation vom MSB zu diesem Zeitpunkt übermittelt wurden
6889    fn evaluate_525(&self, _ctx: &EvaluationContext) -> ConditionResult {
6890        ConditionResult::True
6891    }
6892
6893    /// [526] Hinweis: Wenn der Marktlokation keine Technische Ressource in der Lokationsbündelstruktur zugeordnet wurde
6894    fn evaluate_526(&self, _ctx: &EvaluationContext) -> ConditionResult {
6895        ConditionResult::True
6896    }
6897
6898    /// [527] Hinweis: Es sind alle Identifikatoren der Messlokationen anzugeben
6899    fn evaluate_527(&self, _ctx: &EvaluationContext) -> ConditionResult {
6900        ConditionResult::True
6901    }
6902
6903    /// [528] Hinweis: Es ist das Datum/ Daten aus der Anfrage zu verwenden
6904    fn evaluate_528(&self, _ctx: &EvaluationContext) -> ConditionResult {
6905        ConditionResult::True
6906    }
6907
6908    /// [529] Hinweis: Für zusätzliche nicht im Markt standardisierte Identifikatoren wie z.B. eine Netzbetreiber-Projektnummer
6909    fn evaluate_529(&self, _ctx: &EvaluationContext) -> ConditionResult {
6910        ConditionResult::True
6911    }
6912
6913    /// [530] Hinweis: Es sind alle an der Lokation vorhandenen Daten, die mit dieser Segmentgruppe übermittelt werden und zum Datum „Änderung zum" Gültigkeit haben, anzugeben. Dies kann zur Folge haben, ...
6914    fn evaluate_530(&self, _ctx: &EvaluationContext) -> ConditionResult {
6915        ConditionResult::True
6916    }
6917
6918    /// [531] Hinweis: Es ist das Jahr anzugeben in dem die nächste Netznutzungsabrechnung erfolgt
6919    fn evaluate_531(&self, _ctx: &EvaluationContext) -> ConditionResult {
6920        ConditionResult::True
6921    }
6922
6923    /// [532] Hinweis: Kritische Daten (gemäß GPKE)
6924    fn evaluate_532(&self, _ctx: &EvaluationContext) -> ConditionResult {
6925        ConditionResult::True
6926    }
6927
6928    /// [533] Hinweis: Es ist die MP-ID des Lieferanten anzugeben
6929    fn evaluate_533(&self, _ctx: &EvaluationContext) -> ConditionResult {
6930        ConditionResult::True
6931    }
6932
6933    /// [555] Die Anwendungsfälle für die Durchführung der BDEW-Anwendungshilfe „Marktprozesse Netzbetreiberwechsel Sparte Strom" sind ab dem 01.08.2025 für Netzbetreiberwechsel ab dem 01.01.2026 zu verw...
6934    fn evaluate_555(&self, _ctx: &EvaluationContext) -> ConditionResult {
6935        // TODO: implement
6936        ConditionResult::Unknown
6937    }
6938
6939    /// [556] Hinweis: Wenn keine Korrespondenzanschrift des Endverbrauchers/ Kunden vorliegt, ist die Anschrift der Marktlokation zu übermitteln
6940    fn evaluate_556(&self, _ctx: &EvaluationContext) -> ConditionResult {
6941        ConditionResult::True
6942    }
6943
6944    /// [558] Hinweis: Diese Information kann freiwillig ausgetauscht werden
6945    fn evaluate_558(&self, _ctx: &EvaluationContext) -> ConditionResult {
6946        ConditionResult::True
6947    }
6948
6949    /// [559] Hinweis: Die Korrespondenzanschrift des Endverbrauchers/Kunden wird nicht zur Identifikation genutzt
6950    fn evaluate_559(&self, _ctx: &EvaluationContext) -> ConditionResult {
6951        ConditionResult::True
6952    }
6953
6954    /// [563] Hinweis: Für die ID der LieferantensummenZR
6955    fn evaluate_563(&self, _ctx: &EvaluationContext) -> ConditionResult {
6956        ConditionResult::True
6957    }
6958
6959    /// [566] Hinweis: Altlieferant
6960    fn evaluate_566(&self, _ctx: &EvaluationContext) -> ConditionResult {
6961        ConditionResult::True
6962    }
6963
6964    /// [567] Hinweis: Neulieferant
6965    fn evaluate_567(&self, _ctx: &EvaluationContext) -> ConditionResult {
6966        ConditionResult::True
6967    }
6968
6969    /// [568] Hinweis: Lieferant der LieferantensummenZR
6970    fn evaluate_568(&self, _ctx: &EvaluationContext) -> ConditionResult {
6971        ConditionResult::True
6972    }
6973
6974    /// [569] Hinweis: Dritter Nutzer
6975    fn evaluate_569(&self, _ctx: &EvaluationContext) -> ConditionResult {
6976        ConditionResult::True
6977    }
6978
6979    /// [570] Hinweis: Netzbetreiber Alt
6980    fn evaluate_570(&self, _ctx: &EvaluationContext) -> ConditionResult {
6981        ConditionResult::True
6982    }
6983
6984    /// [572] Hinweis: Kundenname aus Anmeldung Lieferant neu
6985    fn evaluate_572(&self, _ctx: &EvaluationContext) -> ConditionResult {
6986        ConditionResult::True
6987    }
6988
6989    /// [576] Hinweis: Stammdaten des bisherigen Messstellenbetreibers
6990    fn evaluate_576(&self, _ctx: &EvaluationContext) -> ConditionResult {
6991        ConditionResult::True
6992    }
6993
6994    /// [577] Hinweis: Wird mit dem ursprünglich vom NB bestätigten Beginnzeitpunkt gefüllt
6995    fn evaluate_577(&self, _ctx: &EvaluationContext) -> ConditionResult {
6996        ConditionResult::True
6997    }
6998
6999    /// [579] Hinweis: Auslösender Marktpartner (LFN bei STS+7++ZH0/ZG9, NB bei STS+7++ZH1)
7000    fn evaluate_579(&self, _ctx: &EvaluationContext) -> ConditionResult {
7001        ConditionResult::True
7002    }
7003
7004    /// [580] Hinweis:  Ersatzbelieferung gibt es nur bei  - Marktlokationen in der  Niederspannung, die kein Haushaltskunde gem. EnWG sind und die nicht mehr der gesetzlichen Ersatzversorgung (drei Monate) unte...
7005    fn evaluate_580(&self, _ctx: &EvaluationContext) -> ConditionResult {
7006        ConditionResult::True
7007    }
7008
7009    /// [581] Hinweis: Es ist der Zeitpunkt anzugeben, zu welchem der Vertrag am Tag des Versandes der Antwort noch kündbar ist.
7010    fn evaluate_581(&self, _ctx: &EvaluationContext) -> ConditionResult {
7011        ConditionResult::True
7012    }
7013
7014    /// [586] Hinweis: Die Messlokationsadresse ist der Messlokation zugeordnet, welche in SG8 SEQ+Z18/ ZF3 (Daten der Messlokation) mit CCI+Z01++Z82 (Verwendungsumfang: ID der prozessual behandelten Messlokatio...
7015    fn evaluate_586(&self, _ctx: &EvaluationContext) -> ConditionResult {
7016        ConditionResult::True
7017    }
7018
7019    /// [590] Hinweis: Für den Empfang des Steuerbefehls
7020    fn evaluate_590(&self, _ctx: &EvaluationContext) -> ConditionResult {
7021        ConditionResult::True
7022    }
7023
7024    /// [594] Hinweis: Es ist der ZPB des ZP der NGZ und die ZPB der NZR anzugeben
7025    fn evaluate_594(&self, _ctx: &EvaluationContext) -> ConditionResult {
7026        ConditionResult::True
7027    }
7028
7029    /// [599] Hinweis: Es ist der Name und die Adresse des Ablesekartenempfängers für die Messlokation anzugeben, welche in SG8 SEQ+Z18 (Daten der Messlokation) mit CCI+Z01++Z82 (Verwendungsumfang: ID der proz...
7030    fn evaluate_599(&self, _ctx: &EvaluationContext) -> ConditionResult {
7031        ConditionResult::True
7032    }
7033
7034    /// [601] Hinweis: Es ist die ID der Marktlokation und alle Identifikatoren der Messlokationen anzugeben. Sowie wenn vorhanden die Tranche/n der Marklokation
7035    fn evaluate_601(&self, _ctx: &EvaluationContext) -> ConditionResult {
7036        ConditionResult::True
7037    }
7038
7039    /// [606] Hinweis: In diesem Segment bzw. SG sind die Daten aus der Sicht des NB anzugeben
7040    fn evaluate_606(&self, _ctx: &EvaluationContext) -> ConditionResult {
7041        ConditionResult::True
7042    }
7043
7044    /// [609] Hinweis: In diesem Segment bzw. SG sind die zwischen NB, LF und ÜNB im Rahmen der Marktkommunikation ausgetauschten Daten aus der Sicht des ÜNB anzugeben
7045    fn evaluate_609(&self, _ctx: &EvaluationContext) -> ConditionResult {
7046        ConditionResult::True
7047    }
7048
7049    /// [611] Hinweis: Wenn das Unternehmen NB die Aufgaben der Marktrolle LF wahrnimmt, ist die MP-ID des Unternehmens NB in der Marktrolle LF anzugeben
7050    fn evaluate_611(&self, _ctx: &EvaluationContext) -> ConditionResult {
7051        ConditionResult::True
7052    }
7053
7054    /// [614] Hinweis: Es werden nur die OBIS Kennzahlen übermittelt die für die Bilanzierung relevant sind
7055    fn evaluate_614(&self, _ctx: &EvaluationContext) -> ConditionResult {
7056        ConditionResult::True
7057    }
7058
7059    /// [617] Hinweis: Mehrere Vorgänge für eine Marktlokation bei Wechsel bilanzierungsrelevanter Stammdaten innerhalb des Bilanzierungsmonats
7060    fn evaluate_617(&self, _ctx: &EvaluationContext) -> ConditionResult {
7061        ConditionResult::True
7062    }
7063
7064    /// [618] Hinweis: Bisheriges Datum des MSBA. Sollte der MSBN ein abweichendes Datum verwenden wollen, so teilt er das neue Datum mit einer Stammdatenänderung mit
7065    fn evaluate_618(&self, _ctx: &EvaluationContext) -> ConditionResult {
7066        ConditionResult::True
7067    }
7068
7069    /// [619] Hinweis: Für die selbständige Änderungsmöglichkeit der Schwellwertunter- / -über-schreitung
7070    fn evaluate_619(&self, _ctx: &EvaluationContext) -> ConditionResult {
7071        ConditionResult::True
7072    }
7073
7074    /// [621] Hinweis: Es ist der MSB anzugeben, welcher ab dem Zeitpunkt der Lokation zugeordnet ist, der in DTM+76 (Datum zum geplanten Leistungsbeginn) genannt ist.
7075    fn evaluate_621(&self, _ctx: &EvaluationContext) -> ConditionResult {
7076        ConditionResult::True
7077    }
7078
7079    /// [622] Hinweis: Falls die OBIS-Kennzahl für mehrere Marktrollen relevant ist, so muss die Segmentgruppe pro Marktrolle wiederholt werden
7080    fn evaluate_622(&self, _ctx: &EvaluationContext) -> ConditionResult {
7081        ConditionResult::True
7082    }
7083
7084    /// [623] Hinweis: Es sind alle Identifikatoren der Messlokationen anzugeben, die zur Ermittlung der Energiemenge der im Vorgang genannten Marktlokation benötigt werden
7085    fn evaluate_623(&self, _ctx: &EvaluationContext) -> ConditionResult {
7086        ConditionResult::True
7087    }
7088
7089    /// [630] Hinweis: Wenn die Liste abgelehnt wird, ist kein Vorgang enthalten
7090    fn evaluate_630(&self, _ctx: &EvaluationContext) -> ConditionResult {
7091        ConditionResult::True
7092    }
7093
7094    /// [631] Hinweis: Es ist die Listennummer aus der Lieferanten- bzw. Bilanzierungsgebietsclearingliste zu verwenden
7095    fn evaluate_631(&self, _ctx: &EvaluationContext) -> ConditionResult {
7096        ConditionResult::True
7097    }
7098
7099    /// [632] Hinweis: Es ist die Listennummer aus der Lieferanten-ausfallarbeits-clearingliste zu verwenden
7100    fn evaluate_632(&self, _ctx: &EvaluationContext) -> ConditionResult {
7101        ConditionResult::True
7102    }
7103
7104    /// [637] Hinweis: Bei Verpflichtungsanfrage
7105    fn evaluate_637(&self, _ctx: &EvaluationContext) -> ConditionResult {
7106        ConditionResult::True
7107    }
7108
7109    /// [638] Hinweis: Bei Aufforderung zur Übernahme der einzelnen Messlokation durch den gMSB
7110    fn evaluate_638(&self, _ctx: &EvaluationContext) -> ConditionResult {
7111        ConditionResult::True
7112    }
7113
7114    /// [639] Hinweis: Wenn Antwort auf Deaktivierung
7115    fn evaluate_639(&self, _ctx: &EvaluationContext) -> ConditionResult {
7116        ConditionResult::True
7117    }
7118
7119    /// [640] Hinweis: Wenn Antwort auf Aktivierung
7120    fn evaluate_640(&self, _ctx: &EvaluationContext) -> ConditionResult {
7121        ConditionResult::True
7122    }
7123
7124    /// [641] Hinweis: Wenn Einzelanforderung vorliegt
7125    fn evaluate_641(&self, _ctx: &EvaluationContext) -> ConditionResult {
7126        ConditionResult::True
7127    }
7128
7129    /// [642] Hinweis: Wenn Abo vorliegt
7130    fn evaluate_642(&self, _ctx: &EvaluationContext) -> ConditionResult {
7131        ConditionResult::True
7132    }
7133
7134    /// [643] Hinweis: Nachfolgender Netzbetreiber
7135    fn evaluate_643(&self, _ctx: &EvaluationContext) -> ConditionResult {
7136        ConditionResult::True
7137    }
7138
7139    /// [645] Hinweis: Es ist der Bilanzkreis des LF anzugeben
7140    fn evaluate_645(&self, _ctx: &EvaluationContext) -> ConditionResult {
7141        ConditionResult::True
7142    }
7143
7144    /// [646] Hinweis: Es ist der RD-Bilanzkreis des ANB anzugeben
7145    fn evaluate_646(&self, _ctx: &EvaluationContext) -> ConditionResult {
7146        ConditionResult::True
7147    }
7148
7149    /// [647] Hinweis: Es ist der RD-Bilanzkreis des anfNB anzugeben
7150    fn evaluate_647(&self, _ctx: &EvaluationContext) -> ConditionResult {
7151        ConditionResult::True
7152    }
7153
7154    /// [648] Hinweis: Soll ein Produkt ab dem Datum \"Änderung zum\" nicht mehr vorhanden sein, wird dies durch nicht angeben des PIA+5 ausgedrückt
7155    fn evaluate_648(&self, _ctx: &EvaluationContext) -> ConditionResult {
7156        ConditionResult::True
7157    }
7158
7159    /// [651] Hinweis: Es sind die Marktlokationen anzugeben, zu welchen die hier genannte OBIS benötigt wird
7160    fn evaluate_651(&self, _ctx: &EvaluationContext) -> ConditionResult {
7161        ConditionResult::True
7162    }
7163
7164    /// [653] Hinweis: Es sind alle Netzlokationen, Marktlokationen, Tranchen und Messlokationen zu nennen, die durch die Bestätigung der Abmeldung der prozessual behandelten Messlokation nicht mehr dem MSB zug...
7165    fn evaluate_653(&self, _ctx: &EvaluationContext) -> ConditionResult {
7166        ConditionResult::True
7167    }
7168
7169    /// [655] Hinweis: Es ist die Listennummer aus der DZÜ Liste zu verwenden
7170    fn evaluate_655(&self, _ctx: &EvaluationContext) -> ConditionResult {
7171        ConditionResult::True
7172    }
7173
7174    /// [659] Hinweis: Bei Tranchen ist nur der Meldepunkt der Tranche anzugeben
7175    fn evaluate_659(&self, _ctx: &EvaluationContext) -> ConditionResult {
7176        ConditionResult::True
7177    }
7178
7179    /// [660] Hinweis: Es ist die ID der BK-Summenzeitreihe Aggregationsebene BG anzugeben
7180    fn evaluate_660(&self, _ctx: &EvaluationContext) -> ConditionResult {
7181        ConditionResult::True
7182    }
7183
7184    /// [662] Hinweis: Es sind die Daten NGZ und die Daten der NZR anzugeben
7185    fn evaluate_662(&self, _ctx: &EvaluationContext) -> ConditionResult {
7186        ConditionResult::True
7187    }
7188
7189    /// [663] Hinweis: Es ist die ID der Marktlokation und die ZPB des ZP der NGZ anzugeben
7190    fn evaluate_663(&self, _ctx: &EvaluationContext) -> ConditionResult {
7191        ConditionResult::True
7192    }
7193
7194    /// [664] Hinweis: Es ist das BG des NB (LPB) anzugeben
7195    fn evaluate_664(&self, _ctx: &EvaluationContext) -> ConditionResult {
7196        ConditionResult::True
7197    }
7198
7199    /// [665] Hinweis: Wenn ein Zähler mit einem SMGW parametriert ist werden an dem Zähler keine OBIS-Kennzahlen angegeben Hier gibt es nur OBIS Kennzahlen vom SMGW
7200    fn evaluate_665(&self, _ctx: &EvaluationContext) -> ConditionResult {
7201        ConditionResult::True
7202    }
7203
7204    /// [667] Hinweis: Für Zeiten die bilanziert wurden, aber inzwischen keine Aggregationsverantwortung beim ÜNB vorliegt, ist eine SG8 mit SG8 - SG10 CCI+6=ZA8 oder SG 10 CCI+6 = ZA9 CAV=ZG4 und SG8 - SG9 QT...
7205    fn evaluate_667(&self, _ctx: &EvaluationContext) -> ConditionResult {
7206        ConditionResult::True
7207    }
7208
7209    /// [668] Hinweis: Dieses Segment wird nach Abschluss der Einführung der Lokationsbündelstruktur zum 01.10.2025 aus der UTILMD entfernt
7210    fn evaluate_668(&self, _ctx: &EvaluationContext) -> ConditionResult {
7211        ConditionResult::True
7212    }
7213
7214    /// [670] Hinweis: Es sind alle Netzlokationen, zu nennen, die dem gleichen Lokationsbündel angehören
7215    fn evaluate_670(&self, _ctx: &EvaluationContext) -> ConditionResult {
7216        ConditionResult::True
7217    }
7218
7219    /// [671] Hinweis: Es sind alle Marktlokationen, zu nennen, die dem gleichen Lokationsbündel angehören
7220    fn evaluate_671(&self, _ctx: &EvaluationContext) -> ConditionResult {
7221        ConditionResult::True
7222    }
7223
7224    /// [672] Hinweis: Es sind alle Technischen Ressourcen, zu nennen, die dem gleichen Lokationsbündel angehören
7225    fn evaluate_672(&self, _ctx: &EvaluationContext) -> ConditionResult {
7226        ConditionResult::True
7227    }
7228
7229    /// [673] Hinweis: Es sind alle Steuerbaren Ressourcen, zu nennen, die dem gleichen Lokationsbündel angehören
7230    fn evaluate_673(&self, _ctx: &EvaluationContext) -> ConditionResult {
7231        ConditionResult::True
7232    }
7233
7234    /// [674] Hinweis: Es sind alle Tranchen, zu nennen, die dem gleichen Lokationsbündel angehören
7235    fn evaluate_674(&self, _ctx: &EvaluationContext) -> ConditionResult {
7236        ConditionResult::True
7237    }
7238
7239    /// [675] Hinweis: Es sind alle Messlokationen, zu nennen, die Lokationsbündel angehören
7240    fn evaluate_675(&self, _ctx: &EvaluationContext) -> ConditionResult {
7241        ConditionResult::True
7242    }
7243
7244    /// [677] Hinweis: Es sind alle Netzlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
7245    fn evaluate_677(&self, _ctx: &EvaluationContext) -> ConditionResult {
7246        ConditionResult::True
7247    }
7248
7249    /// [678] Hinweis: Es sind alle Marktlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
7250    fn evaluate_678(&self, _ctx: &EvaluationContext) -> ConditionResult {
7251        ConditionResult::True
7252    }
7253
7254    /// [679] Hinweis: Es sind alle Technischen Ressourcen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
7255    fn evaluate_679(&self, _ctx: &EvaluationContext) -> ConditionResult {
7256        ConditionResult::True
7257    }
7258
7259    /// [680] Hinweis: Es sind alle Steuerbaren Ressourcen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
7260    fn evaluate_680(&self, _ctx: &EvaluationContext) -> ConditionResult {
7261        ConditionResult::True
7262    }
7263
7264    /// [682] Hinweis: Es sind alle Messlokationen, zu nennen, die aktuell und / oder zukünftig dem gleichen Lokationsbündel angehören
7265    fn evaluate_682(&self, _ctx: &EvaluationContext) -> ConditionResult {
7266        ConditionResult::True
7267    }
7268
7269    /// [683] Hinweis: Es sind alle ID der Netzlokationen, welche der im SG5 LOC+Z16 angegebenen Marktlokation aktuell und / oder zukünftig vorgelagert sind, anzugeben
7270    fn evaluate_683(&self, _ctx: &EvaluationContext) -> ConditionResult {
7271        ConditionResult::True
7272    }
7273
7274    /// [684] Hinweis: Es sind alle ID der Technischen Ressourcen, welche der im LOC+Z16/ Z22 angegebenen Marktlokation aktuell und / oder zukünftig zugehören, anzugeben
7275    fn evaluate_684(&self, _ctx: &EvaluationContext) -> ConditionResult {
7276        ConditionResult::True
7277    }
7278
7279    /// [685] Hinweis: Es sind alle ID der Steuerbaren Ressourcen, welche der im LOC+Z20 angegebenen Technischen Ressourcen aktuell und / oder zukünftig zugeordnet sind, anzugeben.
7280    fn evaluate_685(&self, _ctx: &EvaluationContext) -> ConditionResult {
7281        ConditionResult::True
7282    }
7283
7284    /// [687] Hinweis: Es sind alle Messlokationen zu nennen, die für die Energiemengenermittlung aktuell und / oder zukünftig der im LOC+Z16/ Z22 angegebenen Marktlokation notwendig sind
7285    fn evaluate_687(&self, _ctx: &EvaluationContext) -> ConditionResult {
7286        ConditionResult::True
7287    }
7288
7289    /// [688] Hinweis: Es sind alle ID der Netzlokationen, welche der im LOC+Z16 angegebenen Marktlokation vorgelagert sind, anzugeben
7290    fn evaluate_688(&self, _ctx: &EvaluationContext) -> ConditionResult {
7291        ConditionResult::True
7292    }
7293
7294    /// [689] Hinweis: Es sind alle ID der Technischen Ressourcen, welche der im LOC+Z16 angegebenen Marktlokation zugehören, anzugeben
7295    fn evaluate_689(&self, _ctx: &EvaluationContext) -> ConditionResult {
7296        ConditionResult::True
7297    }
7298
7299    /// [690] Hinweis: Es sind alle ID der Steuerbaren Ressourcen, welche der im LOC+Z20 angegebenen Technischen Ressourcen zugeordnet sind, anzugeben
7300    fn evaluate_690(&self, _ctx: &EvaluationContext) -> ConditionResult {
7301        ConditionResult::True
7302    }
7303
7304    /// [693] Hinweis: Es sind die Daten NGZ anzugeben
7305    fn evaluate_693(&self, _ctx: &EvaluationContext) -> ConditionResult {
7306        ConditionResult::True
7307    }
7308
7309    /// [694] Hinweis: Wenn in einer Marktlokation eine ID für eine Technischen Ressource vergeben wird, müssen für alle ggf. weitere Technische Ressourcen in der Marktlokation ID vergeben werden. Hintergrund...
7310    fn evaluate_694(&self, _ctx: &EvaluationContext) -> ConditionResult {
7311        ConditionResult::True
7312    }
7313
7314    /// [695] Hinweis: Verwendung, wenn Rolle LF einem Unternehmen NB zugeordnet ist
7315    fn evaluate_695(&self, _ctx: &EvaluationContext) -> ConditionResult {
7316        ConditionResult::True
7317    }
7318
7319    /// [696] Hinweis: Verwendung, nur wenn die Rolle LF nicht einem Unternehmen NB zugeordnet ist
7320    fn evaluate_696(&self, _ctx: &EvaluationContext) -> ConditionResult {
7321        ConditionResult::True
7322    }
7323
7324    /// [698] Hinweis: Für eine erzeugende Marktlokation muss für jede Technische Ressource eine ID der Technischen Ressourcen vergeben werden. Dies ist notwendig um die Nennleistung der Technische Ressource b...
7325    fn evaluate_698(&self, _ctx: &EvaluationContext) -> ConditionResult {
7326        ConditionResult::True
7327    }
7328
7329    /// [699] Hinweis: Es ist die ID der Steuerbare Ressource zu nennen über die die Technische Ressource gesteuert wird
7330    fn evaluate_699(&self, _ctx: &EvaluationContext) -> ConditionResult {
7331        ConditionResult::True
7332    }
7333
7334    /// [700] Hinweis: Es ist die ID der Netzlokation zu nennen über die die Technische Ressource gesteuert wird
7335    fn evaluate_700(&self, _ctx: &EvaluationContext) -> ConditionResult {
7336        ConditionResult::True
7337    }
7338
7339    /// [704] Hinweis: Segment ist zu verwenden, wenn es in Anfrage vorhanden war
7340    fn evaluate_704(&self, _ctx: &EvaluationContext) -> ConditionResult {
7341        ConditionResult::True
7342    }
7343
7344    /// [705] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Rückmeldung auf Änderung\" durchgeführt wird
7345    fn evaluate_705(&self, _ctx: &EvaluationContext) -> ConditionResult {
7346        ConditionResult::True
7347    }
7348
7349    /// [706] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Bestellung einer Änderung von Stammdaten...\" durchgeführt wird, mit dem Ziel ein Datenclearing durchzuführen
7350    fn evaluate_706(&self, ctx: &EvaluationContext) -> ConditionResult {
7351        ctx.external.evaluate("data_clearing_required")
7352    }
7353
7354    /// [707] Hinweis: für weitere Details siehe Kapitel \"SG6 Verwendungszeitraum der Daten\"
7355    fn evaluate_707(&self, _ctx: &EvaluationContext) -> ConditionResult {
7356        ConditionResult::True
7357    }
7358
7359    /// [708] Hinweis: Wenn die Aktion \"Ankündigung der Zuordnung des E/G zur Marktlokation\" durchgeführt wird
7360    fn evaluate_708(&self, _ctx: &EvaluationContext) -> ConditionResult {
7361        ConditionResult::True
7362    }
7363
7364    /// [709] Hinweis: Wenn die Aktion \"Zuordnung des E/G zur Marktlokation aufgrund fehlender Antwort\" durchgeführt wird
7365    fn evaluate_709(&self, _ctx: &EvaluationContext) -> ConditionResult {
7366        ConditionResult::True
7367    }
7368
7369    /// [710] Hinweis: Wenn die Aktion \"Ankündigung der Zuordnung des LFN zur Marktlokation bzw. Tranche\" durchgeführt wird
7370    fn evaluate_710(&self, _ctx: &EvaluationContext) -> ConditionResult {
7371        ConditionResult::True
7372    }
7373
7374    /// [711] Hinweis: Wenn die Aktion \"Zuordnung des LFN zur Marktlokation bzw. Tranche aufgrund fehlender Antwort\" durchgeführt wird
7375    fn evaluate_711(&self, _ctx: &EvaluationContext) -> ConditionResult {
7376        ConditionResult::True
7377    }
7378
7379    /// [712] Hinweis: Wenn die Aktion \"Ankündigung der Beendigung der Zuordnung des LF zur Marktlokation bzw. Tranche\" durchgeführt wird
7380    fn evaluate_712(&self, _ctx: &EvaluationContext) -> ConditionResult {
7381        ConditionResult::True
7382    }
7383
7384    /// [713] Hinweis: Wenn die Aktion \"Beendigung der Zuordnung des LF zur Marktlokation bzw. Tranche aufgrund fehlender Antwort\" durchgeführt wird
7385    fn evaluate_713(&self, _ctx: &EvaluationContext) -> ConditionResult {
7386        ConditionResult::True
7387    }
7388
7389    /// [714] Hinweis: Es ist bei einer unterjährigen Gebietsübernahme möglich hier den bisherigen NB zu nennen um aufzuzeigen, dass die im PIA+5 dieser SG8 genannten Gruppenartikel-ID bzw. Artikel-ID auf die...
7390    fn evaluate_714(&self, _ctx: &EvaluationContext) -> ConditionResult {
7391        ConditionResult::True
7392    }
7393
7394    /// [715] Hinweis: Dieser Transaktionsgrund darf für die betroffene Lokation nur angewendet werden wenn zuvor vom LF eine Anfrage Abr.-Daten BK-Abr. in die Vergangenheit erfolgte oder eine Korrektur zuvor m...
7395    fn evaluate_715(&self, _ctx: &EvaluationContext) -> ConditionResult {
7396        ConditionResult::True
7397    }
7398
7399    /// [716] Hinweis: Wenn die Aktion eines Sequenzdiagramms \"Rückmeldung auf Abrechnungsdaten\" durchgeführt wird
7400    fn evaluate_716(&self, _ctx: &EvaluationContext) -> ConditionResult {
7401        ConditionResult::True
7402    }
7403
7404    /// [717] Hinweis: Wenn die Aktion des Sequenzdiagramms \"Bestellung einer Änderung von Abrechnungsdaten\" durchgeführt wird, mit dem Ziel ein Datenclearing durchzuführen
7405    fn evaluate_717(&self, ctx: &EvaluationContext) -> ConditionResult {
7406        ctx.external.evaluate("data_clearing_required")
7407    }
7408
7409    /// [718] Hinweis: Es sind alle Tranchen der im SG5 LOC+Z16 (Marktlokation) genannten Marktlokation anzugeben, die für die im SG6 (Verwendungszeitraum der Daten) genannten Zeiträume vorhanden sind
7410    fn evaluate_718(&self, _ctx: &EvaluationContext) -> ConditionResult {
7411        ConditionResult::True
7412    }
7413
7414    /// [719] Hinweis: Dieser Transaktionsgrund darf für die betroffene Lokation nur angewendet werden wenn der LF auf eine Anfrage mit diesem Transaktionsgrund antwortet oder eine Anfrage Abr.-Daten BK-Abr. in...
7415    fn evaluate_719(&self, _ctx: &EvaluationContext) -> ConditionResult {
7416        ConditionResult::True
7417    }
7418
7419    /// [902] Format: Möglicher Wert: ≥ 0
7420    fn evaluate_902(&self, _ctx: &EvaluationContext) -> ConditionResult {
7421        // Format condition — informational, always applies
7422        ConditionResult::True
7423    }
7424
7425    /// [910] Format: Möglicher Wert: < 0 oder ≥ 0
7426    fn evaluate_910(&self, _ctx: &EvaluationContext) -> ConditionResult {
7427        // Format condition — informational, always applies
7428        ConditionResult::True
7429    }
7430
7431    /// [914] Format: Möglicher Wert: > 0
7432    fn evaluate_914(&self, ctx: &EvaluationContext) -> ConditionResult {
7433        ctx.format_check("SEQ", 1, 0, |val| validate_numeric(val, ">", 0.0))
7434    }
7435
7436    /// [922] Format: TR-ID
7437    fn evaluate_922(&self, _ctx: &EvaluationContext) -> ConditionResult {
7438        // Format condition — informational, always applies
7439        ConditionResult::True
7440    }
7441
7442    /// [926] Format: Möglicher Wert: 0
7443    fn evaluate_926(&self, _ctx: &EvaluationContext) -> ConditionResult {
7444        // Format condition — informational, always applies
7445        ConditionResult::True
7446    }
7447
7448    /// [930] Format: max. 2 Nachkommastellen
7449    fn evaluate_930(&self, _ctx: &EvaluationContext) -> ConditionResult {
7450        // Format condition — informational, always applies
7451        ConditionResult::True
7452    }
7453
7454    /// [931] Format: ZZZ = +00
7455    fn evaluate_931(&self, ctx: &EvaluationContext) -> ConditionResult {
7456        ctx.format_check("DTM", 0, 1, validate_timezone_utc)
7457    }
7458
7459    /// [932] Format: HHMM = 2200
7460    fn evaluate_932(&self, ctx: &EvaluationContext) -> ConditionResult {
7461        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2200"))
7462    }
7463
7464    /// [933] Format: HHMM = 2300
7465    fn evaluate_933(&self, ctx: &EvaluationContext) -> ConditionResult {
7466        ctx.format_check("DTM", 0, 1, |val| validate_hhmm_equals(val, "2300"))
7467    }
7468
7469    /// [937] Format: keine Nachkommastelle
7470    fn evaluate_937(&self, ctx: &EvaluationContext) -> ConditionResult {
7471        ctx.format_check("SEQ", 1, 0, |val| validate_max_decimal_places(val, 0))
7472    }
7473
7474    /// [938] Format: Möglicher Wert: <= 10
7475    fn evaluate_938(&self, _ctx: &EvaluationContext) -> ConditionResult {
7476        ConditionResult::True
7477    }
7478
7479    /// [939] Format: Die Zeichenkette muss die Zeichen @ und . enthalten
7480    fn evaluate_939(&self, ctx: &EvaluationContext) -> ConditionResult {
7481        ctx.format_check("COM", 0, 0, validate_email)
7482    }
7483
7484    /// [940] Format: Die Zeichenkette muss mit dem Zeichen + beginnen und danach dürfen nur noch Ziffern folgen
7485    fn evaluate_940(&self, ctx: &EvaluationContext) -> ConditionResult {
7486        ctx.format_check("COM", 0, 0, validate_phone)
7487    }
7488
7489    /// [942] Format: n1-n2-n1-n3
7490    fn evaluate_942(&self, _ctx: &EvaluationContext) -> ConditionResult {
7491        // Format condition — informational, always applies
7492        ConditionResult::True
7493    }
7494
7495    /// [943] Format: n1-n2-n1
7496    fn evaluate_943(&self, _ctx: &EvaluationContext) -> ConditionResult {
7497        // Format condition — informational, always applies
7498        ConditionResult::True
7499    }
7500
7501    /// [946] Format: max. 11 Nachkommastellen
7502    fn evaluate_946(&self, _ctx: &EvaluationContext) -> ConditionResult {
7503        // Format condition — informational, always applies
7504        ConditionResult::True
7505    }
7506
7507    /// [948] Format: n1-n2-n1-n8-n2
7508    fn evaluate_948(&self, _ctx: &EvaluationContext) -> ConditionResult {
7509        // Format condition — informational, always applies
7510        ConditionResult::True
7511    }
7512
7513    /// [950] Format: Marktlokations-ID
7514    fn evaluate_950(&self, _ctx: &EvaluationContext) -> ConditionResult {
7515        // Format condition — informational, always applies
7516        ConditionResult::True
7517    }
7518
7519    /// [951] Format: Zählpunktbezeichnung
7520    fn evaluate_951(&self, _ctx: &EvaluationContext) -> ConditionResult {
7521        // Format condition — informational, always applies
7522        ConditionResult::True
7523    }
7524
7525    /// [952] Format: Gerätenummer nach DIN 43863-5
7526    fn evaluate_952(&self, _ctx: &EvaluationContext) -> ConditionResult {
7527        // Format condition — informational, always applies
7528        ConditionResult::True
7529    }
7530
7531    /// [955] Format: Möglicher Wert: < 100
7532    fn evaluate_955(&self, _ctx: &EvaluationContext) -> ConditionResult {
7533        // Format condition — informational, always applies
7534        ConditionResult::True
7535    }
7536
7537    /// [957] Format: n1-n2-n1-n8
7538    fn evaluate_957(&self, _ctx: &EvaluationContext) -> ConditionResult {
7539        // Format condition — informational, always applies
7540        ConditionResult::True
7541    }
7542
7543    /// [960] Format: Netzlokations-ID
7544    fn evaluate_960(&self, _ctx: &EvaluationContext) -> ConditionResult {
7545        // Format condition — informational, always applies
7546        ConditionResult::True
7547    }
7548
7549    /// [961] Format: SR-ID
7550    fn evaluate_961(&self, _ctx: &EvaluationContext) -> ConditionResult {
7551        // Format condition — informational, always applies
7552        ConditionResult::True
7553    }
7554
7555    /// [967] Format: Zertifikatskörper gemäß X509.1, BSI TR-03109-4
7556    fn evaluate_967(&self, _ctx: &EvaluationContext) -> ConditionResult {
7557        // Format condition — informational, always applies
7558        ConditionResult::True
7559    }
7560
7561    /// [2001] Segmentgruppe ist mindestens zweimal je SG4 IDE+24 (Vorgang) anzugeben
7562    fn evaluate_2001(&self, ctx: &EvaluationContext) -> ConditionResult {
7563        // Cardinality: at least twice per SG4 IDE+24
7564        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7565        ConditionResult::from(ide_count > 0)
7566    }
7567
7568    /// [2002] Für jede Produktpaket-ID im SG8 SEQ+Z79 (Erforderliches Produkt) DE1050 genau einmal anzugeben
7569    fn evaluate_2002(&self, ctx: &EvaluationContext) -> ConditionResult {
7570        let seq_segs = ctx.find_segments("SEQ");
7571        let has_z79 = seq_segs.iter().any(|s| {
7572            s.elements.first()
7573                .and_then(|e| e.first())
7574                .is_some_and(|v| v == "Z79")
7575        });
7576        ConditionResult::from(has_z79)
7577    }
7578
7579    /// [2003] Einmal für jede ruhende Marktlokation, die der Marktlokation \"Kundenanlage\" aus dem SG5 LOC+Z16 (Marktlokation) ab dem Zeitpunkt aus dem SG4 DTM+92 (Beginn zum) untergeordnet ist
7580    fn evaluate_2003(&self, _ctx: &EvaluationContext) -> ConditionResult {
7581        // TODO: implement
7582        ConditionResult::Unknown
7583    }
7584
7585    /// [2004] Segmentgruppe ist genau einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: "Gültige Daten") anzugeben
7586    // REVIEW: Collects Zeitraum-IDs from SG6 RFF+Z49 DE1156 (elements[0][2]) by correlating qualifier (elements[0][0]) and ID (elements[0][2]) vectors via shared SG6 instance index. Then collects all SEQ DE1050 (elements[1][0]) references from SG8 instances. For each Zeitraum-ID from SG6 RFF+Z49, counts matching SG8 SEQ references; returns False if any count != 1 (violates 'exactly once' cardinality). Returns Unknown if no RFF+Z49 Zeitraum-IDs exist. (medium confidence)
7587    fn evaluate_2004(&self, ctx: &EvaluationContext) -> ConditionResult {
7588        let rff_qualifiers = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG6"]);
7589        let rff_zeitraum_ids = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG6"]);
7590
7591        let zeitraum_ids: Vec<String> = rff_qualifiers
7592            .iter()
7593            .filter(|(_, qual)| qual.as_str() == "Z49")
7594            .filter_map(|(idx, _)| {
7595                rff_zeitraum_ids
7596                    .iter()
7597                    .find(|(i, v)| i == idx && !v.is_empty())
7598                    .map(|(_, v)| v.clone())
7599            })
7600            .collect();
7601
7602        if zeitraum_ids.is_empty() {
7603            return ConditionResult::Unknown;
7604        }
7605
7606        let seq_refs = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
7607
7608        for zid in &zeitraum_ids {
7609            let count = seq_refs.iter().filter(|(_, v)| v == zid).count();
7610            if count != 1 {
7611                return ConditionResult::False;
7612            }
7613        }
7614
7615        ConditionResult::True
7616    }
7617
7618    /// [2005] Segmentgruppe ist mindesten einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 (Verwendungszeitraum der Daten: "Gültige Daten") anzugeben
7619    // REVIEW: Same logic as 2004 but enforces 'at least once' cardinality (count >= 1) instead of 'exactly once'. Collects Zeitraum-IDs from SG6 RFF+Z49 DE1156 and checks that each has at least one matching SG8 SEQ DE1050 reference. Returns False if any Zeitraum-ID has zero matching SG8 references. (medium confidence)
7620    fn evaluate_2005(&self, ctx: &EvaluationContext) -> ConditionResult {
7621        let rff_qualifiers = ctx.collect_group_values("RFF", 0, 0, &["SG4", "SG6"]);
7622        let rff_zeitraum_ids = ctx.collect_group_values("RFF", 0, 2, &["SG4", "SG6"]);
7623
7624        let zeitraum_ids: Vec<String> = rff_qualifiers
7625            .iter()
7626            .filter(|(_, qual)| qual.as_str() == "Z49")
7627            .filter_map(|(idx, _)| {
7628                rff_zeitraum_ids
7629                    .iter()
7630                    .find(|(i, v)| i == idx && !v.is_empty())
7631                    .map(|(_, v)| v.clone())
7632            })
7633            .collect();
7634
7635        if zeitraum_ids.is_empty() {
7636            return ConditionResult::Unknown;
7637        }
7638
7639        let seq_refs = ctx.collect_group_values("SEQ", 1, 0, &["SG4", "SG8"]);
7640
7641        for zid in &zeitraum_ids {
7642            let count = seq_refs.iter().filter(|(_, v)| v == zid).count();
7643            if count == 0 {
7644                return ConditionResult::False;
7645            }
7646        }
7647
7648        ConditionResult::True
7649    }
7650
7651    /// [2010] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [266] ∧ [479] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID ...
7652    fn evaluate_2010(&self, _ctx: &EvaluationContext) -> ConditionResult {
7653        // TODO: implement
7654        ConditionResult::Unknown
7655    }
7656
7657    /// [2011] Segmentgruppe ist genau einmal für jede Zeitraum-ID aus dem DE1156 der SG6 RFF+Z49 / Z53 (Verwendungszeitraum der Daten: "Gültige Daten" / "Keine Daten") aus der Anfragennachricht aus SG6 RFF+TN ...
7658    /// EXTERNAL: Requires context from outside the message.
7659    // REVIEW: Condition requires checking Zeitraum-IDs from DE1156 of SG6 RFF+Z49/Z53 ('Verwendungszeitraum der Daten: Gültige Daten / Keine Daten') that originated in the REQUEST message referenced by SG6 RFF+TN DE1154. The referenced request message is a separate EDIFACT interchange not present in the current message being validated. The cardinality constraint ('exactly once per Zeitraum-ID from the request') is therefore an external business context check that depends on data from a prior message in the business process. (medium confidence)
7660    fn evaluate_2011(&self, ctx: &EvaluationContext) -> ConditionResult {
7661        ctx.external
7662            .evaluate("request_message_zeitraum_ids_present")
7663    }
7664
7665    /// [2012] Segmentgruppe ist genau einmal für die Angabe der Informativen Daten der Marktlokation anzugeben
7666    fn evaluate_2012(&self, _ctx: &EvaluationContext) -> ConditionResult {
7667        // TODO: implement
7668        ConditionResult::Unknown
7669    }
7670
7671    /// [2013] Mindesten einmal anzugeben wenn kein SG6 RFF+Z54 (Verwendungszeitraum der Daten: Im System keine Daten vorhanden) vorhanden
7672    fn evaluate_2013(&self, ctx: &EvaluationContext) -> ConditionResult {
7673        // Check: condition applies when no RFF+Z54 exists
7674        ctx.lacks_qualifier("RFF", 0, "Z54")
7675    }
7676
7677    /// [2014] Mindesten einmal anzugeben wenn kein SG6 RFF+Z47 (Verwendungszeitraum der Daten: Im System vorhandene Daten) vorhanden
7678    fn evaluate_2014(&self, ctx: &EvaluationContext) -> ConditionResult {
7679        // Check: condition applies when no RFF+Z47 exists
7680        ctx.lacks_qualifier("RFF", 0, "Z47")
7681    }
7682
7683    /// [2015] Einmal für jede ruhende Marktlokation, die der Marktlokation \"Kundenanlage\" aus dem SG5 LOC+Z16 (Marktlokation) untergeordnet ist
7684    fn evaluate_2015(&self, _ctx: &EvaluationContext) -> ConditionResult {
7685        // TODO: implement
7686        ConditionResult::Unknown
7687    }
7688
7689    /// [2016] Je SG5 LOC+Z16 (Marktlokation) ist genau einmal die Segmentgruppe anzugeben
7690    fn evaluate_2016(&self, ctx: &EvaluationContext) -> ConditionResult {
7691        // Cardinality: exactly once per SG5 LOC+Z16 (Marktlokation)
7692        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
7693        ConditionResult::from(loc_count > 0)
7694    }
7695
7696    /// [2017] Je SG5 LOC+Z17 (Messlokation) ist genau einmal die Segmentgruppe anzugeben
7697    fn evaluate_2017(&self, ctx: &EvaluationContext) -> ConditionResult {
7698        // Cardinality: exactly once per SG5 LOC+Z17 (Messlokation)
7699        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
7700        ConditionResult::from(loc_count > 0)
7701    }
7702
7703    /// [2018] Segmentgruppe ist genau einmal für jede SG8 SEQ+Z01 (Daten der Marktlokation) anzugeben, bei der die Bedingungen [266] an der Segmentgruppe erfüllt ist. Dabei ist die selbe Zeitraum-ID im nachfol...
7704    fn evaluate_2018(&self, _ctx: &EvaluationContext) -> ConditionResult {
7705        // TODO: implement
7706        ConditionResult::Unknown
7707    }
7708
7709    /// [2060] Wenn SG10 CAV+NZR ist die Segmentgruppe genau zwei Mal je IDE+24 anzugeben
7710    fn evaluate_2060(&self, ctx: &EvaluationContext) -> ConditionResult {
7711        // Check: CAV+NZR exists (then segment group exactly twice per IDE+24)
7712        let found = ctx.find_segments("CAV").iter().any(|s| {
7713            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "NZR")
7714        });
7715        ConditionResult::from(found)
7716    }
7717
7718    /// [2061] Segment bzw. Segmentgruppe ist genau einmal je SG4 IDE (Vorgang) anzugeben
7719    fn evaluate_2061(&self, ctx: &EvaluationContext) -> ConditionResult {
7720        // Cardinality: exactly once per SG4 IDE (always true for single-transaction messages)
7721        let ide_count = ctx.find_segments("IDE").len();
7722        ConditionResult::from(ide_count > 0)
7723    }
7724
7725    /// [2071] Für die ID der LieferantensummenZR einmal je SG4 IDE+24 (Vorgang)
7726    fn evaluate_2071(&self, ctx: &EvaluationContext) -> ConditionResult {
7727        // Cardinality: LieferantensummenZR once per SG4 IDE+24
7728        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7729        ConditionResult::from(ide_count > 0)
7730    }
7731
7732    /// [2073] Für die ID der BilanzkreissummenZR einmal je SG4 IDE+24 (Vorgang)
7733    fn evaluate_2073(&self, ctx: &EvaluationContext) -> ConditionResult {
7734        // Cardinality: BilanzkreissummenZR once per SG4 IDE+24
7735        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7736        ConditionResult::from(ide_count > 0)
7737    }
7738
7739    /// [2075] Für die ID der Zeitreihen (nicht bei EEG-EUZ und EUZ der AAÜZ) in der Clearingliste einmal je SG4 IDE+24 (Vorgang)
7740    fn evaluate_2075(&self, ctx: &EvaluationContext) -> ConditionResult {
7741        // Cardinality: Zeitreihen (not EEG-EUZ/AAÜZ) once per SG4 IDE+24
7742        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7743        ConditionResult::from(ide_count > 0)
7744    }
7745
7746    /// [2080] Segmentgruppe ist max. zweimal je SG4 IDE+24 (Vorgang) anzugeben
7747    fn evaluate_2080(&self, ctx: &EvaluationContext) -> ConditionResult {
7748        // Cardinality: max twice per SG4 IDE+24
7749        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7750        ConditionResult::from(ide_count > 0)
7751    }
7752
7753    /// [2095] Je SG5 LOC+Z15 (MaBiS-Zählpunkt) ist genau einmal die Segmentgruppe anzugeben
7754    fn evaluate_2095(&self, ctx: &EvaluationContext) -> ConditionResult {
7755        // Cardinality: exactly once per SG5 LOC+Z15 (MaBiS-Zählpunkt)
7756        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z15").len();
7757        ConditionResult::from(loc_count > 0)
7758    }
7759
7760    /// [2096] Segmentgruppe ist genau zweimal je SG4 IDE anzugeben
7761    fn evaluate_2096(&self, ctx: &EvaluationContext) -> ConditionResult {
7762        // Cardinality: exactly twice per SG4 IDE
7763        let ide_count = ctx.find_segments("IDE").len();
7764        ConditionResult::from(ide_count > 0)
7765    }
7766
7767    /// [2119] Je SG8 SEQ+Z13/ ZG0 (Smartmeter-Gateway) ist genau einmal die Segmentgruppe anzugeben
7768    fn evaluate_2119(&self, ctx: &EvaluationContext) -> ConditionResult {
7769        // Cardinality: exactly once per SG8 SEQ+Z13/ZG0 (Smartmeter-Gateway)
7770        let found = ctx.find_segments("SEQ").iter().any(|s| {
7771            s.elements.first().and_then(|e| e.first())
7772                .is_some_and(|v| v == "Z13" || v == "ZG0")
7773        });
7774        ConditionResult::from(found)
7775    }
7776
7777    /// [2140] Für die ID der LieferantensummenZR einmal je SG4 IDE+Z01 (Liste)
7778    fn evaluate_2140(&self, ctx: &EvaluationContext) -> ConditionResult {
7779        // Cardinality: LieferantensummenZR once per SG4 IDE+Z01
7780        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "Z01").len();
7781        ConditionResult::from(ide_count > 0)
7782    }
7783
7784    /// [2182] Segmentgruppe ist genau einmal je SG8 SEQ+Z01/ Z80/ Z81/ Z98 (Daten der Marktlokation/ Erwartete Daten der Marktlokation/ Im System vorhandene Daten der Marktlokation) anzugeben
7785    fn evaluate_2182(&self, ctx: &EvaluationContext) -> ConditionResult {
7786        // Cardinality: exactly once per SG8 SEQ+Z01/Z80/Z81/Z98
7787        let found = ctx.find_segments("SEQ").iter().any(|s| {
7788            s.elements.first().and_then(|e| e.first())
7789                .is_some_and(|v| ["Z01", "Z80", "Z81", "Z98"].contains(&v.as_str()))
7790        });
7791        ConditionResult::from(found)
7792    }
7793
7794    /// [2183] Segmentgruppe ist genau zweimal je SG8 SEQ+Z01/ Z80/ Z81/ Z98 (Daten der Marktlokation/ Erwartete Daten der Marktlokation/ Im System vorhandene Daten der Marktlokation) anzugeben
7795    fn evaluate_2183(&self, ctx: &EvaluationContext) -> ConditionResult {
7796        // Cardinality: exactly twice per SG8 SEQ+Z01/Z80/Z81/Z98
7797        let found = ctx.find_segments("SEQ").iter().any(|s| {
7798            s.elements.first().and_then(|e| e.first())
7799                .is_some_and(|v| ["Z01", "Z80", "Z81", "Z98"].contains(&v.as_str()))
7800        });
7801        ConditionResult::from(found)
7802    }
7803
7804    /// [2207] Für die ID der Lieferanten-ausfall-arbeits-summen-zeitreihe einmal je SG4 IDE+Z01 (Liste)
7805    fn evaluate_2207(&self, ctx: &EvaluationContext) -> ConditionResult {
7806        // Cardinality: Lieferantenausfallarbeitssummenzeitreihe once per SG4 IDE+Z01
7807        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "Z01").len();
7808        ConditionResult::from(ide_count > 0)
7809    }
7810
7811    /// [2225] Einmal für jede Marktlokation bzw. Tranche für die der LF nicht die gemeldete Ansicht des NB teilt
7812    fn evaluate_2225(&self, _ctx: &EvaluationContext) -> ConditionResult {
7813        // TODO: implement
7814        ConditionResult::Unknown
7815    }
7816
7817    /// [2236] Code einmal je SG4 IDE+24 (Vorgang)
7818    fn evaluate_2236(&self, ctx: &EvaluationContext) -> ConditionResult {
7819        // Cardinality: code once per SG4 IDE+24
7820        let ide_count = ctx.find_segments_with_qualifier("IDE", 0, "24").len();
7821        ConditionResult::from(ide_count > 0)
7822    }
7823
7824    /// [2252] Einmal für jede Marktlokation bzw. Tranche, die in der Lieferantenausfallarbeits-summenzeitreihe berücksichtigt wurde
7825    fn evaluate_2252(&self, _ctx: &EvaluationContext) -> ConditionResult {
7826        // TODO: implement
7827        ConditionResult::Unknown
7828    }
7829
7830    /// [2261] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225, mindestens einmal anzugeben
7831    fn evaluate_2261(&self, ctx: &EvaluationContext) -> ConditionResult {
7832        // Cardinality: at least once per LOC+Z21 (Tranche) ID
7833        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
7834        ConditionResult::from(loc_count > 0)
7835    }
7836
7837    /// [2284] Für jede Messlokations-ID im SG5 LOC+Z17 (Messlokation) DE3225 genau einmal anzugeben
7838    fn evaluate_2284(&self, ctx: &EvaluationContext) -> ConditionResult {
7839        // Cardinality: exactly once per LOC+Z17 (Messlokation) ID
7840        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
7841        ConditionResult::from(loc_count > 0)
7842    }
7843
7844    /// [2286] Für jede SEQ+ZF3 (Daten der Messlokation) mindestens einmal anzugeben
7845    fn evaluate_2286(&self, ctx: &EvaluationContext) -> ConditionResult {
7846        // Cardinality: at least once per SEQ+ZF3 (Daten der Messlokation)
7847        let found = !ctx.find_segments_with_qualifier("SEQ", 0, "ZF3").is_empty();
7848        ConditionResult::from(found)
7849    }
7850
7851    /// [2287] Für jede SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) mindestens einmal anzugeben
7852    fn evaluate_2287(&self, ctx: &EvaluationContext) -> ConditionResult {
7853        // Cardinality: at least once per SEQ+Z03/ZF5 (Zähleinrichtungsdaten)
7854        let found = ctx.find_segments("SEQ").iter().any(|s| {
7855            s.elements.first().and_then(|e| e.first())
7856                .is_some_and(|v| v == "Z03" || v == "ZF5")
7857        });
7858        ConditionResult::from(found)
7859    }
7860
7861    /// [2288] Einmal für jede Zeitreihe, die in der DZR berücksichtigt wurde
7862    fn evaluate_2288(&self, _ctx: &EvaluationContext) -> ConditionResult {
7863        // TODO: implement
7864        ConditionResult::Unknown
7865    }
7866
7867    /// [2307] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225 genau einmal anzugeben
7868    fn evaluate_2307(&self, ctx: &EvaluationContext) -> ConditionResult {
7869        // Cardinality: exactly once per LOC+Z21 (Tranche) ID
7870        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
7871        ConditionResult::from(loc_count > 0)
7872    }
7873
7874    /// [2308] Für jede ID im SG5 LOC+Z16 (Marktlokation) DE3225, mindestens einmal anzugeben
7875    fn evaluate_2308(&self, ctx: &EvaluationContext) -> ConditionResult {
7876        // Cardinality: at least once per LOC+Z16 (Marktlokation) ID
7877        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
7878        ConditionResult::from(loc_count > 0)
7879    }
7880
7881    /// [2309] Für jede ID im SG5 LOC+Z17 (Messlokation) DE3225 mindestens einmal anzugeben
7882    fn evaluate_2309(&self, ctx: &EvaluationContext) -> ConditionResult {
7883        // Cardinality: at least once per LOC+Z17 (Messlokation) ID
7884        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z17").len();
7885        ConditionResult::from(loc_count > 0)
7886    }
7887
7888    /// [2310] Für jede ID im SG5 LOC+Z16 (Marktlokation) DE3225 genau einmal anzugeben
7889    fn evaluate_2310(&self, ctx: &EvaluationContext) -> ConditionResult {
7890        // Cardinality: exactly once per LOC+Z16 (Marktlokation) ID
7891        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z16").len();
7892        ConditionResult::from(loc_count > 0)
7893    }
7894
7895    /// [2311] Für jede ID im SG5 LOC+Z21 (Tranche) DE3225, mindestens einmal anzugeben
7896    fn evaluate_2311(&self, ctx: &EvaluationContext) -> ConditionResult {
7897        // Cardinality: at least once per LOC+Z21 (Tranche) ID
7898        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z21").len();
7899        ConditionResult::from(loc_count > 0)
7900    }
7901
7902    /// [2312] Wenn der Objektcode \"9992000001256\" (Netzlokation) im DE1154 des selben RFF+Z33 nicht vorhanden ist, ist das RFF+Z33 in derselben SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des...
7903    fn evaluate_2312(&self, ctx: &EvaluationContext) -> ConditionResult {
7904        // Check: RFF+Z33 DE1154 does NOT contain Objektcode 9992000001256 (Netzlokation)
7905        let rff_z33 = ctx.find_segments_with_qualifier("RFF", 0, "Z33");
7906        let has_netzlokation = rff_z33.iter().any(|s| {
7907            s.elements.first().and_then(|e| e.get(1)).is_some_and(|v| v == "9992000001256")
7908        });
7909        ConditionResult::from(!has_netzlokation)
7910    }
7911
7912    /// [2313] Je SG8 SEQ+Z58/ ZC9/ ZD0/ ZD6 (Zuordnung Lokation zum Objektcode des Lokationsbündels) genau einmal anzugeben
7913    fn evaluate_2313(&self, ctx: &EvaluationContext) -> ConditionResult {
7914        // Check: SG8 with SEQ+Z58/ZC9/ZD0/ZD6 exists (cardinality constraint)
7915        let found = ctx.find_segments("SEQ").iter().any(|s| {
7916            s.elements.first().and_then(|e| e.first())
7917                .is_some_and(|v| ["Z58", "ZC9", "ZD0", "ZD6"].contains(&v.as_str()))
7918        });
7919        ConditionResult::from(found)
7920    }
7921
7922    /// [2317] Wenn in derselben SG8 SEQ+Z04/ ZF7 (Wandlerdaten) das SG10 CCI+++Z25 (Wandler) CAV+MIW/MPW/MUW vorhanden, ist das Segment mindestens zweimal anzugeben
7923    fn evaluate_2317(&self, ctx: &EvaluationContext) -> ConditionResult {
7924        // Check: SG10 CCI+++Z25 has CAV+MIW/MPW/MUW (Wandler types)
7925        let has_cav = ctx.find_segments("CAV").iter().any(|s| {
7926            s.elements.first().and_then(|e| e.first())
7927                .is_some_and(|v| ["MIW", "MPW", "MUW"].contains(&v.as_str()))
7928        });
7929        ConditionResult::from(has_cav)
7930    }
7931
7932    /// [2318] Wenn in derselben SG8 SEQ+Z04/ ZF7 (Wandlerdaten) das SG10 CCI+++Z25 (Wandler) CAV+MBW (Blockstromwandler) vorhanden, ist das Segment genau einmal anzugeben
7933    fn evaluate_2318(&self, ctx: &EvaluationContext) -> ConditionResult {
7934        // Check: SG10 CCI+++Z25 has CAV+MBW (Blockstromwandler)
7935        let has_cav = ctx.find_segments("CAV").iter().any(|s| {
7936            s.elements.first().and_then(|e| e.first()).is_some_and(|v| v == "MBW")
7937        });
7938        ConditionResult::from(has_cav)
7939    }
7940
7941    /// [2344] Einmal für jede Marktlokation bzw. Tranche, die in der DZÜ / BG-CL / LF-SZR berücksichtigt wurde
7942    fn evaluate_2344(&self, _ctx: &EvaluationContext) -> ConditionResult {
7943        // TODO: implement
7944        ConditionResult::Unknown
7945    }
7946
7947    /// [2350] Für jedes SMGW das im SEQ+Z13/ ZG0 (Smartmeter-Gateway) SG10 CCI+++Z75 CAV+Z30 (Gerätenummer) genannt ist, mindestens einmal je SEQ+Z03/ ZF5 (Zähleinrichtungsdaten) das mit SG8 RFF+Z14 (Referenz...
7948    fn evaluate_2350(&self, _ctx: &EvaluationContext) -> ConditionResult {
7949        // TODO: implement
7950        ConditionResult::Unknown
7951    }
7952
7953    /// [2351] Einmal je ZP einer BK-SZR, in der die Marktlokation in die Berechnung der abgerechneten Summenzeitreihe aufgenommen wurde
7954    fn evaluate_2351(&self, _ctx: &EvaluationContext) -> ConditionResult {
7955        // TODO: implement
7956        ConditionResult::Unknown
7957    }
7958
7959    /// [2352] Einmal je ZP einer BG-SZR, in der die Marktlokation in die Berechnung der abgerechneten Summenzeitreihe aufge-nommen wurde
7960    fn evaluate_2352(&self, _ctx: &EvaluationContext) -> ConditionResult {
7961        // TODO: implement
7962        ConditionResult::Unknown
7963    }
7964
7965    /// [2356] Je SG5 LOC+Z18 (Netzlokation) ist genau einmal die Segmentgruppe anzugeben
7966    fn evaluate_2356(&self, ctx: &EvaluationContext) -> ConditionResult {
7967        // Cardinality: exactly once per SG5 LOC+Z18 (Netzlokation)
7968        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z18").len();
7969        ConditionResult::from(loc_count > 0)
7970    }
7971
7972    /// [2357] Je SG5 LOC+Z20 (Technische Ressource) ist genau einmal die Segmentgruppe anzugeben
7973    fn evaluate_2357(&self, ctx: &EvaluationContext) -> ConditionResult {
7974        // Cardinality: exactly once per SG5 LOC+Z20 (Technische Ressource)
7975        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z20").len();
7976        ConditionResult::from(loc_count > 0)
7977    }
7978
7979    /// [2358] Je SG5 LOC+Z19 (Steuerbare Ressource) ist genau einmal die Segmentgruppe anzugeben
7980    fn evaluate_2358(&self, ctx: &EvaluationContext) -> ConditionResult {
7981        // Cardinality: exactly once per SG5 LOC+Z19 (Steuerbare Ressource)
7982        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z19").len();
7983        ConditionResult::from(loc_count > 0)
7984    }
7985
7986    /// [2359] Für jede ID im SG5 LOC+Z16 / Z17 / Z20 (Marktlokation / Messlokation / Technische Ressource) DE3225 mindestens einmal anzugeben
7987    fn evaluate_2359(&self, ctx: &EvaluationContext) -> ConditionResult {
7988        // Cardinality: at least once per LOC+Z16/Z17/Z20 ID
7989        let found = ctx.find_segments("LOC").iter().any(|s| {
7990            s.elements.first().and_then(|e| e.first())
7991                .is_some_and(|v| ["Z16", "Z17", "Z20"].contains(&v.as_str()))
7992        });
7993        ConditionResult::from(found)
7994    }
7995
7996    /// [2360] Für jede ID im SG5 LOC+Z18 (Netzlokation) DE3225 mindestens einmal anzugeben
7997    fn evaluate_2360(&self, ctx: &EvaluationContext) -> ConditionResult {
7998        // Cardinality: at least once per LOC+Z18 (Netzlokation) ID
7999        let loc_count = ctx.find_segments_with_qualifier("LOC", 0, "Z18").len();
8000        ConditionResult::from(loc_count > 0)
8001    }
8002
8003    /// [2361] Für jede ID im SG5 LOC+Z17 / Z20 / Z22 (Messlokation / Technische Ressource / ruhende Marktlokation) DE3225 mindestens einmal anzugeben
8004    fn evaluate_2361(&self, ctx: &EvaluationContext) -> ConditionResult {
8005        // Cardinality: at least once per LOC+Z17/Z20/Z22 ID
8006        let found = ctx.find_segments("LOC").iter().any(|s| {
8007            s.elements.first().and_then(|e| e.first())
8008                .is_some_and(|v| ["Z17", "Z20", "Z22"].contains(&v.as_str()))
8009        });
8010        ConditionResult::from(found)
8011    }
8012}