#!/usr/bin/perl

use CGI qw(:standard);
use CGI::Carp qw/fatalsToBrowser/;
use Mysql;

# Parameters
# action: Search or Display.  Search shows list of hits.  Display shows a single entry in context
#   Search Parameters
# start: find matches later than this datetime
# end: find matches earlier than this datetime
# person: list of people to match
# room: list of rooms to match
# forcedby: list of forcedby to match
# command: pattern to match in command
# exact: if no, wrap command in %
# count: if yes, display only a total count.
# page: which results page to show
# pagelength: how many results per page?
# context: how many lines before and after the matching line?
#   Display Parameters
# time: datetime to start display
# room: room to display
# private: yes to include pages and whispers
# length: number of commands to show

my $dbuser = 'dbuser';
my $dbpasswd = 'dbpasswd';

my $dbh = Mysql->connect(undef, 'mucklog', $dbuser, $dbpasswd);

my $pattern = shift;
my %rooms;
my %people;
my @me;
my $wizard;

&load_people;
&load_rooms;

my $action = param('action');

my $output =
"<html>\n".
" <body>\n".
&header;
if($action eq "Search")
{
  $output .= &search;
}
elsif($action eq "View")
{
  $output .= &view;
}
$output .=
" </body>\n".
"</html>\n";

print
"Content-type: text/html\n\n".
$output;

exit;

sub view
{
  my $view;
  my $query = "select * from COMMANDS where ";
  my $start = param('start');
  my $end = param('end');
  my $person = param('person');
  my $room = param('room');
  my $nofilter;
  if($wizard && param('nofilter')){$nofilter = 1;}
  if($start){ $query .= "TIME >= '$start' and "; }
  if($end){ $query .= "TIME <= '$end' and "; }
  if($person){ $query .= "PERSON = '$person' and "; }
  if($room){ $query .= "ROOM = '$room' and "; }
  $query =~ s/ and $/ order by TIME;/;
  my $results = $dbh->query($query) or die $dbh->errmsg.": $query";
  my @hits = &filter($results, 1000, $nofilter);
  grep
  {
    $view .= "$$_{'TIME'} $people{$$_{'PERSON'}} in $rooms{$$_{'ROOM'}}: $$_{'COMMAND'}<br/>\n";
  } @hits;
  return $view;
}

sub search
{
  my $search;
  my $query = "select * from COMMANDS where ";
  my $start = param('start');
  my $end = param('end');
  my $person = param('person');
  my $room = param('room');
  my $nofilter;
  if($wizard && param('nofilter')){$nofilter = 1;}
  if($start){ $query .= "TIME >= '$start' and "; }
  if($end){ $query .= "TIME <= '$end' and "; }
  if($person){ $query .= "PERSON = '$person' and "; }
  if($room){ $query .= "ROOM = '$room' and "; }
  $query .= "COMMAND like '%".param('command')."%'";
  $query = $dbh->query("$query order by TIME;");
  my @hits = &filter($query, 100, $nofilter);
  $search .= (($page*100)+1)."-".@hits." of ".$query->numrows." matching commands. ";
  $search .= "<table border='1'>\n";

  grep
  {
    my $cmd = $_;
    my @hit;
    #push @hit, $_;
    my $query = $dbh->query("select * from COMMANDS where ROOM = '$$_{'ROOM'}' and TIME < '$$_{'TIME'}' order by TIME desc limit 6;");
    my @context = &filter($query, 3, $nofilter);
    grep
    {
      unshift @hit, $_;
    } @context;
    $query = $dbh->query("select * from COMMANDS where ROOM = '$$_{'ROOM'}' and TIME >= '$$_{'TIME'}' order by TIME limit 7;");
    @context = &filter($query, 4, $nofilter);
    grep
    {
      push @hit, $_;
    } @context;
    $search .= "<tr><td>";
    my $contextstart;
    my $contextend;
    grep
    {
      if(!$contextstart){ $contextstart = $$_{'TIME'}; }
      $contextend = $$_{'TIME'};
      if(($$_{'PERSON'} eq $$cmd{'PERSON'}) && ($$_{'COMMAND'} eq $$cmd{'COMMAND'})){$search .= "<font color='blue'>";}
      $search .= "$$_{'TIME'} $people{$$_{'PERSON'}} in $rooms{$$_{'ROOM'}}: $$_{'COMMAND'}<br/>\n";
      if(($$_{'PERSON'} eq $$cmd{'PERSON'}) && ($$_{'COMMAND'} eq $$cmd{'COMMAND'})){$search .= "</font>";}
    } @hit;
    $contextstart = $dbh->query("select FROM_UNIXTIME(UNIX_TIMESTAMP('$contextstart') - (2 * (UNIX_TIMESTAMP('$contextend') - UNIX_TIMESTAMP('$contextstart'))));")->fetchrow;
    $contextend = $dbh->query("select FROM_UNIXTIME(UNIX_TIMESTAMP('$contextend') + (2 * (UNIX_TIMESTAMP('$contextend') - UNIX_TIMESTAMP('$contextstart'))));")->fetchrow;
    $search .= "<a href='?action=View&start=$contextstart&end=$contextend&person=$person&room=$room&nofilter=$nofilter'>Read More</a>";
    $search .= "</td></tr>\n";
  } @hits;
  $search .= "</table>\n".
  return $search;
}

