1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use {
    crate::*,
    minimad::OwningTemplateExpander,
    termimad::*,
};

static MD: &str = r#"
|:-:|:-:|:-:|:-
|**date**|**hits**|**bytes**|**${scale}**
|:-|:-:|-:|:-
${bars
|${date}|${hits}|${bytes}|*${bar}*
}
|-:
"#;

#[derive(Clone)]
pub struct Bar {
    pub date: Date,
    pub hits: u64,
    pub bytes_sent: u64,
}

impl Bar {
    pub fn new(date: Date) -> Self {
        Self {
            date,
            hits: 0,
            bytes_sent: 0,
        }
    }
}

#[derive(Clone, Default)]
pub struct Histogram {
    pub bars: Vec<Bar>,
}

impl Histogram {

    pub fn from(base: &LogBase) -> Self {
        let mut bars: Vec<Bar> = base.dates.iter()
            .map(|&date| Bar { date, bytes_sent: 0, hits: 0 })
            .collect();
        for line in &base.lines {
            bars[line.date_idx].hits += 1;
            bars[line.date_idx].bytes_sent += line.bytes_sent;
        }
        Self { bars }
    }

    pub fn print(
        &self,
        printer: &md::Printer,
    ) {
        let mut expander = OwningTemplateExpander::new();
        let max_bar = self.bars
            .iter()
            .map(|b| if printer.key==Key::Hits { b.hits } else { b.bytes_sent })
            .max().unwrap();
        expander.set(
            "scale",
            format!("0               {:>4}", file_size::fit_4(max_bar)),
        );
        let max_bar = max_bar as f32;
        for bar in &self.bars {
            if printer.date_filter.map_or(true, |f| f.contains(bar.date)) {
                let value = if printer.key == Key::Hits { bar.hits } else { bar.bytes_sent };
                let part = (value as f32) / max_bar;
                expander.sub("bars")
                    .set("date", bar.date)
                    .set_md("hits", printer.md_hits(bar.hits as usize))
                    .set_md("bytes", printer.md_bytes(bar.bytes_sent))
                    .set("bar", ProgressBar::new(part, 20));
            }
        }
        printer.print(expander, MD);
    }
    pub fn total_hits(&self) -> u64 {
        self.bars.iter().map(|b| b.hits).sum()
    }
    pub fn total_bytes_sent(&self) -> u64 {
        self.bars.iter().map(|b| b.bytes_sent).sum()
    }
}