#!/usr/bin/perl

# Heavily hacked from a script originally provided by Mark Smith, this 
# is a bot which will keep track of menow information. It's not very
# sophisticated yet, but it does do what I want it to. Next step is
# to write a similar bot for AIM.

# Requires database table menow:
#| nick      | varchar(30)  | YES  |     | NULL    |       |
#| type      | varchar(100) | YES  |     | NULL    |       |
#| object    | text         | YES  |     | NULL    |       |
#| timestamp | datetime     | YES  |     | NULL    |       |

# Contact Christopher Schmidt, crschmid@uiuc.edu, for more info

# uses
use Net::IRC;
use DBI;

$dbh;
# setup
my $server = "irc.freenode.net";
my $port = "6667";
$globalnick = "menow";
my $nick = $globalnick;
my $chan = '#pa';
my $name = 'Menow Bot';
my $version = "0.2";

# variables
my $dbh;
# connect to IRC
my $irc = new Net::IRC;
my $conn = $irc->newconn(Nick => $nick, Server => $server, Port => $port, Ircname => $name);

sub get_db_handle {
   $dsn = "DBI:mysql:test;localhost";
   $dbh = DBI->connect($dsn, 'root', 'rand0m');
   die "error: no database" unless $dbh;
}

# setup event handlers
$conn->add_global_handler('376', \&on_connect);
$conn->add_global_handler('msg', \&on_msg);
$conn->add_global_handler('public', \&on_chan);

# do it!
$irc->start();

################################
sub on_connect {
  my $self = shift;

  # join a channel, etc
  $self->join($chan);
  get_db_handle();
}

################################
sub on_msg {
  # handle private message command
  my ($self, $event) = @_;
  on_chan($self, $event);
}

sub on_chan {
  # handle private message command
  if (!$dbh) { get_db_handle(); }
  my ($self, $event) = @_;
  my $text = ($event->args())[0];
  my $nick = $event->nick();
  my $res;
  my $lctext = lc($text);
  if ($lctext =~ m/$\$globalnick,/) {
      if ($text =~ m/foaf\s+(.*?)$/) {
          $res = foaf_add($1, $nick);
      }
      elsif ($text =~ m/add\s+(.*?)\s+(.*?)$/) {
          $res = pred_add($nick, $text, $1, $2);
      }
      elsif ($text =~ m/forget\s+(.*?)$/) {
          $res = forget_routine($nick, $1);
      }
      elsif ($text =~ m/(.*?),\s*(.*?)\s+now\?*$/) {
          $res = other_menow($2);
      }
      elsif ($text =~ m/(.*?),\s*(.*?)\s+now\s+human\?*$/) {
          $res = other_human_menow($2);
      }
      elsif ($lctext =~ m/menow human/) {
          $res = self_human_menow($nick);
      }
      elsif ($lctext =~ m/(.*?),\s*menow\?*$/) {
          $res = self_menow($nick);
      }
      elsif ($text =~ m/alias (.*?)$/) {
          $res = alias($nick, $1);
      }
      elsif ($lctext =~ m/recent/) {
          if ($lctext =~ m/user/) {
             $res = recent_users();
          }
          else {
             $res = recent_pred();
          }
      }
      elsif ($lctext =~ m/help/) {
          $res = help_routine();
      }
      else {
          else_routine($nick, $self);
      }

  }
  $self->privmsg($chan, $res) if $res;

}

###################################