sub header
{
  my $header =
  "  <form method='post'>\n".
  "   <table>\n".
  "    <tr><td>From:</td><td>".&datepicker('start')."</td></tr>\n".
  "    <tr><td>To:</td><td>".&datepicker('end')."<br />\n".
  "    <tr><td>Player:</td>\n".
  "    <td><select name='person' size='5'>\n".
  "    <option value='' selected='yes'>ANY</option>\n";
  grep
  {
    $header .= "     <option value='$_'>$people{$_}</option>\n";
  } sort{lc($people{$a}) cmp lc($people{$b})} keys(%people);
  $header .=
  "   </select></td></tr>\n".
  "    <tr><td>Room:</td>\n".
  "    <td><select name='room' size='5'>\n".
  "    <option value='' selected='yes'>ANY</option>\n";
  grep
  {
    $header .= "     <option value='$_'>$rooms{$_}</option>\n";
  } sort{lc($rooms{$a}) cmp lc($rooms{$b})} keys(%rooms);
  $header .=
  "   </select></td></tr>\n".
  "   <tr><td>Pattern:</td><td><input name='command' type='text' size='40'/></td></tr>\n";

  $header .=
  "    <tr><td></td><td><input type='submit' name='action' value='Search'/></td></tr>\n";
  if($wizard)
  {
    $header .=
    "    <tr><td>Do not filter:</td><td><input type='checkbox' name='nofilter'/></td></tr>\n";
  }
  $header .=
  "   </table>\n".
  "  </form>\n";
  return $header;
}

# start: find matches later than this datetime
# end: find matches earlier than this datetime
# person: list of people to match
# room: list of rooms to match
# forcedby: list of forcedby to match
# command: pattern to match in command
# exact: if no, wrap command in %
# count: if yes, display only a total count.
# page: which results page to show
# pagelength: how many results per page?
# context: how many lines before and after the matching line?

sub datepicker
{
  my $name = shift;
  return "<input type='text' name='$name'/> $name date, format: yyyy-mm-dd hh:mm:ss";
}

sub filter
{
  my $query = shift;
  my $max = shift;
  my $nofilter = shift;
  my $count = 0;
  my @results;
  while(my %line = $query->fetchhash)
  {
    my $allowed = 0;
    if($nofilter)
    { $allowed = 1; }
    elsif(grep($_ eq $line{'PERSON'}, @me) || grep($_ eq $line{'FORCEDBY'}, @me)) 
    { $allowed = 1; }
    elsif($line{'COMMAND'} =~ /^(wh|whisper|p|page) ([^=]*)\s*=/i)
    {
      my $target = $2;
      while(my ($key, $value) = each %people)
      {
        if(lc($target) eq lc($value) && grep($_ eq $key, @me))
        { $allowed = 1; }
      }
    }
    elsif($line{'COMMAND'} =~ /^(:|;|pose\s|ponder\s|"|'|say\s|ask\s|yell\s|spoof\s|sp\s|spf\s|mean\s|na$|act$|afk$)/i)
    {
      if(&connected($line{'TIME'}, $line{'ROOM'})){ $allowed = 1; }
    }

    if($allowed)
    {
      push @results, \%line;
      $count++;
      if($count >= $max){ return @results; }
    }
  }
  return @results;
}

sub connected
{
  my $time = shift;
  my $room = shift;

  my $person = "";
  grep
  {
    $person .= " or PERSON = '$_'";
  } @me;
  $person =~ s/^ or //;
  $forcedby = $person;
  $forcedby =~ s/PERSON/FORCEDBY/g;

  my $query = $dbh->query("select * from COMMANDS where ($person or $forcedby) and TIME >= '$time' limit 1;");
  my %line = $query->fetchhash;
  my $next = $line{'TIME'};
  my $nextc = $line{'COMMAND'};
  if($line{'ROOM'} eq $room)
  {
    my @sockets;
    my $query = $dbh->query("select * from CONNECTS where ($person) and EVENT = 'CONN' and TIME >= '$time' - interval 72 hour and TIME < '$time' order by TIME;");
    while(my %line = $query->fetchhash)
    {
      $sockets[$line{'SOCKET'}] = {'CONN'=>$line{'TIME'}, 'DISC'=>""};
    }
    $query = $dbh->query("select * from CONNECTS where ($person) and EVENT = 'DISC' and TIME >= '$time' and TIME < '$time' + interval 72 hour order by TIME desc;");
    while(my %line = $query->fetchhash)
    {
      $sockets[$line{'SOCKET'}]{'DISC'} = $line{'TIME'};
    }
    grep
    {
      if($_)
      {
        if($$_{'CONN'} && $$_{'DISC'})
        { return 1; }
      }
    } @sockets;
    if($nextc =~ /^act/)
    {
      my $query = $dbh->query("select * from COMMANDS where ($person or $forcedby) and TIME <= '$time' and TIME >= '$next' - interval 4 hour limit 1;");
      if($query->fetchhash){ return 1; }
    }
    else
    {
      my $query = $dbh->query("select * from COMMANDS where ($person or $forcedby) and TIME <= '$time' and TIME >= '$next' - interval 1 hour limit 1;");
      if($query->fetchhash){ return 1; }
    }
  }

  return 0;
}

sub load_people
{
  my $query = $dbh->query("select * from PEOPLE;");
  my $me = $ENV{'REMOTE_USER'};
  while(my %person = $query->fetchhash)
  {
    $people{$person{'DBREF'}} = $person{'NAME'};
    if(lc($person{'OWNER'}) eq lc($me))
    {
      push @me, $person{'DBREF'};
      if($person{'WIZARD'}){ $wizard = 1; }
    }
  }
}

sub load_rooms
{
  my $query = $dbh->query("select * from ROOMS;");
  while(my %room = $query->fetchhash)
  {
    $rooms{$room{'DBREF'}} = $room{'NAME'};
  }
}
