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