Skip to main content

automapper_validation/generated/fv2604/
utilmd_strom_conditions_fv2604.rs

1// <auto-generated>
2// Generated by automapper-generator generate-conditions
3// AHB: xml-migs-and-ahbs/FV2604/UTILMD_AHB_Strom_2_1_Fehlerkorrektur_20260629.xml
4// Generated: 2026-09-23T18:15:06Z
5// Delegates unchanged conditions to UtilmdStromConditionEvaluatorFV2510 (FV2510).
6// </auto-generated>
7
8#![allow(clippy::style, clippy::complexity)]
9
10#[allow(unused_imports)]
11use crate::eval::format_validators::*;
12use crate::eval::{ConditionEvaluator, ConditionResult, EvaluationContext};
13use crate::generated::fv2510::UtilmdStromConditionEvaluatorFV2510;
14use mig_types::segment::OwnedSegment;
15
16/// Condition evaluator for UTILMD_Strom FV2604.
17///
18/// Delegates to [`UtilmdStromConditionEvaluatorFV2510`] for conditions whose AHB description is
19/// unchanged from that version. Local overrides: [160], [182], [183], [203], [271].
20pub struct UtilmdStromConditionEvaluatorFV2604 {
21    fallback: UtilmdStromConditionEvaluatorFV2510,
22}
23
24impl Default for UtilmdStromConditionEvaluatorFV2604 {
25    fn default() -> Self {
26        Self {
27            fallback: UtilmdStromConditionEvaluatorFV2510::default(),
28        }
29    }
30}
31
32/// Condition IDs whose implementation differs from the fallback.
33const FV2604_OVERRIDES: &[u32] = &[160, 182, 183, 203, 271];
34
35impl ConditionEvaluator for UtilmdStromConditionEvaluatorFV2604 {
36    fn message_type(&self) -> &str {
37        "UTILMD_Strom"
38    }
39
40    fn format_version(&self) -> &str {
41        "FV2604"
42    }
43
44    fn evaluate(&self, condition: u32, ctx: &EvaluationContext) -> ConditionResult {
45        match condition {
46            160 => self.evaluate_160(ctx),
47            182 => self.evaluate_182(ctx),
48            183 => self.evaluate_183(ctx),
49            203 => self.evaluate_203(ctx),
50            271 => self.evaluate_271(ctx),
51            other => self.fallback.evaluate(other, ctx),
52        }
53    }
54
55    fn is_external(&self, condition: u32) -> bool {
56        !FV2604_OVERRIDES.contains(&condition) && self.fallback.is_external(condition)
57    }
58
59    fn is_known(&self, condition: u32) -> bool {
60        FV2604_OVERRIDES.contains(&condition) || self.fallback.is_known(condition)
61    }
62}
63
64/// Whether some SG8 has an SG10 whose CCI and CAV segments satisfy `pred`.
65fn sg10_has(
66    ctx: &EvaluationContext,
67    pred: impl Fn(&[OwnedSegment], &[OwnedSegment]) -> bool,
68) -> ConditionResult {
69    // HAND-EDITED: "in dieser SG8" — only the SG10s of the enclosing SG8 when the
70    // scope reaches one; every SG8's otherwise.
71    if let (Some(sg8), Some(nav)) = (ctx.enclosing_scope("SG8"), ctx.navigator()) {
72        let found = (0..nav.child_instance_count(sg8, "SG10")).any(|j| {
73            let mut sg10 = sg8.to_vec();
74            sg10.push(("SG10", j));
75            pred(
76                &nav.find_segments_in_instance("CCI", &sg10),
77                &nav.find_segments_in_instance("CAV", &sg10),
78            )
79        });
80        return ConditionResult::from(found);
81    }
82    let Some(nav) = ctx.navigator() else {
83        let ccis: Vec<OwnedSegment> = ctx.find_segments("CCI").into_iter().cloned().collect();
84        let cavs: Vec<OwnedSegment> = ctx.find_segments("CAV").into_iter().cloned().collect();
85        return ConditionResult::from(pred(&ccis, &cavs));
86    };
87    for i in 0..nav.group_instance_count(&["SG4", "SG8"]) {
88        for j in 0..nav.child_group_instance_count(&["SG4", "SG8"], i, "SG10") {
89            let ccis = nav.find_segments_in_child_group("CCI", &["SG4", "SG8"], i, "SG10", j);
90            let cavs = nav.find_segments_in_child_group("CAV", &["SG4", "SG8"], i, "SG10", j);
91            if pred(&ccis, &cavs) {
92                return ConditionResult::True;
93            }
94        }
95    }
96    ConditionResult::False
97}
98
99impl UtilmdStromConditionEvaluatorFV2604 {
100    /// [160] Wenn der Objektcode im RFF+Z33 (Referenz auf den Objektcode in der LokationsbĂĽndelstruktur) im DE1154 derselben SG8 SEQ+...
101    // Message-wide approximation: some two SG8 SEQ+Z58/ZC9/ZD0/ZD6 share Zeitraum-ID
102    // (SEQ C286 1050), DE1229 code and the RFF+Z33 Objektcode.
103    fn evaluate_160(&self, ctx: &EvaluationContext) -> ConditionResult {
104        let nav = match ctx.navigator() {
105            Some(n) => n,
106            None => return ConditionResult::Unknown,
107        };
108        let mut seen = std::collections::BTreeSet::new();
109        for i in 0..nav.group_instance_count(&["SG4", "SG8"]) {
110            let seqs = nav.find_segments_in_group("SEQ", &["SG4", "SG8"], i);
111            let Some(seq) = seqs.first() else { continue };
112            let code = seq
113                .elements
114                .first()
115                .and_then(|e| e.first())
116                .cloned()
117                .unwrap_or_default();
118            if !["Z58", "ZC9", "ZD0", "ZD6"].contains(&code.as_str()) {
119                continue;
120            }
121            let zeitraum = seq
122                .elements
123                .get(1)
124                .and_then(|e| e.first())
125                .cloned()
126                .unwrap_or_default();
127            for rff in
128                nav.find_segments_with_qualifier_in_group("RFF", 0, "Z33", &["SG4", "SG8"], i)
129            {
130                let objekt = rff
131                    .elements
132                    .first()
133                    .and_then(|e| e.get(1))
134                    .cloned()
135                    .unwrap_or_default();
136                if !seen.insert((zeitraum.clone(), code.clone(), objekt)) {
137                    return ConditionResult::True;
138                }
139            }
140        }
141        ConditionResult::False
142    }
143
144    /// [182] Wenn SG10 CCI+++ZA6 (Prognosegrundlage der Marktlokation: Prognose auf Basis von Profilen) CAV+E14 (TLP/TEP) in dieser S...
145    fn evaluate_182(&self, ctx: &EvaluationContext) -> ConditionResult {
146        sg10_has(ctx, |ccis, cavs| {
147            ccis.iter().any(|s| {
148                s.elements
149                    .get(2)
150                    .and_then(|e| e.first())
151                    .is_some_and(|v| v == "ZA6")
152            }) && cavs.iter().any(|s| {
153                s.elements
154                    .first()
155                    .and_then(|e| e.first())
156                    .is_some_and(|v| v == "E14")
157            })
158        })
159    }
160
161    /// [183] Wenn SG10 CCI+Z30++Z07 (Lieferrichtung: Verbrauch) in dieser SG8 vorhanden
162    fn evaluate_183(&self, ctx: &EvaluationContext) -> ConditionResult {
163        sg10_has(ctx, |ccis, _| {
164            ccis.iter().any(|s| {
165                s.elements
166                    .first()
167                    .and_then(|e| e.first())
168                    .is_some_and(|v| v == "Z30")
169                    && s.elements
170                        .get(2)
171                        .and_then(|e| e.first())
172                        .is_some_and(|v| v == "Z07")
173            })
174        })
175    }
176
177    /// [203] Wenn STS+7++E06 / Z39 / ZC6 / ZC7/ ZT6/ ZT7 / Z02 / ZZD vorhanden
178    fn evaluate_203(&self, ctx: &EvaluationContext) -> ConditionResult {
179        ctx.has_qualified_value(
180            "STS",
181            0,
182            "7",
183            2,
184            0,
185            &["E06", "Z39", "ZC6", "ZC7", "ZT6", "ZT7", "Z02", "ZZD"],
186        )
187    }
188
189    /// [271] Wenn das RFF+Z50 (Termine der Marktlokation) aus dieser SG6 (Termine der Marktlokation) auf das gleiche SG5 LOC+Z16 (Mar...
190    // As FV2504's [86] (RFF+Z50 of an SG6 references the LOC+Z16 an SG8 RFF+Z18 does),
191    // and some SG10 carries CCI+++Z83 with CAV+Z53 (kME/mME).
192    fn evaluate_271(&self, ctx: &EvaluationContext) -> ConditionResult {
193        let shared = ctx.groups_share_qualified_value(
194            "RFF",
195            0,
196            "Z50",
197            0,
198            2,
199            &["SG4", "SG6"],
200            "RFF",
201            0,
202            2,
203            &["SG4", "SG8"],
204        );
205        let messtechnik = sg10_has(ctx, |ccis, cavs| {
206            ccis.iter().any(|s| {
207                s.elements
208                    .get(2)
209                    .and_then(|e| e.first())
210                    .is_some_and(|v| v == "Z83")
211            }) && cavs.iter().any(|s| {
212                s.elements
213                    .first()
214                    .and_then(|e| e.first())
215                    .is_some_and(|v| v == "Z53")
216            })
217        });
218        shared.and(messtechnik)
219    }
220}