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 GridOperatorBuilder {
177 pub const fn new() -> Self {
178 Self {
179 name: None,
180 vat_number: None,
181 country: None,
182 main_fuses: None,
183 price_lists: None,
184 links: None,
185 }
186 }
187
188 pub const fn name(mut self, name: &'static str) -> Self {
189 self.name = Some(name);
190 self
191 }
192
193 pub const fn vat_number(mut self, vat_number: &'static str) -> Self {
194 self.vat_number = Some(vat_number);
195 self
196 }
197
198 pub const fn country(mut self, country: Country) -> Self {
199 self.country = Some(country);
200 self
201 }
202
203 pub const fn main_fuses(mut self, main_fuses: MainFuseSizes) -> Self {
204 self.main_fuses = Some(main_fuses);
205 self
206 }
207
208 pub const fn links(mut self, links: Links) -> Self {
209 self.links = Some(links);
210 self
211 }
212
213 pub const fn price_lists(mut self, price_lists: &'static [PriceList]) -> Self {
214 self.price_lists = Some(price_lists);
215 self
216 }
217
218 pub const fn build(self) -> GridOperator {
219 GridOperator {
220 name: self.name.expect("`name` required"),
221 vat_number: self.vat_number.expect("`vat_number` required"),
222 country: self.country.expect("`country` required"),
223 main_fuses: self.main_fuses.expect("`main_fuses` required"),
224 price_lists: self.price_lists.expect("`price_lists` expected"),
225 links: self.links.expect("`links` required"),
226 }
227 }
228}
229
230impl FromStr for &'static GridOperator {
231 type Err = &'static str;
232
233 fn from_str(s: &str) -> Result<Self, Self::Err> {
234 GridOperator::get_by_vat_id(s).ok_or("grid operator not found")
235 }
236}
237
238impl<'de> Deserialize<'de> for &'static GridOperator {
239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240 where
241 D: serde::Deserializer<'de>,
242 {
243 let s = String::deserialize(deserializer)?;
244 Self::from_str(&s).map_err(serde::de::Error::custom)
245 }
246}
247
248impl Serialize for GridOperator {
249 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
250 where
251 S: serde::Serializer,
252 {
253 serializer.serialize_str(self.vat_number())
254 }
255}
256
257impl PartialEq for GridOperator {
258 fn eq(&self, other: &Self) -> bool {
259 self.vat_number == other.vat_number
260 }
261}
262
263impl Eq for GridOperator {}
264
265impl PartialOrd for GridOperator {
266 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
267 self.vat_number.partial_cmp(&other.vat_number)
268 }
269}
270
271impl Ord for GridOperator {
272 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
273 self.vat_number.cmp(other.vat_number)
274 }
275}
276
277impl Hash for GridOperator {
278 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
279 self.vat_number.hash(state);
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_grid_operator_serialize_deserialize() {
289 let operator: &GridOperator = "SE556037732601".parse().unwrap();
290
291 let serialized = serde_json::to_string(operator).expect("serialization should succeed");
293
294 assert_eq!(serialized, format!("\"{}\"", operator.vat_number()));
296
297 let deserialized: &'static GridOperator =
299 serde_json::from_str(&serialized).expect("deserialization should succeed");
300
301 assert_eq!(deserialized.name(), operator.name());
303 assert_eq!(deserialized.vat_number(), operator.vat_number());
304 assert_eq!(deserialized.country(), operator.country());
305 }
306
307 #[test]
308 fn test_grid_operator_deserialize_invalid() {
309 let result: Result<&'static GridOperator, _> = serde_json::from_str("\"SE000000000000\"");
311
312 assert!(
313 result.is_err(),
314 "deserialization should fail for invalid VAT number"
315 );
316 }
317
318 #[test]
319 fn test_grid_operator_partial_eq() {
320 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
321 let operator2: &GridOperator = "SE556037732601".parse().unwrap();
322 let operator3: &GridOperator = "SE556532083401".parse().unwrap();
323
324 assert_eq!(operator1, operator2);
326
327 assert_ne!(operator1, operator3);
329 }
330
331 #[test]
332 fn test_grid_operator_partial_ord() {
333 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
334 let operator2: &GridOperator = "SE556532083401".parse().unwrap();
335
336 assert!(operator1 < operator2);
338 assert!(operator2 > operator1);
339 assert!(operator1 <= operator1);
340 assert!(operator1 >= operator1);
341 }
342
343 #[test]
344 fn test_grid_operator_ord() {
345 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
346 let operator2: &GridOperator = "SE556532083401".parse().unwrap();
347 let operator3: &GridOperator = "SE556037732601".parse().unwrap();
348
349 assert_eq!(operator1.cmp(operator2), std::cmp::Ordering::Less);
351 assert_eq!(operator2.cmp(operator1), std::cmp::Ordering::Greater);
352 assert_eq!(operator1.cmp(operator3), std::cmp::Ordering::Equal);
353 }
354
355 #[test]
356 fn test_grid_operator_hash() {
357 use std::collections::hash_map::DefaultHasher;
358 use std::hash::{Hash, Hasher};
359
360 let operator1: &GridOperator = "SE556037732601".parse().unwrap();
361 let operator2: &GridOperator = "SE556037732601".parse().unwrap();
362 let operator3: &GridOperator = "SE556532083401".parse().unwrap();
363
364 let compute_hash = |op: &GridOperator| {
366 let mut hasher = DefaultHasher::new();
367 op.hash(&mut hasher);
368 hasher.finish()
369 };
370
371 assert_eq!(compute_hash(operator1), compute_hash(operator2));
373
374 assert_ne!(compute_hash(operator1), compute_hash(operator3));
376 }
377}