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