about summary refs log tree commit diff stats
path: root/lib/Taurus/CLI.rakumod
blob: 7d80f51d4f658f74c847e9dcc00ec59665450d29 (plain) (blame)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use Taurus::Seconds;

use CSV::Parser;
use Terminal::UI 'ui';
use Terminal::ANSI::OO 't';

# If no arguments are passed then run USAGE & exit.
proto MAIN(|) is export {unless so @*ARGS {put $*USAGE; exit}; {*}}

#| parses Call Logs
multi sub MAIN (
    Str $log where *.IO.f, #= input log file to parse
    UInt :$digits = 10, #= number of significant digits
) is export {
    my @logs;
    my Str %contacts{Str};

    my Instant $timed = now;
    my Promise $initial = start {
        my $p = CSV::Parser.new();
        # 0: Name, 1: Phone number, 2: Call Type,
        # 3: Timestamp, 4: Duration, 5: Sim used.

        # Turn the Hash to an Array.
        @logs = @($log.IO.lines.skip.hyper.map({$p.parse($_)})>>.{0..4}
                  # Discard invalid phone numbers.
                  .grep(*.[1].chars >= $digits));

        for @logs {
            # Discard non-significant digits from phone numbers.
            .[1] .= substr(*-10);

            # Removing leading/trailing whitespaces from names.
            .[0] .= trim;

            # Build contact list.
            %contacts{.[1]} = .[0] if .[0].chars > 0;

            # Store Duration in seconds.
            .[4] = (.[4].split(":")[0] * 60) + .[4].split(":")[1];
        }
    };

    ui.setup: :2panes;
    my $p0 = ui.panes[0];
    my $p1 = ui.panes[1];

    $p0.put: t.bold ~ t.bg-cyan ~ t.black ~t.underline~ "Taurus v" ~ $?DISTRIBUTION.meta<version>;
    $p0.put: "";

    with ui.screen.add-frame(:4height, :40width, :center) -> $f {
        with $f.add-pane -> $p {
            $f.draw;
            until $initial.status {
                $p.splash: "Parsing logs" ~ (".  ", ".. ", "...")[$++ % 3];
                sleep 1;
            }
            $p.splash: "Parsed {@logs.elems} entries in {now - $timed}s.";
            $p.put: " " x 18 ~ "Ok";
            $p.select-last;
            ui.focus($f);
        }
        ui.get-key;
        ui.screen.remove-frame($f);
        ui.focus($f);
    }
    ui.refresh;

    $p0.put: "- Show Records", :meta(:all);
    $p0.put: "";
    # First list Contacts, then sorted phone numbers.
    for @logs.race.map(*.[1]).unique.sort({%contacts{$_} // "Z", $_}) {
        $p0.put: "- " ~ $_ ~ " {%contacts{$_} // ''}", :meta(:number($_));
    }

    $p1.clear;
    $p0.select-first;
    $p0.select(2);
    $p0.on: select => -> :%meta {
        my Int $fmt = 16;
        if %meta<all> {
            ui.focus(:pane(1));
            $p1.clear;
            with @logs {
                my $outgoing = .grep(*.[2] eqv "Outgoing Call").map(*.[4]).sum;
                my $incoming = .grep(*.[2] eqv "Incoming Call").map(*.[4]).sum;

                $p1.put: "%-*s %s".sprintf($fmt, "Outgoing:", seconds-to-str($outgoing));
                $p1.put: "%-*s %s".sprintf($fmt, "Incoming:",  seconds-to-str($incoming));
                $p1.put: "%-*s %s".sprintf($fmt, "Total:",  seconds-to-str($outgoing + $incoming));
                $p1.put: "";
            }
            $p1.select-first;
        } elsif %meta<number> -> $num {
            ui.focus(:pane(1));
            $p1.clear;
            $p1.put: "Name:   " ~ $_ with %contacts{$num};
            $p1.put: "Number: " ~ $num;
            $p1.put: "";
            with @logs.grep(*.[1] eqv $num).cache {
                my $outgoing = .grep(*.[2] eqv "Outgoing Call").map(*.[4]).sum;
                my $incoming = .grep(*.[2] eqv "Incoming Call").map(*.[4]).sum;

                $p1.put: "%-*s %s".sprintf($fmt, "Outgoing:", seconds-to-str($outgoing));
                $p1.put: "%-*s %s".sprintf($fmt, "Incoming:", seconds-to-str($incoming));
                $p1.put: "%-*s %s".sprintf($fmt, "Total:", seconds-to-str($outgoing + $incoming));
                $p1.put: "";

                $p1.put: "%-*s %d".sprintf($fmt, "Declined:",
                                           .grep({$_.[2] eqv "Incoming Call" and $_.[4] == 0}).elems);
                $p1.put: "%-*s %d".sprintf($fmt, "Declined (they):",
                                           .grep({$_.[2] eqv "Outgoing Call" and $_.[4] == 0}).elems);
                $p1.put: "%-*s %d".sprintf($fmt, "Missed Calls:",
                                           .grep(*.[2] eqv "Missed Call").elems);
            }
            $p1.select-first;
        }
    }

    ui.interact;
    ui.shutdown;
}


multi sub MAIN(
    Bool :$version #= print version
) is export { put "Taurus v" ~ $?DISTRIBUTION.meta<version>; }