sub pred_add {
    my $ret;
my %properties = ("iswith" => 1,  "listeningto" => 1,  "located" => 1,  "game" => 1,  "gamingat" => 1,  "gamenick" => 1,  "thinking" => 1,  "mood" => 1,  "moodicon" => 1,  "liking" => 1,  "chatting" => 1,  "browsing" => 1,  "reading" => 1,  "vacation" => 1,  "moblogging" => 1,  "moImage" => 1,  "camimage" => 1,  "status" => 1,  "statusicon" => 1,  "workingOn" => 1,  "writing" => 1,  "planning" => 1,  "watching" => 1);
    my ($nick, $text, $predicate, $object) = @_;
    forget_routine($nick, $predicate);
    $nick = $dbh->quote($nick);
    my $type = $dbh->quote($predicate);
    return "$predicate not part of the MeNow Schema, see http://schema.peoplesdns.com/menow/." unless $properties{lc($predicate)}; 
    $object = $dbh->quote($object);
    $dbh->do("INSERT INTO menow (nick, type, object, timestamp) VALUES ($nick, $type, $object, NOW())");
    print "$nick added $object as $type\n";
    return $ret;
    
}

sub forget_routine {
    my ($nick, $predicate) = @_;
    my $type = $dbh->quote($predicate);
    my $nick = $dbh->quote($nick);
    $dbh->do("DELETE FROM menow WHERE type=$type AND nick = $nick");
    my $sth = $dbh->prepare("SELECT alias from aliases WHERE nick = $nick");
    $sth->execute();
    while (($alias) = $sth->fetchrow_array()) {
       $alias = $dbh->quote($alias);
       $dbh->do("DELETE FROM menow WHERE type=$type AND nick = $alias");
    }
           
    print "$nick dropped $type\n";
    return;
}

