kobo_db_tools/statistics/imp/
brightness.rs

1use crate::model::{BrightnessHistory, NaturalLightHistory};
2use crate::statistics::Statistics;
3
4impl Statistics for BrightnessHistory {
5    type Metric = ();
6
7    fn avg(&self) -> f64 {
8        if self.events.len() < 2 {
9            return self
10                .events
11                .first()
12                .map_or(0.0, |e| e.brightness.percentage as f64);
13        }
14
15        let mut weighted_sum = 0.0;
16        let mut total_duration = 0.0;
17
18        for i in 0..self.events.len() - 1 {
19            let current_event = &self.events[i];
20            let next_event = &self.events[i + 1];
21
22            let duration = (next_event.timestamp - current_event.timestamp).num_seconds() as f64;
23            if duration > 0.0 {
24                weighted_sum += current_event.brightness.percentage as f64 * duration;
25                total_duration += duration;
26            }
27        }
28
29        if total_duration == 0.0 {
30            self.events
31                .last()
32                .map_or(0.0, |e| e.brightness.percentage as f64)
33        } else {
34            weighted_sum / total_duration
35        }
36    }
37
38    fn calculate_percentile(&self, _metric: Self::Metric, _percentiles: &[f64]) -> Vec<f64> {
39        // Placeholder implementation
40        unimplemented!("Percentile calculation is not implemented for BrightnessHistory");
41    }
42}
43
44impl Statistics for NaturalLightHistory {
45    type Metric = ();
46
47    fn avg(&self) -> f64 {
48        if self.events.len() < 2 {
49            return self
50                .events
51                .first()
52                .map_or(0.0, |e| e.brightness.percentage as f64);
53        }
54
55        let mut weighted_sum = 0.0;
56        let mut total_duration = 0.0;
57
58        for i in 0..self.events.len() - 1 {
59            let current_event = &self.events[i];
60            let next_event = &self.events[i + 1];
61
62            let duration = (next_event.timestamp - current_event.timestamp).num_seconds() as f64;
63            if duration > 0.0 {
64                weighted_sum += current_event.brightness.percentage as f64 * duration;
65                total_duration += duration;
66            }
67        }
68
69        if total_duration == 0.0 {
70            self.events
71                .last()
72                .map_or(0.0, |e| e.brightness.percentage as f64)
73        } else {
74            weighted_sum / total_duration
75        }
76    }
77
78    fn calculate_percentile(&self, _metric: Self::Metric, percentiles: &[f64]) -> Vec<f64> {
79        let mut values: Vec<f64> = self
80            .events
81            .iter()
82            .map(|e| e.brightness.percentage as f64)
83            .collect();
84
85        if values.is_empty() {
86            return vec![0.0];
87        }
88
89        values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Less));
90        percentiles
91            .iter()
92            .map(|&p| {
93                let idx = ((p.clamp(0.0, 1.0)) * ((values.len() - 1) as f64)).round() as usize;
94                values.get(idx).copied().unwrap_or(0.0)
95            })
96            .collect()
97    }
98}