1package Onis::Plugins::Longterm; 2 3use strict; 4use warnings; 5 6use Exporter; 7 8use Onis::Config (qw(get_config)); 9use Onis::Html (qw(get_filehandle)); 10use Onis::Language (qw(translate)); 11use Onis::Data::Core (qw(register_plugin get_main_nick get_most_recent_time nick_to_ident nick_to_name)); 12use Onis::Data::Persistent (); 13 14=head1 NAME 15 16Onis::Plugins::Longterm 17 18=cut 19 20@Onis::Plugins::Longterm::EXPORT_OK = (qw(get_longterm)); 21@Onis::Plugins::Longterm::ISA = ('Exporter'); 22 23register_plugin ('TEXT', \&add); 24register_plugin ('ACTION', \&add); 25register_plugin ('OUTPUT', \&output); 26 27our $LongtermLastSeen = Onis::Data::Persistent->new ('LongtermLastSeen', 'nick', 'day'); 28our $LongtermCache = Onis::Data::Persistent->new ('LongtermCache', 'key', qw(time0 time1 time2 time3)); 29our $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 37Sets the images to use for vertical graphs. 38 39=cut 40 41our @VImages = get_config ('vertical_images'); 42if (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 49Sets the number of days displayed by this plugin. 50 51=cut 52 53our $DisplayDays = 31; 54if (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 65my $VERSION = '$Id$'; 66print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG); 67 68return (1); 69 70sub 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 102sub 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 155sub 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 223Returns the longterm-statistics for I<$nick>. The numbers are array-counters. 224The 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 235sub 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 251Florian octo Forster E<lt>octo at verplant.orgE<gt> 252 253=cut 254