sub help_routine {
    return "I understand the following commands: add <predicate> " . 
        "<object>, forget <predicate>, menow, <nick> now. <nick> is either an " .
        "IRC nickname or an AIM ID. Predicates can be chosen from the MeNow " .
        "schema at http://schema.peoplesdns.com/menow/.";
}
sub else_routine {
    my ($nick, $self) = @_;
    my $msg = "Hi $nick. I'm a bot which stores 'now' information according " . 
        "to the MeNow Schema. This is version $version . Information about " .
        "this bot is available at " .
        "http://crschmidt.net/wordpress/archives/2004/06/01/metadata-the-quick-and-easy-way/ " .
        ". You can contact me at cr5chmidt on AIM or crschmidt on irc.freenode.net if you're " .
        "interested in contributing. For commands, type 'help'.";
    $self->privmsg($nick, $msg);
    return;
    
}
sub self_human_menow {
my %english = ("iswith" => "is with",  "listeningto" => " is listening to",  "located" => "is located in or at",  "game" => "is playing",  "gamingat" => "is playing on the server at",  "gamenick" => "is playing as",  "thinking" => "is thinking about",  "mood" => "is feeling",  "moodicon" => "has a mood which looks like",  "liking" => "likes",  "chatting" => "is chatting on",  "browsing" => "is browsing",  "reading" => "is reading",  "vacation" => "is on vaccation at",  "moblogging" => "is moblogging",  "moImage" => "has a most recent mobile image at",  "camimage" => "has a webcam image of",  "status" => "has a status of",  "statusicon" => "has a status icon of",  "workingOn" => "is working on",  "writing" => "is writing",  "planning" => "is planning on",  "watching" => "is watching");
    my $res;
    my $nick = shift;
    my $quotednick = $dbh->quote($nick);
    my $sth = $dbh->prepare("SELECT DISTINCT m.type, m.object, m.timestamp FROM menow m, aliases a WHERE m.nick=$quotednick OR (a.alias = m.nick AND a.nick = $quotednick) ORDER BY timestamp DESC");
    $sth->execute();
    while (($type, $object, $timestamp) = $sth->fetchrow_array()) {
        $res .= $english{lc($type)} . " $object at $timestamp and ";
    }
    $res = "$nick ".$res;
    print "$nick menow printed\n";
    return substr($res, 0, length($res) - 5);
    
}
sub self_menow {
    my $res;
    my $nick = shift;
    my $quotednick = $dbh->quote($nick);
    my $sth = $dbh->prepare("SELECT DISTINCT m.type, m.object, m.timestamp FROM menow m, aliases a WHERE m.nick=$quotednick OR (a.alias = m.nick AND a.nick = $quotednick) ORDER BY timestamp DESC");
    $sth->execute();
    while (($type, $object, $timestamp) = $sth->fetchrow_array()) {
        $res .= "menow:$type = $object at $timestamp  ";
    }
    $res = "$nick : ".$res;
    print "$nick menow printed\n";
    return $res;
    
}
sub other_human_menow {
my %english = ("iswith" => "is with",  "listeningto" => " is listening to",  "located" => "is located in or at",  "game" => "is playing",  "gamingat" => "is playing on the server at",  "gamenick" => "is playing as",  "thinking" => "is thinking about",  "mood" => "is feeling",  "moodicon" => "has a mood which looks like",  "liking" => "likes",  "chatting" => "is chatting on",  "browsing" => "is browsing",  "reading" => "is reading",  "vacation" => "is on vaccation at",  "moblogging" => "is moblogging",  "moImage" => "has a most recent mobile image at",  "camimage" => "has a webcam image of",  "status" => "has a status of",  "statusicon" => "has a status icon of",  "workingOn" => "is working on",  "writing" => "is writing",  "planning" => "is planning on",  "watching" => "is watching");
    my $res;
    my $othernick = shift;
    my $quotednick = $dbh->quote($othernick);
    my $sth = $dbh->prepare("SELECT DISTINCT m.type, m.object, m.timestamp FROM menow m, aliases a WHERE m.nick=$quotednick OR (a.alias = m.nick AND a.nick = $quotednick) ORDER BY timestamp DESC");
    $sth->execute();
    while (($type, $object, $timestamp) = $sth->fetchrow_array()) {
        $res .= $english{lc($type)} . " $object at $timestamp and ";
    }
    $res = "$othernick ".$res;
    print "$othernick menow printed\n";
    return substr($res, 0, length($res) - 5);
}
sub other_menow {
    my $res;
    my $othernick = shift;
    my $quotednick = $dbh->quote($othernick);
    my $sth = $dbh->prepare("SELECT DISTINCT m.type, m.object, m.timestamp FROM menow m, aliases a WHERE m.nick=$quotednick OR (a.alias = m.nick AND a.nick = $quotednick) ORDER BY timestamp DESC");
    $sth->execute();
    while (($type, $object, $timestamp) = $sth->fetchrow_array()) {
        $res .= "menow:$type = $object at $timestamp  ";
    }
    $res = "$othernick : ".$res;
    print "$othernick menow printed\n";
    return $res;
}
sub recent_users {
   my $res, $nick;
   my $sth = $dbh->prepare("SELECT DISTINCT nick FROM menow ORDER BY timestamp DESC LIMIT 5");
   $sth->execute();
   $res = "Recent participants: ";
   $res .= $nick.", " while ($nick = $sth->fetchrow_array());
   
   return substr($res, 0, length($res)-2);
}

sub recent_pred {
    my $res, $pred;
    my $sth = $dbh->prepare("SELECT DISTINCT type FROM menow ORDER BY timestamp DESC LIMIT 5");
    $sth->execute();
    $res = "Recent predicates: ";
    $res .= $pred.", " while ($pred = $sth->fetchrow_array());

    return substr($res, 0, length($res)-2);

}
sub foaf_add {
    my ($url, $nick) = @_;
    $dbh->do("INSERT INTO menow_foaf (nick, foaf) VALUES ('$nick', '$url')");
        return;
    }
sub alias {
    my $res;
    my ($nick, $alias) = @_;
    my $quotedalias = $dbh->quote($alias);
    my $quotednick = $dbh->quote($nick);
    $dbh->do("INSERT INTO aliases (nick, alias, timestamp) VALUES ($quotednick, $quotedalias, NOW())");
    $res = "Aliased $nick to $alias - results for either will be shared on a \"menow\" command.";
    return $res;
    
}
