1use std::{hash::Hash, str::FromStr};
2
3use chrono::Utc;
4use indexmap::IndexMap;
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 Country, Currency, Language, Links, PriceList, fuse::MainFuseSizes,
9 price_list::PriceListSimplified, registry::sweden,
10};
11
12#[derive(Debug, Clone)]
13#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
14pub struct GridOperator {
15 name: &'static str,
16 vat_number: &'static str,
17 country: Country,
19 main_fuses: MainFuseSizes,
21 price_lists: &'static [PriceList],
22 links: Links,
23}
24
25impl GridOperator {
26 pub const fn name(&self) -> &str {
27 self.name
28 }
29
30 pub const fn vat_number(&self) -> &str {
31 self.vat_number
32 }
33
34 pub const fn country(&self) -> Country {
35 self.country
36 }
37
38 pub const fn links(&self) -> &Links {
39 &self.links
40 }
41
42 pub fn active_price_lists(&self) -> Vec<&'static PriceList> {
43 let now = Utc::now().date_naive();
44 let mut map: IndexMap<Option<&str>, &PriceList> = IndexMap::new();
45 for pl in self.price_lists {
46 if now >= pl.from_date() {
47 if let Some(current_max_date) = map.get(&pl.variant()).map(|pl| pl.from_date()) {
48 if pl.from_date() > current_max_date {
49 map.insert(pl.variant(), pl);
50 }
51 } else {
52 map.insert(pl.variant(), pl);
53 }
54 }
55 }
56 map.into_values().collect()
57 }
58
59 pub fn active_price_list(&self, variant: Option<&str>) -> Option<&'static PriceList> {
60 self.active_price_lists()
61 .iter()
62 .filter(|pl| pl.variant() == variant)
63 .next_back()
64 .copied()
65 }
66
67 pub fn price_lists(&self) -> &'static [PriceList] {
68 self.price_lists
69 }
70
71 pub const fn currency(&self) -> Currency {
72 match self.country {
73 Country::SE => Currency::SEK,
74 }
75 }
76
77 pub fn get(country: Country, name: &str) -> Option<&'static Self> {
78 match country {
79 Country::SE => sweden::GRID_OPERATORS
80 .iter()
81 .find(|o| o.name == name)
82 .copied(),
83 }
84 }
85
86 pub fn get_by_vat_id(vat_id: &str) -> Option<&'static Self> {
87 let country: Country = vat_id[0..2].parse().ok()?;
88 match country {
89 Country::SE => sweden::GRID_OPERATORS
90 .iter()
91 .find(|o| o.vat_number == vat_id)
92 .copied(),
93 }
94 }
95
96 pub fn all() -> Vec<&'static Self> {
97 sweden::GRID_OPERATORS.to_vec()
98 }
99
100 pub fn all_for_country(country: Country) -> &'static [&'static Self] {
101 match country {
102 Country::SE => sweden::GRID_OPERATORS,
103 }
104 }
105
106 pub const fn builder() -> GridOperatorBuilder {
107 GridOperatorBuilder::new()
108 }
109
110 pub fn simplified(
111 &self,
112 fuse_size: u16,
113 yearly_consumption: u32,
114 language: Language,
115 ) -> GridOperatorSimplified {
116 GridOperatorSimplified::new(self, fuse_size, yearly_consumption, language)
117 }
118}
119
120#[derive(Debug, Clone, Serialize)]
122#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
123pub struct GridOperatorSimplified {
124 name: &'static str,
125 vat_number: &'static str,
126 country: Country,
128 price_lists: Vec<PriceListSimplified>,
129}
130
131impl GridOperatorSimplified {
132 pub fn name(&self) -> &'static str {
133 self.name
134 }
135
136 pub fn vat_number(&self) -> &'static str {
137 self.vat_number
138 }
139
140 pub fn country(&self) -> Country {
141 self.country
142 }
143
144 pub fn price_lists(&self) -> &[PriceListSimplified] {
145 &self.price_lists
146 }
147}
148
149impl GridOperatorSimplified {
150 fn new(op: &GridOperator, fuse_size: u16, yearly_consumption: u32, language: Language) -> Self {
151 Self {
152 name: op.name,
153 vat_number: op.vat_number,
154 country: op.country(),
155 price_lists: op
156 .active_price_lists()
157 .into_iter()
158 .map(|pl| pl.simplified(fuse_size, yearly_consumption, language))
159 .collect(),
160 }
161 }
162}
163
164#[derive(Debug, Clone)]
165pub struct GridOperatorBuilder {
166 name: Option<&'static str>,
167 vat_number: Option<&'static str>,
168 country: Option<Country>,
170 main_fuses: Option<MainFuseSizes>,
172 price_lists: Option<&'static [PriceList]>,
173 links: Option<Links>,
174}
175
176impl Default for GridOperatorBuilder {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182impl GridOperatorBuilder {
183 pub const fn new() -> Self {
184 Self {
185 name: None,
186 vat_number: None,
187 country: None,
188 main_fuses: None,
189 price_lists: None,
190 links: None,
191 }
192 }
193
194 pub const fn name(mut self, name: &'static str) -> Self {
195 self.name = Some(name);
196 self
197 }
198
199 pub const fn vat_number(mut self, vat_number: &'static str) -> Self {
200 self.vat_number = Some(vat_number);
201 self
202 }
203
204 pub const fn country(mut self, country: Country) -> Self {
205 self.country = Some(country);
206 self
207 }
208
209 pub const fn main_fuses(mut self, main_fuses: MainFuseSizes) -> Self {
210 self.main_fuses = Some(main_fuses);
211 self
212 }
213
214 pub const fn links(mut self, links: Links) -> Self {
215 self.links = Some(links);
216 self
217 }
218
219 pub const fn price_lists(mut self, price_lists: &'static [PriceList]) -> Self {
220 self.price_lists = Some(price_lists);
221 self
222 }
223
224 pub const fn build(self) -> GridOperator {
225 GridOperator {
226 name: self.name.expect("`name` required"),
227 vat_number: self.vat_number.expect("`vat_number` required"),
228 country: self.country.expect("`country` required"),
229 main_fuses: self.main_fuses.expect("`main_fuses` required"),
230 price_lists: self.price_lists.expect("`price_lists` expected"),
231 links: self.links.expect("`links` required"),
232 }
233 }
234}
235
236impl FromStr for &'static GridOperator {
237 type Err = &'static str;
238
239 fn from_str(s: &str) -> Result<Self, Self::Err> {
240 GridOperator::get_by_vat_id(s).ok_or("grid operator not found")
241 }
242}
243
244impl<'de> Deserialize<'de> for &'static GridOperator {
245 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
246 where
247 D: serde::Deserializer<'de>,
248 {
249 let s = String::deserialize(deserializer)?;
250 Self::from_str(&s).map_err(serde::de::Error::custom)
251 }
252}
253
254impl Serialize for GridOperator {
255 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
256 where
257 S: serde::Serializer,
258 {
259 serializer.serialize_str(self.vat_number())
260 }
261}
262
263impl PartialEq for GridOperator {
264 fn eq(&self, other: &Self) -> bool {
265 self.vat_number == other.vat_number
266 }
267}
268
269impl Eq for GridOperator {}
270
271impl PartialOrd for GridOperator {
272 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
273 Some(self.cmp(other))
274 }
275}
276
277impl Ord for GridOperator {
278 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
279 self.vat_number.cmp(other.vat_number)
280 }
281}
282
283impl Hash for GridOperator {
284 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
285 self.vat_number.hash(state);
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_grid_operator_serialize_deserialize() {
295 let operator: &GridOperator = "SE556037732601".parse().unwrap();
296
297 let serialized = serde_json::to_string(operator).expect("serialization should succeed");
299
300 assert_eq!(serialized, format!("\"{}\"", operator.vat_number()));
302
303 let deserialized: &'static GridOperator =
305 serde_json::from_str(&serialized).expect("deserialization should succeed");
306
307 assert_eq!(deserialized.name(), operator.name());
309 assert_eq!(deserialized.vat_number(), operator.vat_number());
310 assert_eq!(deserialized.country(), operator.country());
311 }
312
313 #[test]
314 fn test_grid_operator_deserialize_invalid() {
315 let result: Result<&'static GridOperator, _> = serde_json::from_str("\"SE000000000000\"");
317
318 assert!(
319 result.is_err(),
320 "deserialization should fail for invalid VAT number"
321 );
322 }
323
324 #[test]
325 fn test_grid_operator_partial_eq() {
326 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
327 let operator2: &GridOperator = "SE556037732601".parse().unwrap();
328 let operator3: &GridOperator = "SE556532083401".parse().unwrap();
329
330 assert_eq!(operator1, operator2);
332
333 assert_ne!(operator1, operator3);
335 }
336
337 #[test]
338 fn test_grid_operator_partial_ord() {
339 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
340 let operator2: &GridOperator = "SE556532083401".parse().unwrap();
341
342 assert!(operator1 < operator2);
344 assert!(operator2 > operator1);
345 assert!(operator1 <= operator1);
346 assert!(operator1 >= operator1);
347 }
348
349 #[test]
350 fn test_grid_operator_ord() {
351 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
352 let operator2: &GridOperator = "SE556532083401".parse().unwrap();
353 let operator3: &GridOperator = "SE556037732601".parse().unwrap();
354
355 assert_eq!(operator1.cmp(operator2), std::cmp::Ordering::Less);
357 assert_eq!(operator2.cmp(operator1), std::cmp::Ordering::Greater);
358 assert_eq!(operator1.cmp(operator3), std::cmp::Ordering::Equal);
359 }
360
361 #[test]
362 fn test_grid_operator_hash() {
363 use std::collections::hash_map::DefaultHasher;
364 use std::hash::{Hash, Hasher};
365
366 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
367 let operator2: &GridOperator = "SE556037732601".parse().unwrap();
368 let operator3: &GridOperator = "SE556532083401".parse().unwrap();
369
370 let compute_hash = |op: &GridOperator| {
372 let mut hasher = DefaultHasher::new();
373 op.hash(&mut hasher);
374 hasher.finish()
375 };
376
377 assert_eq!(compute_hash(operator1), compute_hash(operator2));
379
380 assert_ne!(compute_hash(operator1), compute_hash(operator3));
382 }
383}