automapper_validation/eval/
sg4_instances.rs1use mig_types::segment::OwnedSegment;
10
11use super::EvaluationContext;
12
13pub type Path<'a> = Vec<(&'a str, usize)>;
15
16pub fn sg8s<'a>(ctx: &EvaluationContext<'a>) -> Vec<Path<'a>> {
19 ctx.scopes_under("SG4", "SG8").unwrap_or_default()
20}
21
22pub fn seq_at(ctx: &EvaluationContext, path: &[(&str, usize)]) -> Option<(String, String)> {
24 ctx.find_segments_at(path, "SEQ").first().map(|s| {
25 (
26 s.get_element(0).to_string(),
27 s.get_component(1, 0).to_string(),
28 )
29 })
30}
31
32pub fn rffs_at(
34 ctx: &EvaluationContext,
35 path: &[(&str, usize)],
36 qualifier: &str,
37) -> Vec<OwnedSegment> {
38 ctx.find_segments_at(path, "RFF")
39 .into_iter()
40 .filter(|s| s.get_element(0) == qualifier)
41 .collect()
42}
43
44pub fn rff_values_at(
46 ctx: &EvaluationContext,
47 path: &[(&str, usize)],
48 qualifier: &str,
49) -> Vec<String> {
50 rffs_at(ctx, path, qualifier)
51 .iter()
52 .map(|s| s.get_component(0, 1).to_string())
53 .filter(|v| !v.is_empty())
54 .collect()
55}
56
57pub fn sg10_at(
60 ctx: &EvaluationContext,
61 path: &[(&str, usize)],
62 pred: impl Fn(&[OwnedSegment]) -> bool,
63) -> bool {
64 ctx.child_segments_at(path, "SG10", &["CCI", "CAV"])
65 .iter()
66 .any(|segs| pred(segs))
67}
68
69pub fn has_cci(segs: &[OwnedSegment], klassentyp: &str, merkmal: &str) -> bool {
72 segs.iter().any(|s| {
73 s.id == "CCI"
74 && (klassentyp.is_empty() || s.get_element(0) == klassentyp)
75 && s.get_component(2, 0) == merkmal
76 })
77}
78
79pub fn has_cav(segs: &[OwnedSegment], code: &str) -> bool {
81 segs.iter()
82 .any(|s| s.id == "CAV" && s.get_element(0) == code)
83}
84
85pub fn malo_ids(ctx: &EvaluationContext) -> Vec<String> {
87 ctx.scopes_under("SG4", "SG5")
88 .unwrap_or_default()
89 .iter()
90 .flat_map(|path| ctx.find_segments_at(path, "LOC"))
91 .filter(|s| s.get_element(0) == "Z16")
92 .map(|s| s.get_component(1, 0).to_string())
93 .filter(|v| !v.is_empty())
94 .collect()
95}
96
97pub fn z01_of_malo_has(
101 ctx: &EvaluationContext,
102 refs: &[String],
103 pred: impl Fn(&[OwnedSegment]) -> bool,
104) -> bool {
105 let malos = malo_ids(ctx);
106 let refs: Vec<&String> = refs.iter().filter(|r| malos.contains(r)).collect();
107 if refs.is_empty() {
108 return false;
109 }
110 sg8s(ctx).iter().any(|path| {
111 seq_at(ctx, path).is_some_and(|(code, _)| code == "Z01")
112 && rff_values_at(ctx, path, "Z18")
113 .iter()
114 .any(|v| refs.contains(&v))
115 && sg10_at(ctx, path, &pred)
116 })
117}
118
119pub fn other_sg8s<'a>(ctx: &EvaluationContext<'a>, own: &[(&str, usize)]) -> Vec<Path<'a>> {
121 sg8s(ctx)
122 .into_iter()
123 .filter(|path| path.as_slice() != own)
124 .collect()
125}
126
127pub fn z02_of_same_malo_has(
132 ctx: &EvaluationContext,
133 own: &[(&str, usize)],
134 obis: impl Fn(&str) -> bool,
135) -> bool {
136 let refs = rff_values_at(ctx, own, "Z18");
137 !refs.is_empty()
138 && other_sg8s(ctx, own).iter().any(|path| {
139 seq_at(ctx, path).is_some_and(|(code, _)| code == "Z02")
140 && rff_values_at(ctx, path, "Z18")
141 .iter()
142 .any(|v| refs.contains(v))
143 && ctx
144 .find_segments_at(path, "PIA")
145 .iter()
146 .any(|s| s.get_element(0) == "5" && obis(s.get_component(1, 0)))
147 })
148}
149
150pub fn objektcode_elsewhere(
156 ctx: &EvaluationContext,
157 own: &[(&str, usize)],
158 kinds: &[&str],
159 same_nummer: bool,
160 same_zeitraum: bool,
161) -> bool {
162 let Some((code, zeitraum)) = seq_at(ctx, own).filter(|(c, _)| kinds.contains(&c.as_str()))
163 else {
164 return false;
165 };
166 let objektcodes = |path: &[(&str, usize)]| -> Vec<(String, String)> {
167 rffs_at(ctx, path, "Z33")
168 .iter()
169 .map(|s| {
170 (
171 s.get_component(0, 1).to_string(),
172 s.get_component(0, 2).to_string(),
173 )
174 })
175 .filter(|(c, _)| !c.is_empty())
176 .collect()
177 };
178 let mine = objektcodes(own);
179 !mine.is_empty()
180 && other_sg8s(ctx, own).iter().any(|path| {
181 seq_at(ctx, path).is_some_and(|(c, z)| c == code && (!same_zeitraum || z == zeitraum))
182 && objektcodes(path).iter().any(|(c, n)| {
183 mine.iter()
184 .any(|(mc, mn)| c == mc && (!same_nummer || n == mn))
185 })
186 })
187}
188
189pub fn z01_of_zeitraum<'a>(ctx: &EvaluationContext<'a>, own: &[(&str, usize)]) -> Vec<Path<'a>> {
192 let Some((_, zeitraum)) = seq_at(ctx, own).filter(|(_, z)| !z.is_empty()) else {
193 return Vec::new();
194 };
195 sg8s(ctx)
196 .into_iter()
197 .filter(|path| seq_at(ctx, path).is_some_and(|(c, z)| c == "Z01" && z == zeitraum))
198 .collect()
199}
200
201pub fn ruhende_malo_with_zeitraum(ctx: &EvaluationContext, zeitraum: &str) -> bool {
204 ctx.scopes_under("SG4", "SG5")
205 .unwrap_or_default()
206 .iter()
207 .flat_map(|path| ctx.find_segments_at(path, "LOC"))
208 .any(|s| s.get_element(0) == "Z22" && s.get_component(1, 3) == zeitraum)
209}