sglab02_lib/web/
wk5g.rs

1use crate::sg::{dcl, dcl::DaVa, /*ldp*/ ldp::base, uty::NumForm, wk5};
2use askama::Template;
3//use askama_axum;
4//use axum::extract::{Path, Query};
5use regex::{/*Captures*/ Regex};
6use serde::{Deserialize, Serialize};
7use std::cmp::{/*Eq, Ord, PartialEq,*/ PartialOrd};
8//use std::collections::{HashMap, HashSet};
9use std::sync::Arc;
10//use thousands::Separable;
11use tokio::sync::RwLock;
12use tokio::sync::{OwnedRwLockReadGuard, /*RwLockReadGuard*/};
13
14#[derive(Template, Debug)]
15#[template(path = "pg2/wk5f.html", escape = "none")]
16pub struct ReportTemp {
17    pub title: String,
18    pub wk: OwnedRwLockReadGuard<wk5::Wk5Proc>,
19}
20
21fn rp(wk5prc: &wk5::Wk5Proc) -> &Report {
22    &wk5prc.wk5g
23}
24fn sp(wk5prc: &mut wk5::Wk5Proc, rp: Report) {
25    wk5prc.wk5g = rp;
26}
27
28impl ReportTemp {
29    pub fn repo(&self) -> &Report {
30        &self.wk.wk5g
31    }
32    async fn new(wk5prc: Arc<RwLock<wk5::Wk5Proc>>) -> Self {
33        let wk = wk5prc.read_owned().await;
34        let title = "SOLAR ENERGY PROJECTION : WK5G";
35        let title = title.to_string();
36
37        ReportTemp { wk, title }
38    }
39    pub fn sum(&self, c: &usize) -> String {
40        if *c == 0 {
41            return format!("");
42        }
43        match rp(&self.wk).sums[*c] {
44            //DaVa::F32(v) => ((v * 100.0).floor() / 100.0).separate_with_commas(),
45            DaVa::F32(v) => v.form(),
46            DaVa::F64(v) => v.form(),
47            DaVa::USZ(v) => v.form(),
48            DaVa::I32(v) => v.form(),
49            DaVa::I64(v) => v.form(),
50            _ => format!(""),
51        }
52    }
53    pub fn cell(&self, r: &usize, c: &usize) -> String {
54        let mut ce = rp(&self.wk).dava(&self.wk.ssv, *r, *c);
55        if *c == 5 {
56            if let DaVa::F32(v) = ce {
57                let s = rp(&self.wk).rows[*r].s;
58                let f = rp(&self.wk).rows[*r].f;
59                let ss = &self.wk.ssv[s].ssid;
60                let fd = &self.wk.ssv[s].feeders[f].fdid;
61                ce = DaVa::Text(format!(
62                    "<a href='/feeder_yrpw01/{}/{}'>{}</a>",
63                    ss,
64                    fd,
65                    v.form()
66                ));
67            }
68        }
69        match ce {
70            DaVa::Text(s) => s,
71            DaVa::F32(f) => ((f * 100.0).floor() / 100.0).form(),
72            DaVa::F64(f) => ((f * 100.0).floor() / 100.0).form(),
73            DaVa::USZ(u) => format!("{}", u),
74            d => format!("{:?}", d),
75        }
76    }
77}
78
79#[derive(Serialize, Deserialize, Debug, Clone, Default)]
80pub struct Report {
81    pub rows: Vec<RepoRow1>,
82    pub cols: Vec<String>,
83    pub sums: Vec<DaVa>,
84}
85
86#[derive(Serialize, Deserialize, Debug, Clone, Default)]
87pub struct RepoRow1 {
88    pub s: usize, // substation
89    pub f: usize, // feeder
90}
91
92const TT: [&str; 4] = ["NO", "NAME", "FDID", "ENERGY:mwh"];
93
94pub async fn make_repo(wk5prc: &mut wk5::Wk5Proc, _acfg: Arc<RwLock<dcl::Config>>) {
95    let mut repo = rp(wk5prc).clone();
96
97    //let cfg = acfg.read().await;
98    for t in TT {
99        repo.cols.push(t.to_string());
100        repo.sums.push(DaVa::None);
101    }
102    let cfg = base().config.read().await;
103    let syf = cfg.criteria.start_year_from_2022;
104    let imy = cfg.criteria.implement_year;
105    let opy = cfg.criteria.operate_year;
106    let yrl = syf + imy + opy;
107    let yrl = yrl as usize;
108    for i in 0..yrl {
109        let yr = 2022 + i + 1;
110        repo.cols.push(format!("{}:MWh", yr));
111        repo.sums.push(DaVa::None);
112    }
113    let re = Regex::new(r"..._[0-9][0-9].+").unwrap();
114    for s in 0..wk5prc.ssv.len() {
115        for f in 0..wk5prc.ssv[s].feeders.len() {
116            let mut rw = RepoRow1::default();
117            rw.s = s;
118            rw.f = f;
119            let fd = &wk5prc.ssv[s].feeders[f];
120            if re.is_match(fd.fdid.as_str()) {
121                //if &fd.fdid[5..6] == "V" {
122                if fd.ev.ev_ds > 0.0 && fd.tx.tx_no > 0 {
123                    repo.rows.push(rw);
124                }
125            }
126        }
127    }
128    repo.rows.sort_by(|a, b| {
129        let a0 = &wk5prc.ssv[a.s].prov;
130        let a1 = &wk5prc.ssv[a.s].ssid;
131        let a2 = &wk5prc.ssv[a.s].feeders[a.f].fdid;
132        let b0 = &wk5prc.ssv[b.s].prov;
133        let b1 = &wk5prc.ssv[b.s].ssid;
134        let b2 = &wk5prc.ssv[b.s].feeders[b.f].fdid;
135		if a0!=b0 {
136			a0.partial_cmp(b0).unwrap()
137		} else {
138			if a1!=b1 {
139				a1.partial_cmp(b1).unwrap()
140			} else {
141				a2.partial_cmp(b2).unwrap()
142			}
143		}
144		/*
145        let a1 = &wk5prc.ssv[a.s].feeders[a.f].year_load.power_quality.pos_energy;
146        let b1 = &wk5prc.ssv[b.s].feeders[b.f].year_load.power_quality.pos_energy;
147        b1.partial_cmp(a1).unwrap()
148		*/
149    });
150    sum(&mut repo, &wk5prc.ssv);
151    sp(wk5prc, repo);
152}
153
154impl Report {
155    pub fn dava(&self, ssv: &Vec<wk5::Substation>, r: usize, c: usize) -> dcl::DaVa {
156        let s = self.rows[r].s;
157        let f = self.rows[r].f;
158        let ss = &ssv[s];
159        let fd = &ssv[s].feeders[f];
160        match c {
161            0 => DaVa::USZ(r + 1),
162            1 => DaVa::Text(ss.name.to_string()),
163            2 => DaVa::Text(fd.fdid5.to_string()),
164            3 => DaVa::F32(fd.year_load.power_quality.pos_energy),
165            // ========
166            n => DaVa::F32(fd.solar_energy_series[n - 4]),
167        }
168    }
169}
170
171// ========================================================================
172// ========================================================================
173
174pub async fn handler() -> ReportTemp {
175    ReportTemp::new(base().wk5prc.clone()).await
176}
177
178fn sum(repo: &mut Report, ssv: &Vec<wk5::Substation>) {
179    if repo.rows.len() > 0 {
180        repo.sums[0] = DaVa::None;
181        for ci in 1..repo.cols.len() {
182            repo.sums[ci] = match repo.dava(ssv, 0, ci) {
183                DaVa::F32(_) => DaVa::F32(0.0),
184                DaVa::F64(_) => DaVa::F64(0.0),
185                DaVa::I32(_) => DaVa::I32(0),
186                DaVa::I64(_) => DaVa::I64(0),
187                DaVa::USZ(_) => DaVa::USZ(0),
188                _ => DaVa::None,
189            };
190        }
191        //let mut txno = 0;
192        for (ri, _rr) in repo.rows.iter().enumerate() {
193            if let DaVa::USZ(_v) = repo.dava(ssv, ri, 5) {
194               // txno += v;
195            }
196
197            for ci in 0..repo.cols.len() {
198                repo.sums[ci] = match repo.dava(ssv, ri, ci) {
199                    DaVa::F32(v1) => {
200                        if let DaVa::F32(v2) = repo.sums[ci] {
201                            DaVa::F32(v1 + v2)
202                        } else {
203                            DaVa::F32(0.0)
204                        }
205                    }
206                    DaVa::F64(v1) => {
207                        if let DaVa::F64(v2) = repo.sums[ci] {
208                            DaVa::F64(v1 + v2)
209                        } else {
210                            DaVa::F64(0.0)
211                        }
212                    }
213                    DaVa::I32(v1) => {
214                        if let DaVa::I32(v2) = repo.sums[ci] {
215                            DaVa::I32(v1 + v2)
216                        } else {
217                            DaVa::I32(0)
218                        }
219                    }
220                    DaVa::I64(v1) => {
221                        if let DaVa::I64(v2) = repo.sums[ci] {
222                            DaVa::I64(v1 + v2)
223                        } else {
224                            DaVa::I64(0)
225                        }
226                    }
227                    DaVa::USZ(v1) => {
228                        if let DaVa::USZ(v2) = repo.sums[ci] {
229                            DaVa::USZ(v1 + v2)
230                        } else {
231                            DaVa::USZ(0)
232                        }
233                    }
234                    _ => DaVa::None,
235                };
236            }
237        }
238    }
239}
240/*
241pub trait Comm<T> {
242    fn comm(&self) -> String;
243}
244impl<T, U> Comm<T> for U
245where
246    U: Separable,
247    T: Separable,
248{
249    fn comm(&self) -> String {
250        let cm = self.separate_with_commas();
251        let re = Regex::new(r"([0-9,]+)\.([0-9]+)").unwrap();
252        let cm = re.replace(cm.as_str(), |caps: &Captures| {
253            format!(
254                "{}.{}",
255                &caps[1],
256                if caps[2].len() > 2 {
257                    format!("{}", &caps[2][0..2])
258                } else {
259                    if caps[2].len() < 2 {
260                        format!("{}0", &caps[2][0..1])
261                    } else {
262                        format!("{}", &caps[2])
263                    }
264                }
265            )
266        });
267        format!("{}", cm)
268    }
269}
270pub trait Comma {
271    fn comma(&self) -> String;
272}
273fn comma0(cm: String) -> String {
274    let re = Regex::new(r"([0-9,]+)\.([0-9]+)").unwrap();
275    let cm = re.replace(cm.as_str(), |caps: &Captures| {
276        format!(
277            "{}.{}",
278            &caps[1],
279            if caps[2].len() > 2 {
280                format!("{}", &caps[2][0..2])
281            } else {
282                if caps[2].len() < 2 {
283                    format!("{}0", &caps[2][0..1])
284                } else {
285                    format!("{}", &caps[2])
286                }
287            }
288        )
289    });
290    format!("{}", cm)
291}
292impl Comma for f32 {
293    fn comma(&self) -> String {
294        comma0(self.separate_with_commas())
295    }
296}
297impl Comma for f64 {
298    fn comma(&self) -> String {
299        comma0(self.separate_with_commas())
300    }
301}
302impl Comma for i32 {
303    fn comma(&self) -> String {
304        comma0(self.separate_with_commas())
305    }
306}
307impl Comma for i64 {
308    fn comma(&self) -> String {
309        comma0(self.separate_with_commas())
310    }
311}
312impl Comma for usize {
313    fn comma(&self) -> String {
314        comma0(self.separate_with_commas())
315    }
316}
317*/