=encoding utf8

=head1 NAME

POE::Component::IRC::Cookbook::Seen - Implement the 'seen' command

=head1 SYNOPSIS

This little bot tracks the whereabouts of users and allows you to retrieve
that information on command.

 19:59:51 * seen_bot (n=hinrik@pool-71-164-43-32.chrlwv.east.verizon.net) has joined #test_channel1
 19:59:55 <foo> bar
 20:00:16 * seen_bot has quit (Remote closed the connection)
 20:00:27 * seen_bot (n=hinrik@pool-71-164-43-32.chrlwv.east.verizon.net) has joined #test_channel1
 20:00:29 <literal> seen_bot: seen seen_bot
 20:00:29 <seen_bot> literal: I last saw seen_bot at Mon Sep 22 20:00:27 2008 joining #test_channel1
 20:00:34 <literal> seen_bot: seen foo
 20:00:40 <seen_bot> literal: I last saw foo at Mon Sep 22 19:59:56 2008 on #test_channel1 saying: bar
 20:00:45 <literal> seen_bot: seen baz
 20:00:48 <seen_bot> literal: I haven't seen baz

=head1 DESCRIPTION

 #!/usr/bin/env perl

 use strict;
 use warnings;
 use IRC::Utils qw(parse_user lc_irc);
 use POE;
 use POE::Component::IRC::State;
 use POE::Component::IRC::Plugin::AutoJoin;
 use POE::Component::IRC::Plugin::BotCommand;
 use Storable;

 use constant {
     USER_DATE     => 0,
     USER_MSG      => 1,
     DATA_FILE     => 'seen',
     SAVE_INTERVAL => 20 * 60,   # save state every 20 mins
 };

 my $seen = { };
 $seen = retrieve(DATA_FILE) if -s DATA_FILE;

 POE::Session->create(
     package_states => [
         main => [ qw(
             _start
             irc_botcmd_seen
             irc_ctcp_action
             irc_join
             irc_part
             irc_public
             irc_quit
             save
         )]
     ],
 );

 $poe_kernel->run();

 sub _start {
     my ($kernel, $heap) = @_[KERNEL, HEAP];
     my $irc = POE::Component::IRC::State->spawn(
         Nick   => 'seen_bot',
         Server => 'irc.freenode.net',
     );
     $heap->{irc} = $irc;

     $irc->plugin_add('AutoJoin', POE::Component::IRC::Plugin::AutoJoin->new(
         Channels => [ '#test_channel1', '#test_channel2' ]
     ));

     $irc->plugin_add('BotCommand', POE::Component::IRC::Plugin::BotCommand->new(
         Commands => {
            seen => 'Usage: seen <nick>'
         }
     ));

     $irc->yield(register => qw(ctcp_action join part public quit botcmd_seen));
     $irc->yield('connect');
     $kernel->delay_set('save', SAVE_INTERVAL);
     return;
 }

 sub save {
     my $kernel = $_[KERNEL];
     warn "storing\n";
     store($seen, DATA_FILE) or die "Can't save state";
     $kernel->delay_set('save', SAVE_INTERVAL);
 }

 sub irc_ctcp_action {
     my $nick = parse_user($_[ARG0]);
     my $chan = $_[ARG1]->[0];
     my $text = $_[ARG2];

     add_nick($nick, "on $chan doing: * $nick $text");
 }

 sub irc_join {
     my $nick = parse_user($_[ARG0]);
     my $chan = $_[ARG1];

     add_nick($nick, "joining $chan");
 }

 sub irc_part {
     my $nick = parse_user($_[ARG0]);
     my $chan = $_[ARG1];
     my $text = $_[ARG2];

     my $msg = 'parting $chan';
     $msg .= " with message '$text'" if defined $text;

     add_nick($nick, $msg);
 }

 sub irc_public {
     my $nick = parse_user($_[ARG0]);
     my $chan = $_[ARG1]->[0];
     my $text = $_[ARG2];

     add_nick($nick, "on $chan saying: $text");
 }

 sub irc_quit {
     my $nick = parse_user($_[ARG0]);
     my $text = $_[ARG1];

     my $msg = 'quitting';
     $msg .= " with message '$text'" if defined $text;

     add_nick($nick, $msg);
 }

 sub add_nick {
     my ($nick, $msg) = @_;
     $seen->{lc_irc($nick)} = [time, $msg];
 }

 sub irc_botcmd_seen {
     my ($heap, $nick, $channel, $target) = @_[HEAP, ARG0..$#_];
     $nick = parse_user($nick);
     my $irc = $heap->{irc};

     if ($seen->{lc_irc($target)}) {
         my $date = localtime $seen->{lc_irc($target)}->[USER_DATE];
         my $msg = $seen->{lc_irc($target)}->[USER_MSG];
         $irc->yield(privmsg => $channel, "$nick: I last saw $target at $date $msg");
     }
     else {
         $irc->yield(privmsg => $channel, "$nick: I haven't seen $target");
     }
 }

=head1 AUTHOR

Hinrik E<Ouml>rn SigurE<eth>sson, hinrik.sig@gmail.com

