Completed the Longterm Plugin. It seems to drain performance quite a bit though....
[onis.git] / lib / Onis / Plugins / Longterm.pm
1 package Onis::Plugins::Longterm;
2
3 use strict;
4 use warnings;
5
6 use Onis::Config (qw(get_config));
7 use Onis::Html (qw(get_filehandle));
8 use Onis::Language (qw(translate));
9 use Onis::Data::Core (qw(register_plugin get_main_nick get_most_recent_time nick_to_ident nick_to_name));
10 use Onis::Data::Persistent ();
11
12 register_plugin ('TEXT', \&add);
13 register_plugin ('ACTION', \&add);
14 register_plugin ('OUTPUT', \&output);
15
16 our $LongtermLastSeen = Onis::Data::Persistent->new ('LongtermLastSeen', 'nick', 'day');
17 our $LongtermCache    = Onis::Data::Persistent->new ('LongtermCache', 'key', qw(time0 time1 time2 time3));
18 our $LongtermData     = {};
19
20 =head1 CONFIGURATION OPTIONS
21
22 =over 4
23
24 =item B<vertical_images>: I<image0>, I<image1>, I<image2>, I<image3>;
25
26 Sets the images to use for vertical graphs.
27
28 =cut
29
30 our @VImages = get_config ('vertical_images');
31 if (scalar (@VImages) != 4)
32 {
33         @VImages = qw#images/ver0n.png images/ver1n.png images/ver2n.png images/ver3n.png#;
34 }
35
36 =item B<longterm_days>: I<31>;
37
38 Sets the number of days displayed by this plugin.
39
40 =cut
41
42 our $DisplayDays = 31;
43 if (get_config ('longterm_days'))
44 {
45         my $tmp = get_config ('longterm_days');
46         $tmp =~ s/\D//g;
47         $DisplayDays = $tmp if ($tmp);
48 }
49
50 =back
51
52 =cut
53
54 my $VERSION = '$Id$';
55 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
56
57 return (1);
58
59 sub add
60 {
61         my $data = shift;
62         my $nick = $data->{'nick'};
63         my $time = $data->{'epoch'};
64         my $hour = int ($data->{'hour'} / 6);
65         my $chars = length ($data->{'text'});
66         my $day   = int ($time / 86400);
67         my $index = ($day * 4) + $hour;
68
69         my ($lastseen) = $LongtermLastSeen->get ($nick);
70         $lastseen ||= $day;
71         
72         for (my $i = $lastseen; $i < $day; $i++)
73         {
74                 my $last = $i - $DisplayDays;
75                 $LongtermCache->del ($nick . ':' . $last);
76
77                 if ($i != $lastseen)
78                 {
79                         $LongtermCache->put ($nick . ':' . $i, qw(0 0 0 0));
80                 }
81         }
82
83         my @data = $LongtermCache->get ($nick . ':' . $day);
84         @data = (qw(0 0 0 0)) unless (@data);
85         $data[$hour] += $chars;
86         $LongtermCache->put ($nick . ':' . $day, @data);
87
88         $LongtermLastSeen->put ($nick, $day);
89 }
90
91 sub calculate
92 {
93         my $now_epoch = get_most_recent_time ();
94         my $now = int ($now_epoch / 86400);
95         return unless ($now);
96
97         my $old = 1 + $now - $DisplayDays;
98
99         my $del = {};
100
101         for ($LongtermLastSeen->keys ())
102         {
103                 my $nick = $_;
104                 my ($last) = $LongtermLastSeen->get ($nick);
105
106                 if ($last < $old)
107                 {
108                         $del->{$nick} = $last;
109                         $LongtermLastSeen->del ($nick);
110                 }
111         }
112         
113         for ($LongtermCache->keys ())
114         {
115                 my $key = $_;
116                 my ($nick, $day) = split (m/:/, $key);
117
118                 if (defined ($del->{$nick}) or ($day < $old))
119                 {
120                         $LongtermCache->del ($key);
121                         next;
122                 }
123
124                 my $idx = $day - $old;
125                 my $main = get_main_nick ($nick);
126                 my @data = $LongtermCache->get ($key);
127                 
128                 if (!defined ($LongtermData->{$main}))
129                 {
130                         $LongtermData->{$main} = [];
131                         $LongtermData->{$main}[$_] = [0, 0, 0, 0] for (0 .. ($DisplayDays - 1));
132                 }
133                 if (!defined ($LongtermData->{'<TOTAL>'}))
134                 {
135                         $LongtermData->{'<TOTAL>'} = [];
136                         $LongtermData->{'<TOTAL>'}[$_] = [0, 0, 0, 0] for (0 .. ($DisplayDays - 1));
137                 }
138
139                 $LongtermData->{$main}[$idx][$_] += $data[$_] for (0 .. 3);
140                 $LongtermData->{'<TOTAL>'}[$idx][$_] += $data[$_] for (0 .. 3);
141         }
142 }
143
144 sub output
145 {
146         calculate ();
147         return (undef) unless (%$LongtermData);
148
149         my $now_epoch = get_most_recent_time ();
150         my $now = int ($now_epoch / 86400);
151         return unless ($now);
152
153         my $old = 1 + $now - $DisplayDays;
154
155         my $data = $LongtermData->{'<TOTAL>'};
156
157         my @weekdays = (qw(sun mon tue wed thu fri sat sun));
158
159         my $fh = get_filehandle ();
160         
161         my $max = 0;
162         my $total = 0;
163
164         for (my $i = 0; $i < $DisplayDays; $i++)
165         {
166                 for (my $j = 0; $j < 4; $j++)
167                 {
168                         $max = $data->[$i][$j] if ($max < $data->[$i][$j]);
169                         $total += $data->[$i][$j];
170                 }
171         }
172         
173         print $fh qq#<table class="plugin longterm">\n  <tr class="bars">\n#;
174         for (my $i = 0; $i < $DisplayDays; $i++)
175         {
176                 for (my $j = 0; $j < 4; $j++)
177                 {
178                         my $num = $data->[$i][$j];
179                         my $height = sprintf ("%.2f", (95 * $num / $max));
180                         my $img = $VImages[$j];
181
182                         print $fh qq#    <td class="bar vertical">#,
183                         qq(<img src="$img" alt="" class="first last" style="height: ${height}%;" /></td>\n);
184                 }
185         }
186         print $fh qq(  </tr>\n  <tr class="counter">\n);
187         for (my $i = 0; $i < $DisplayDays; $i++)
188         {
189                 my $sum = $data->[$i][0] + $data->[$i][1] + $data->[$i][2] + $data->[$i][3];
190                 my $percent = sprintf ("%.1f", 100 * $sum / $total);
191
192                 print $fh qq(    <td colspan="4" class="counter">$percent%</td>\n);
193         }
194         print $fh qq(  </tr>\n  <tr class="numeration">\n);
195         for (my $i = 0; $i < $DisplayDays; $i++)
196         {
197                 my $epoch = ($old + $i) * 86400;
198                 my ($day, $wd) = (localtime ($epoch))[3,6];
199                 my $class = $weekdays[$wd];
200                 
201                 print $fh qq(    <td colspan="4" class="numeration $class">$day.</td>\n);
202         }
203         print $fh "  </tr>\n</table>\n\n";
204 }