797d39ceedb5837e73b3ee8954baf8ab4c346ba3
[onis.git] / lib / Onis / Plugins / Conversations.pm
1 package Onis::Plugins::Conversations;
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 nick_to_ident nick_to_name);
10 use Onis::Users (qw(ident_to_name));
11 use Onis::Data::Persistent;
12
13 our $ConversationCache = Onis::Data::Persistent->new ('ConversationCache', 'partners', qw(time0 time1 time2 time3));
14 our $ConversationData = {};
15
16 our @H_IMAGES = qw#dark-theme/h-red.png dark-theme/h-blue.png dark-theme/h-yellow.png dark-theme/h-green.png#;
17 our $BAR_WIDTH  = 100;
18
19 if (get_config ('horizontal_images'))
20 {
21         my @tmp = get_config ('horizontal_images');
22         my $i;
23         
24         if (scalar (@tmp) != 4)
25         {
26                 print STDERR $/, __FILE__, ": The number of horizontal images is not four. The output might look weird.", $/;
27         }
28
29         for ($i = 0; $i < 4; $i++)
30         {
31                 next unless (defined ($tmp[$i]));
32                 $H_IMAGES[$i] = $tmp[$i];
33         }
34 }
35 if (get_config ('bar_width'))
36 {
37         my $tmp = get_config ('bar_width');
38         $tmp =~ s/\D//g;
39         $BAR_WIDTH = 2 * $tmp if ($tmp >= 10);
40 }
41
42 register_plugin ('TEXT', \&add);
43 register_plugin ('OUTPUT', \&output);
44
45 my $VERSION = '$Id: Conversations.pm,v 1.7 2004/09/15 19:42:04 octo Exp $';
46 print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG);
47
48 return (1);
49
50 sub add
51 {
52         my $data = shift;
53         my $text = $data->{'text'};
54         my $nick = $data->{'nick'};
55         my $ident = $data->{'ident'};
56
57         my $time = int ($data->{'hour'} / 6);
58
59         # <taken from lib/Onis/Plugins/Nicks.pm>
60         my @potential_nicks = split (/[^\w\`\~\^\-\|\[\]]+/, $text);
61         my $talk_to = '';
62         
63         for (@potential_nicks)
64         {
65                 my $other_nick = $_;
66                 my $other_ident = nick_to_ident ($other_nick);
67                 
68                 if ($other_ident)
69                 {
70                         $talk_to = $other_nick;
71                         last;
72                 }
73         }
74         # </taken>
75         
76         if ($talk_to)
77         {
78                 my $key = "$nick:$talk_to";
79                 my @data = $ConversationCache->get ($key);
80                 @data = (0, 0, 0, 0) unless (@data);
81
82                 my $chars = length ($text);
83
84                 $data[$time] += $chars;
85                 
86                 $ConversationCache->put ($key, @data);
87         }
88 }
89
90 sub calculate
91 {
92         for ($ConversationCache->keys ())
93         {
94                 my $key = $_;
95                 my ($nick_from, $nick_to) = split (m/:/, $key);
96                 my @data = $ConversationCache->get ($key);
97
98                 $nick_from = get_main_nick ($nick_from);
99                 $nick_to   = get_main_nick ($nick_to);
100
101                 next if (!$nick_from or !$nick_to);
102                 next if ($nick_from eq $nick_to);
103
104                 if (!defined ($ConversationData->{$nick_from}{$nick_to}))
105                 {
106                         $ConversationData->{$nick_from}{$nick_to} =
107                         {
108                                 total => 0,
109                                 nicks =>
110                                 {
111                                         $nick_from => [0, 0, 0, 0],
112                                         $nick_to   => [0, 0, 0, 0]
113                                 }
114                         };
115                         $ConversationData->{$nick_to}{$nick_from} = $ConversationData->{$nick_from}{$nick_to};
116                 }
117
118                 for (my $i = 0; $i < 4; $i++)
119                 {
120                         $ConversationData->{$nick_from}{$nick_to}{'nicks'}{$nick_from}[$i] += $data[$i];
121                         $ConversationData->{$nick_from}{$nick_to}{'total'} += $data[$i];
122                 }
123         }
124 }
125
126 sub get_top
127 {
128         my $num = shift;
129         my @data = ();
130
131         for (keys %$ConversationData)
132         {
133                 my $nick0 = $_;
134
135                 for (keys %{$ConversationData->{$nick0}})
136                 {
137                         my $nick1 = $_;
138                         next unless ($nick0 lt $nick1);
139
140                         push (@data, [$ConversationData->{$nick0}{$nick1}{'total'}, $nick0, $nick1]);
141                 }
142         }
143
144         @data = sort { $b->[0] <=> $a->[0] } (@data);
145         splice (@data, $num) if (scalar (@data) > $num);
146
147         return (@data);
148 }
149
150 sub output
151 {
152         calculate ();
153
154         my $fh = get_filehandle ();
155         my $title = translate ('Conversation partners');
156
157         my $max_num = 0;
158         my $factor = 0;
159
160         my @img = get_config ('horizontal_images');
161
162         # FIXME
163         my @data = get_top (10);
164         return (undef) unless (@data);
165
166         for (@data)
167         {
168                 my $nick0 = $_->[1];
169                 my $nick1 = $_->[2];
170                 my $rec = $ConversationData->{$nick0}{$nick1};
171
172                 my $sum0 = 0;
173                 my $sum1 = 0;
174
175                 for (my $i = 0; $i < 4; $i++)
176                 {
177                         $sum0 += $rec->{'nicks'}{$nick0}[$i];
178                         $sum1 += $rec->{'nicks'}{$nick1}[$i];
179                 }
180
181                 $max_num = $sum0 if ($max_num < $sum0);
182                 $max_num = $sum1 if ($max_num < $sum1);
183         }
184         
185         $factor = $BAR_WIDTH / $max_num;
186
187         print $fh <<EOF;
188 <table class="plugin conversations">
189   <tr>
190     <th colspan="2">$title</th>
191   </tr>
192 EOF
193         foreach (@data)
194         {
195                 my $nick0 = $_->[1];
196                 my $nick1 = $_->[2];
197                 my $name0 = nick_to_name ($nick0) || $nick0;
198                 my $name1 = nick_to_name ($nick1) || $nick1;
199                 my $rec = $ConversationData->{$nick0}{$nick1};
200
201                 print $fh <<EOF;
202   <tr>
203     <td class="nick left">$name0</td>
204     <td class="nick right">$name1</td>
205   </tr>
206   <tr>
207 EOF
208
209                 print $fh '    <td class="bar left">';
210                 for (3, 2, 1, 0)
211                 {
212                         my $i = $img[$_];
213                         my $w = int (0.5 + ($rec->{'users'}{$nick0}[$_] * $factor));
214                         my $c = '';
215                         $w ||= 1;
216
217                         $w = $w . 'px';
218
219                         if    ($_ == 3) { $c = qq# class="first"#; }
220                         elsif ($_ == 0) { $c = qq# class="last"#;  }
221
222                         print $fh qq#<img src="$i" style="width: $w;"$c alt="" />#;
223                 }
224
225                 print $fh qq#</td>\n    <td class="bar right">#;
226
227                 for (0, 1, 2, 3)
228                 {
229                         my $i = $img[$_];
230                         my $w = int (0.5 + ($rec->{'users'}{$nick1}[$_] * $factor));
231                         my $c = '';
232                         $w ||= 1;
233
234                         $w = $w . 'px';
235
236                         if    ($_ == 0) { $c = qq# class="first"#; }
237                         elsif ($_ == 3) { $c = qq# class="last"#;  }
238
239                         print $fh qq#<img src="$i" style="width: $w;"$c alt=""/>#;
240                 }
241                 print $fh "</td>\n  </tr>\n";
242         }
243
244         print $fh "</table>\n\n";
245 }
246
247 sub get_conversations
248 {
249         my $nick = shift;
250
251         if (!defined ($ConversationData->{$nick}))
252         {
253                 return ({});
254         }
255         else
256         {
257                 return ($ConversationData->{$nick});
258         }
259 }