5294483fa1656b290dd6319c967e2d4981696698
[onis.git] / lib / Onis / Plugins / Core.pm
1 package Onis::Plugins::Core;
2
3 use strict;
4 use warnings;
5
6 use Carp (qw(confess));
7 use Exporter;
8
9 =head1 NAME
10
11 Onis::Plugins::Core
12
13 =head1 DESCRIPTION
14
15 Plugin for the main table and the hourly-statistics. This is the most
16 complicated plugin so far.
17
18 =cut
19
20 use Onis::Config qw/get_config/;
21 use Onis::Html qw/html_escape get_filehandle/;
22 use Onis::Language qw/translate/;
23 use Onis::Users (qw(get_realname get_link get_image ident_to_name));
24 use Onis::Data::Core qw#get_all_nicks nick_to_ident ident_to_nick get_main_nick register_plugin#;
25 use Onis::Data::Persistent;
26
27 @Onis::Plugins::Core::EXPORT_OK = (qw(get_core_nick_counters));
28 @Onis::Plugins::Core::ISA = ('Exporter');
29
30 our $NickLinesCounter = Onis::Data::Persistent->new ('NickLinesCounter', 'nick',
31         qw(
32                 lines00 lines01 lines02 lines03 lines04 lines05 lines06 lines07 lines08 lines09 lines10 lines11
33                 lines12 lines13 lines14 lines15 lines16 lines17 lines18 lines19 lines20 lines21 lines22 lines23
34         )
35 );
36 our $NickWordsCounter = Onis::Data::Persistent->new ('NickWordsCounter', 'nick',
37         qw(
38                 words00 words01 words02 words03 words04 words05 words06 words07 words08 words09 words10 words11
39                 words12 words13 words14 words15 words16 words17 words18 words19 words20 words21 words22 words23
40         )
41 );
42 our $NickCharsCounter = Onis::Data::Persistent->new ('NickCharsCounter', 'nick',
43         qw(
44                 chars00 chars01 chars02 chars03 chars04 chars05 chars06 chars07 chars08 chars09 chars10 chars11
45                 chars12 chars13 chars14 chars15 chars16 chars17 chars18 chars19 chars20 chars21 chars22 chars23
46         )
47 );
48
49 our $QuoteCache = {}; # Saves per-nick information without any modification
50 our $QuoteData = {};  # Is generated before output. Nicks are merged according to Data::Core.
51 our $NickData = {};  # Same as above, but for nicks rather than quotes.
52
53 our @H_IMAGES = qw#dark-theme/h-red.png dark-theme/h-blue.png dark-theme/h-yellow.png dark-theme/h-green.png#;
54 our $QuoteCacheSize = 10;
55 our $QuoteMin = 30;
56 our $QuoteMax = 80;
57 our $WORD_LENGTH = 5;
58 our $SORT_BY = 'LINES';
59 our $DISPLAY_LINES = 'BOTH';
60 our $DISPLAY_WORDS = 'NONE';
61 our $DISPLAY_CHARS = 'NONE';
62 our $DISPLAY_TIMES = 0;
63 our $DISPLAY_IMAGES = 0;
64 our $DEFAULT_IMAGE = '';
65 our $BAR_HEIGHT = 130;
66 our $BAR_WIDTH  = 100;
67 our $LongLines  = 50;
68 our $ShortLines = 10;
69
70 if (get_config ('quote_cache_size'))
71 {
72         my $tmp = get_config ('quote_cache_size');
73         $tmp =~ s/\D//g;
74         $QuoteCacheSize = $tmp if ($tmp);
75 }
76 if (get_config ('quote_min'))
77 {
78         my $tmp = get_config ('quote_min');
79         $tmp =~ s/\D//g;
80         $QuoteMin = $tmp if ($tmp);
81 }
82 if (get_config ('quote_max'))
83 {
84         my $tmp = get_config ('quote_max');
85         $tmp =~ s/\D//g;
86         $QuoteMax = $tmp if ($tmp);
87 }
88 if (get_config ('min_word_length'))
89 {
90         my $tmp = get_config ('min_word_length');
91         $tmp =~ s/\D//g;
92         $WORD_LENGTH = $tmp if ($tmp);
93 }
94 if (get_config ('display_lines'))
95 {
96         my $tmp = get_config ('display_lines');
97         $tmp = uc ($tmp);
98
99         if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
100         {
101                 $DISPLAY_LINES = $tmp;
102         }
103         else
104         {
105                 $tmp = get_config ('display_lines');
106                 print STDERR $/, __FILE__, ": ``display_lines'' has been set to the invalid value ``$tmp''. ",
107                 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``both''.";
108         }
109 }
110 if (get_config ('display_words'))
111 {
112         my $tmp = get_config ('display_words');
113         $tmp = uc ($tmp);
114
115         if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
116         {
117                 $DISPLAY_WORDS = $tmp;
118         }
119         else
120         {
121                 $tmp = get_config ('display_words');
122                 print STDERR $/, __FILE__, ": ``display_words'' has been set to the invalid value ``$tmp''. ",
123                 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''.";
124         }
125 }
126 if (get_config ('display_chars'))
127 {
128         my $tmp = get_config ('display_chars');
129         $tmp = uc ($tmp);
130
131         if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH'))
132         {
133                 $DISPLAY_CHARS = $tmp;
134         }
135         else
136         {
137                 $tmp = get_config ('display_chars');
138                 print STDERR $/, __FILE__, ": ``display_chars'' has been set to the invalid value ``$tmp''. ",
139                 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''.";
140         }
141 }
142 if (get_config ('display_times'))
143 {
144         my $tmp = get_config ('display_times');
145
146         if ($tmp =~ m/true|on|yes/i)
147         {
148                 $DISPLAY_TIMES = 1;
149         }
150         elsif ($tmp =~ m/false|off|no/i)
151         {
152                 $DISPLAY_TIMES = 0;
153         }
154         else
155         {
156                 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ",
157                 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''.";
158         }
159 }
160 if (get_config ('display_images'))
161 {
162         my $tmp = get_config ('display_images');
163
164         if ($tmp =~ m/true|on|yes/i)
165         {
166                 $DISPLAY_IMAGES = 1;
167         }
168         elsif ($tmp =~ m/false|off|no/i)
169         {
170                 $DISPLAY_IMAGES = 0;
171         }
172         else
173         {
174                 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ",
175                 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''.";
176         }
177 }
178 if (get_config ('default_image'))
179 {
180         $DEFAULT_IMAGE = get_config ('default_image');
181 }
182 if (get_config ('sort_by'))
183 {
184         my $tmp = get_config ('sort_by');
185         $tmp = uc ($tmp);
186
187         if (($tmp eq 'LINES') or ($tmp eq 'WORDS') or ($tmp eq 'CHARS'))
188         {
189                 $SORT_BY = $tmp;
190         }
191         else
192         {
193                 $tmp = get_config ('sort_by');
194                 print STDERR $/, __FILE__, ": ``sort_by'' has been set to the invalid value ``$tmp''. ",
195                 $/, __FILE__, ": Valid values are ``lines'' and ``words''. Using default value ``lines''.";
196         }
197 }
198 if (get_config ('horizontal_images'))
199 {
200         my @tmp = get_config ('horizontal_images');
201         my $i;
202         
203         if (scalar (@tmp) != 4)
204         {
205                 print STDERR $/, __FILE__, ": The number of horizontal images is not four. The output might look weird.", $/;
206         }
207
208         for ($i = 0; $i < 4; $i++)
209         {
210                 if (!defined ($tmp[$i]))
211                 {
212                         next;
213                 }
214
215                 $H_IMAGES[$i] = $tmp[$i];
216         }
217 }
218 if (get_config ('bar_height'))
219 {
220         my $tmp = get_config ('bar_height');
221         $tmp =~ s/\D//g;
222         $BAR_HEIGHT = $tmp if ($tmp >= 10);
223 }
224 if (get_config ('bar_width'))
225 {
226         my $tmp = get_config ('bar_width');
227         $tmp =~ s/\D//g;
228         $BAR_WIDTH = $tmp if ($tmp >= 10);
229 }
230 if (get_config ('longlines'))
231 {
232         my $tmp = get_config ('longlines');
233         $tmp =~ s/\D//g;
234         $LongLines = $tmp if ($tmp);
235 }
236 if (get_config ('shortlines'))
237 {
238         my $tmp = get_config ('shortlines');
239         $tmp =~ s/\D//g;
240         if ($tmp or ($tmp == 0))
241         {
242                 $ShortLines = $tmp;
243         }
244 }
245
246 register_plugin ('TEXT', \&add);
247 register_plugin ('ACTION', \&add);
248 register_plugin ('OUTPUT', \&output);
249
250 my $VERSION = '$Id$';
251 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
252
253 return (1);
254
255 sub add
256 {
257         my $data = shift;
258
259         my $nick = $data->{'nick'};
260         my $ident = $data->{'ident'};
261         my $hour = int ($data->{'hour'});
262         my $host = $data->{'host'};
263         my $text = $data->{'text'};
264         my $type = $data->{'type'};
265         my $time = $data->{'epoch'};
266
267         my $words = scalar (@{$data->{'words'}});
268         my $chars = length ($text);
269
270         if ($type eq 'ACTION')
271         {
272                 $chars -= (length ($nick) + 3);
273         }
274
275         my @counter = $NickLinesCounter->get ($nick);
276         if (!@counter)
277         {
278                 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0);
279         }
280         $counter[$hour]++;
281         $NickLinesCounter->put ($nick, @counter);
282
283         @counter = $NickWordsCounter->get ($nick);
284         if (!@counter)
285         {
286                 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0);
287         }
288         $counter[$hour] += $words;
289         $NickWordsCounter->put ($nick, @counter);
290
291         @counter = $NickCharsCounter->get ($nick);
292         if (!@counter)
293         {
294                 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0);
295         }
296         $counter[$hour] += $chars;
297         $NickCharsCounter->put ($nick, @counter);
298
299         if ((length ($text) >= $QuoteMin)
300                                 and (length ($text) <= $QuoteMax))
301         {
302                 if (!defined ($QuoteCache->{$nick}))
303                 {
304                         $QuoteCache->{$nick} = [];
305                 }
306                 push (@{$QuoteCache->{$nick}}, [$time, $text]);
307         }
308
309         if (defined ($QuoteCache->{$nick}))
310         {
311                 while (scalar (@{$QuoteCache->{$nick}}) > $QuoteCacheSize)
312                 {
313                         shift (@{$QuoteCache->{$nick}});
314                 }
315         }
316
317         return (1);
318 }
319
320 sub calculate
321 {
322         for (get_all_nicks ())
323         {
324                 my $nick = $_;
325                 my $main = get_main_nick ($nick);
326
327                 if (!defined ($NickData->{$main}))
328                 {
329                         $NickData->{$main} =
330                         {
331                                 lines => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)],
332                                 words => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)],
333                                 chars => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)],
334                                 lines_total => 0,
335                                 words_total => 0,
336                                 chars_total => 0
337                         };
338                 }
339
340                 my @counter = $NickLinesCounter->get ($nick);
341                 if (@counter)
342                 {
343                         my $sum = 0;
344                         for (my $i = 0; $i < 24; $i++)
345                         {
346                                 $NickData->{$main}{'lines'}[$i] += $counter[$i];
347                                 $sum += $counter[$i];
348                         }
349                         $NickData->{$main}{'lines_total'} = $sum;
350                 }
351
352                 @counter = $NickWordsCounter->get ($nick);
353                 if (@counter)
354                 {
355                         my $sum = 0;
356                         for (my $i = 0; $i < 24; $i++)
357                         {
358                                 $NickData->{$main}{'words'}[$i] += $counter[$i];
359                                 $sum += $counter[$i];
360                         }
361                         $NickData->{$main}{'words_total'} = $sum;
362                 }
363
364                 @counter = $NickWordsCounter->get ($nick);
365                 if (@counter)
366                 {
367                         my $sum = 0;
368                         for (my $i = 0; $i < 24; $i++)
369                         {
370                                 $NickData->{$main}{'words'}[$i] += $counter[$i];
371                                 $sum += $counter[$i];
372                         }
373                         $NickData->{$main}{'chars_total'} = $sum;
374                 }
375
376                 if (!defined ($QuoteData->{$main}))
377                 {
378                         $QuoteData->{$main} = [];
379                 }
380                 if (defined ($QuoteCache->{$nick}))
381                 {
382                         my @new = sort (sub { $b->[0] <=> $a->[0] }, @{$QuoteCache->{$nick}}, @{$QuoteData->{$main}});
383                         splice (@new, $QuoteCacheSize) if (scalar (@new) > $QuoteCacheSize);
384                         $QuoteData->{$main} = \@new;
385                 }
386         }
387 }
388
389 sub output
390 {
391         calculate ();
392         activetimes ();
393         ranking ();
394 }
395         
396 sub activetimes
397 {
398         my $max = 0;            # the most lines that were written in one hour..
399         my $total = 0;          # the total amount of lines we wrote..
400         my $factor = 0;         # used to find a bar's height
401
402         my @data = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0);
403
404         my @img_urls = get_config ('vertical_images');
405         if (!@img_urls)
406         {
407                 @img_urls = qw#images/ver0n.png images/ver1n.png images/ver2n.png images/ver3n.png#;
408         }
409
410         my $fh = get_filehandle () or die;
411         
412 # this for loop looks for the most amount of lines in one hour and sets
413 # $most_lines
414         for (keys %$NickData)
415         {
416                 my $nick = shift;
417
418                 for (my $i = 0; $i < 24; $i++)
419                 {
420                         $data[$i] += $NickData->{$nick}{'chars'}[$i];
421                 }
422         }
423
424         for (my $i = 0; $i < 24; $i++)
425         {
426                 $max = $data[$i] if ($max < $data[$i]);
427                 $total += $data[$i];
428         }
429
430         if (!$total)
431         {
432                 $total = 1;
433                 $max = 1;
434         }
435
436         $factor = (($BAR_HEIGHT - 1) / $max);
437
438         my $header = translate ('When do we actually talk here?');
439         print $fh "<h2>$header</h2>\n",
440         qq#<table class="hours_of_day">\n#,
441         qq#  <tr>\n#;
442
443 # this for circles through the four colors. Each color represents six hours.
444 # (4 * 6 hours = 24 hours)
445         for (my $i = 0; $i <= 3; $i++)
446         {
447                 for (my $j = 0; $j <= 5; $j++)
448                 {
449                         my $hour = (($i * 6) + $j);
450                         if (!defined ($data[$hour]))
451                         {
452                                 $data[$hour] = 0;
453                         }
454
455                         my $percent = 100 * ($data[$hour] / $total);
456                         my $height = int ($data[$hour] * $factor) + 1;
457                         my $img_url = $img_urls[$i];
458                         
459                         print $fh '    <td>', sprintf ("%2.1f", $percent),
460                         qq#%<br /><img src="$img_url" style="height: $height#,
461                         qq#px;" alt="" /></td>\n#;
462                 }
463         }
464
465         print $fh "  </tr>\n",
466         qq#  <tr class="hour_row">\n#;
467         print $fh map { "    <td>$_</td>\n" } (0 .. 23);
468         print $fh "  </tr>\n",
469         "</table>\n\n";
470 }
471
472 sub ranking
473 {
474         my $count = 0;
475
476         my @nicks = keys (%$NickData);
477
478         return unless (@nicks);
479         
480         my $max_lines = 1;
481         my $max_words = 1;
482         my $max_chars = 1;
483         
484         my $linescount = 0;
485
486         my $fh = get_filehandle () or die;
487
488         my $sort_field = lc ($SORT_BY);
489
490         my $trans;
491
492         my $tmp;
493         ($tmp) = sort { $NickData->{$b}{'lines_total'} <=> $NickData->{$a}{'lines_total'} } (@nicks);
494         $max_lines = $NickData->{$tmp}{'lines_total'} || 0;
495         
496         ($tmp) = sort { $NickData->{$b}{'words_total'} <=> $NickData->{$a}{'words_total'} } (@nicks);
497         $max_words = $NickData->{$tmp}{'words_total'} || 0;
498         
499         ($tmp) = sort { $NickData->{$b}{'chars_total'} <=> $NickData->{$a}{'chars_total'} } (@nicks);
500         $max_chars = $NickData->{$tmp}{'chars_total'} || 0;
501         
502         $trans = translate ('Most active nicks');
503         
504         print $fh "<h2>$trans</h2>\n";
505         if ($SORT_BY eq 'LINES')
506         {
507                 $trans = translate ('Nicks sorted by numbers of lines written');
508         }
509         elsif ($SORT_BY eq 'WORDS')
510         {
511                 $trans = translate ('Nicks sorted by numbers of words written');
512         }
513         else # ($SORT_BY eq 'CHARS')
514         {
515                 $trans = translate ('Nicks sorted by numbers of characters written');
516         }
517         print $fh "<p>($trans)</p>\n";
518
519         print $fh <<EOF;
520
521 <table class="big_ranking">
522   <tr>
523     <td class="invis">&nbsp;</td>
524 EOF
525         if ($DISPLAY_IMAGES)
526         {
527                 $trans = translate ('Image');
528                 print $fh "    <th>$trans</th>\n";
529         }
530         #if (true)
531         {
532                 $trans = translate ('Nick');
533                 print $fh "    <th>$trans</th>\n";
534         }
535         if ($DISPLAY_LINES ne 'NONE')
536         {
537                 $trans = translate ('Number of Lines');
538                 print $fh "    <th>$trans</th>\n";
539         }
540         if ($DISPLAY_WORDS ne 'NONE')
541         {
542                 $trans = translate ('Number of Words');
543                 print $fh "    <th>$trans</th>\n";
544         }
545         if ($DISPLAY_CHARS ne 'NONE')
546         {
547                 $trans = translate ('Number of Characters');
548                 print $fh "    <th>$trans</th>\n";
549         }
550         if ($DISPLAY_TIMES)
551         {
552                 $trans = translate ('When?');
553                 print $fh "    <th>$trans</th>\n";
554         }
555         
556         $trans = translate ('Random Quote');
557         print $fh "    <th>$trans</th>\n",
558         "  </tr>\n";
559
560         for (sort
561         {
562                 $NickData->{$b}{"${sort_field}_total"} <=> $NickData->{$a}{"${sort_field}_total"}
563         } (@nicks))
564         {
565                 my $nick = $_;
566                 my $ident = nick_to_ident ($nick);
567                 my $name  = ident_to_name ($ident);
568
569                 $linescount++;
570
571                 # As long as we didn't hit the 
572                 # $LongLines-limit we continue
573                 # our table..
574                 if ($linescount <= $LongLines)
575                 {
576                         my $quote = translate ('-- no quote available --');
577
578                         if (defined ($QuoteData->{$nick}))
579                         {
580                                 my $num = scalar (@{$QuoteData->{$nick}});
581                                 my $rand = int (rand ($num));
582                                 $quote = html_escape ($QuoteData->{$nick}[$rand]);
583                         }
584
585                         my $link = '';
586                         my $image = '';
587                         my $realname = '';
588                         if ($name)
589                         {
590                                 $link     = get_link ($name);
591                                 $image    = get_image ($name);
592                                 $realname = get_realname ($name);
593                         }
594                         
595                         print $fh "  <tr>\n",
596                         qq#    <td class="numeration"># . $linescount . "</td>\n";
597
598                         if ($DISPLAY_IMAGES)
599                         {
600                                 if ($DEFAULT_IMAGE and !$image)
601                                 {
602                                         $image = $DEFAULT_IMAGE;
603                                 }
604                                 
605                                 print $fh qq#    <td class="image">#;
606                                 if ($image)
607                                 {
608                                         if ($link)
609                                         {
610                                                 print $fh qq#<a href="$link">#;
611                                         }
612                                         print $fh qq#<img src="$image" alt="$name" />#;
613                                         if ($link)
614                                         {
615                                                 print $fh "</a>";
616                                         }
617                                 }
618                                 else
619                                 {
620                                         print $fh '&nbsp;';
621                                 }
622                                 print $fh "</td>\n";
623                         }
624                         
625                         my $title = $realname;
626                         if (!$title)
627                         {
628                                 $title = "User: $name; " if ($name);
629                                 $title .= "Ident: $ident";
630                         }
631                         print $fh qq#    <td class="nick" title="$title">#;
632
633                         if ($link)
634                         {
635                                 print $fh qq#<a href="$link">$name</a></td>\n#
636                         }
637                         else
638                         {
639                                 print $fh qq#$name</td>\n#;
640                         }
641                 
642                         if ($DISPLAY_LINES ne 'NONE')
643                         {
644                                 print $fh qq#    <td class="bar">#;
645                                 if (($DISPLAY_LINES eq 'BOTH') or ($DISPLAY_LINES eq 'BAR'))
646                                 {
647                                         my $code = bar ($max_lines, $NickData->{$nick}{'lines'});
648                                         print $fh $code;
649                                 }
650                                 print $fh '&nbsp;' if ($DISPLAY_LINES eq 'BOTH');
651                                 if (($DISPLAY_LINES eq 'BOTH') or ($DISPLAY_LINES eq 'NUMBER'))
652                                 {
653                                         print $fh $NickData->{$nick}{'lines_total'};
654                                 }
655                                 print $fh "</td>\n";
656                         }
657
658                         if ($DISPLAY_WORDS ne 'NONE')
659                         {
660                                 print $fh qq#    <td class="bar">#;
661                                 if (($DISPLAY_WORDS eq 'BOTH') or ($DISPLAY_WORDS eq 'BAR'))
662                                 {
663                                         my $code = bar ($max_words, $NickData->{$nick}{'words'});
664                                         print $fh $code;
665                                 }
666                                 print $fh '&nbsp;' if ($DISPLAY_WORDS eq 'BOTH');
667                                 if (($DISPLAY_WORDS eq 'BOTH') or ($DISPLAY_WORDS eq 'NUMBER'))
668                                 {
669                                         print $fh $NickData->{$nick}{'words_total'};
670                                 }
671                                 print $fh "</td>\n";
672                         }
673
674                         if ($DISPLAY_CHARS ne 'NONE')
675                         {
676                                 print $fh qq#    <td class="bar">#;
677                                 if (($DISPLAY_CHARS eq 'BOTH') or ($DISPLAY_CHARS eq 'BAR'))
678                                 {
679                                         my $code = bar ($max_chars, $NickData->{$nick}{'chars'});
680                                         print $fh $code;
681                                 }
682                                 print $fh '&nbsp;' if ($DISPLAY_CHARS eq 'BOTH');
683                                 if (($DISPLAY_CHARS eq 'BOTH') or ($DISPLAY_CHARS eq 'NUMBER'))
684                                 {
685                                         print $fh $NickData->{$nick}{'chars_total'};
686                                 }
687                                 print $fh "</td>\n";
688                         }
689
690                         if ($DISPLAY_TIMES)
691                         {
692                                 my $code = bar ($NickData->{$nick}{'chars_total'}, $NickData->{$nick}{'chars'});
693                                 print $fh qq#    <td class="bar">$code</td>\n#;
694                         }
695
696                         print $fh qq#    <td class="quote">$quote</td>\n#,
697                         qq#  </tr>\n#;
698                         
699                         if ($linescount == $LongLines)
700                         {
701                                 print $fh "</table>\n\n";
702                         }
703                 }
704
705                 # Ok, we have too many people to
706                 # list them all so we start a
707                 # smaller table and just list the
708                 # names.. (Six names per line..)
709                 elsif ($linescount <= ($LongLines + 6 * $ShortLines))
710                 {
711                         my $row_in_this_table = int (($linescount - $LongLines - 1) / 6);
712                         my $col_in_this_table = ($linescount - $LongLines - 1) % 6;
713
714                         my $total = 0;
715                         if ($SORT_BY eq 'LINES')
716                         {
717                                 $total = $NickData->{$nick}{'lines_total'};
718                         }
719                         elsif ($SORT_BY eq 'WORDS')
720                         {
721                                 $total = $NickData->{$nick}{'words_total'};
722                         }
723                         else # ($SORT_BY eq 'CHARS')
724                         {
725                                 $total = $NickData->{$nick}{'chars_total'};
726                         }
727
728                         my $title = $name ? get_realname ($name) : '';
729                         if (!$title)
730                         {
731                                 $title = "User: $name; " if ($name);
732                                 $title .= "Ident: $ident";
733                         }
734                         
735                         if ($row_in_this_table == 0 and $col_in_this_table == 0)
736                         {
737                                 $trans = translate ("They didn't write so much");
738                                 print $fh "<h2>$trans</h2>\n",
739                                 qq#<table class="small_ranking">\n#,
740                                 qq#  <tr>\n#;
741                         }
742                         
743                         if ($col_in_this_table == 0 and $row_in_this_table != 0)
744                         {
745                                 print $fh "  </tr>\n",
746                                 qq#  <tr>\n#;
747                         }
748                         
749                         print $fh qq#    <td title="$title">$name ($total)</td>\n#;
750                         
751                         if ($row_in_this_table == $ShortLines and $col_in_this_table == 5)
752                         {
753                                 print $fh "  </tr>\n",
754                                 qq#</table>\n\n#;
755                         }
756                 }
757
758                 # There is no else. There are
759                 # just too many people around.
760                 # I might add a "There are xyz
761                 # unmentioned nicks"-line..
762         }
763
764         if (($linescount > $LongLines)
765                         and ($linescount <= ($LongLines + 6 * $ShortLines)))
766         {
767                 my $col = ($linescount - $LongLines - 1) % 6;
768
769                 while ($col < 5)
770                 {
771                         print $fh qq#    <td>&nbsp;</td>\n#;
772                         $col++;
773                 }
774
775                 print $fh "  </tr>\n";
776         }
777
778         if ($linescount != $LongLines)
779         {
780                 print $fh "</table>\n\n";
781         }
782 }
783
784 # this is called by "&ranking ();" and prints the horizontal usage-bar in the
785 # detailed nick-table
786 sub bar
787 {
788         my $max_num = shift;
789
790         my $source = shift;
791
792         confess unless (ref ($source eq 'ARRAY'));
793
794         # BAR_WIDTH is a least 10
795         my $max_width = $BAR_WIDTH - 4;
796         my $factor = 1;
797         my $retval = '';
798
799         my $i;
800         my $j;
801
802         if (!$max_num) { return ($retval); }
803         $factor = $max_width / $max_num;
804
805         for ($i = 0; $i < 4; $i++)
806         {
807                 my $sum = 0;
808                 my $width = 1;
809                 my $img = $H_IMAGES[$i];
810
811                 for ($j = 0; $j < 6; $j++)
812                 {
813                         my $hour = ($i * 6) + $j;
814                         $sum += $source->[$hour];
815                 }
816
817                 $width += int (0.5 + ($sum * $factor));
818                 
819                 $retval .= qq#<img src="$img" style="width: # . $width . q#px"#;
820                 if ($i == 0) { $retval .= qq# class="first"#; }
821                 elsif ($i == 3) { $retval .= qq# class="last"#; }
822                 $retval .= ' alt="" />';
823         }
824
825         return ($retval);
826 }
827
828 =head1 EXPORTED FUNCTIONS
829
830 =over 4
831
832 =item B<get_core_nick_counters> (I<$nick>)
833
834 Returns the total I<lines>, I<words> and I<characters> written by the given
835 nick.
836
837 =cut
838
839 sub get_core_nick_counters
840 {
841         my $nick = shift;
842
843         if (defined ($NickData->{$nick}))
844         {
845                 return ($NickData->{$nick}{'lines_total'},
846                         $NickData->{$nick}{'words_total'},
847                         $NickData->{$nick}{'chars_total'});
848         }
849
850         return (qw());
851 }
852
853 =back
854
855 =head1 AUTHOR
856
857 Florian octo Forster, E<lt>octo at verplant.orgE<gt>
858
859 =cut