#!/usr/bin/perl -w
#extract lines in a given date range from an xchat logfile
#is a bit too hardcoded to be translated to other clients (gaim, etc)
#sorry! Future update will see this more modular.
use Getopt::Std;
use strict;

#extractDate(\%hash, $line)
#extract the contents of the date in line and put it in a hash
#(hash is keyed by month, day, hour, minute, second)
sub extractDate;
#buildRegex($line)
#build a regex from an input string of the form MM HH MM:SS:DD and return it
sub buildRegex;

my %args;
my $buffer;

#regexes for quick and easy pattern matching
my $startregex;
my $endregex;
#start and end date hashes for more complex range matching
my %startdate;
my %enddate;
# additional regex to check for in lines of output
my $addlRegex = ".*";

#Yeah this is a bit hackish. Whaddya want from me? This is, like, my second perl script.
my %monthvals = (
                 Jan => 0,
                 Feb => 1,
                 Mar => 2,
                 Apr => 3,
                 May => 4,
                 Jun => 5,
                 Jul => 6,
                 Aug => 7,
                 Sep => 8,
                 Oct => 9,
                 Nov => 10,
                 Dec => 11,
                 jan => 0,
                 feb => 1,
                 mar => 2,
                 apr => 3,
                 may => 4,
                 jun => 5,
                 jul => 6,
                 aug => 7,
                 sep => 8,
                 oct => 9,
                 nov => 10,
                 dec => 11,
                 );

my $help;

$help = <<EOT;
logger: filter X-Chat 2 log files by date
logger <options> inputfile
   -h : this help
   -s : Starting date 
   -e : Ending date 
   -r : Further restrict the search to lines matching this regex (search, not replace)
   
   inputfile defaults to stdin if no file provided

   Dates are expected in "Month Day Hour:Minute:Second" format. Months 
   are abbreviated to 3 letters, non-case sensitive. You must provide 
   AT LEAST one regex. (If one is missing, then it is assumed that both -s 
   and -e are equal.)

   To search for all lines on the 13th of May:
   logger -s "May 13 *:*:*" xchatlogfile

   To search for all lines between the 13th of May and the 20th of June:
   logger -s "May 13 *:*:*" -e "Jun 20 *:*:*" xchatlogfile

   To search for all lines written between 5 and 10 pm in the entire log:
   logger -s "* * 17:*:*" -e "* * 22:*:*" xchatlogfile

   As above, but only match lines containing "somenick"
   logger -s "* * 17:*:*" -e "* * 22:*:*" -r somenick xchatlogfile

EOT

getopt ( "hxs:e:f:r:", \%args );

# there's quite a bit of redundancy in the argument checking. Sue me.

if ( $args{h} ) {
	print $help;
	exit;
}
if ( $args{r} ) {
   $addlRegex = $args{r};
}
if ( $args{s} ) {
   $startregex = buildRegex($args{s});
   extractDate(\%startdate, $args{s});
}
if ( $args{e} ) {
   $endregex = buildRegex($args{e});
   extractDate(\%enddate, $args{e});
}

if ( !$args{e} && !$args{s} ) {
   print $help;
   exit;
}
elsif ( !$args{e} || !$args{s} ) {
   if ( $args{s} ) {
      $endregex = $startregex;
      extractDate(\%enddate, $args{s});
   }
   elsif ( $args{e} ) {
      $startregex = $endregex;
      extractDate(\%startdate, $args{e});
   }
}


while ( <> ) {
   my $toPrint;
   if ( $_ =~ m/^\*\*\*\*/i || $_ =~ m/^\s*\n/i ) {
      # this is a xchat log status line (effectively a comment for our purpose)
      next;
   }
   if ( $_ =~ m/$startregex/i ||
      $_ =~ m/$endregex/i ) {
      $toPrint = $_;
   }
   else {
      # not lucky enough for an exact match ... check the date
      my %linedate;
      extractDate(\%linedate, $_);
      # check the dates to see if the date in the line is between startdate
      # and end date
      if ( !($enddate{month} eq "*") &&
           $monthvals{$linedate{month}} <= $monthvals{$enddate{month}} &&
              $monthvals{$linedate{month}} >= $monthvals{$startdate{month}} ) {

         if ( !($enddate{day} eq "*") &&
              $linedate{day} <= $enddate{day} &&
              $linedate{day} >= $startdate{day} ) {
   
            if ( !($enddate{hour} eq "*") &&
                 $linedate{hour} <= $enddate{hour} &&
                 $linedate{hour} >= $startdate{hour} ) {
   
               if (!($enddate{minute} eq "*") &&
                  $linedate{minute} <= $enddate{minute} &&
                  $linedate{minute} >= $startdate{minute} ) {
   
                  if (!($enddate{second} eq "*") && 
                      $linedate{second} <= $enddate{second} &&
                      $linedate{second} >= $enddate{second} ) {
                     $toPrint = $_;
                  }
               }
            }
         }
      }
   }

   if ( $toPrint && ($toPrint =~ m/$addlRegex/) ) {
      print $toPrint;
   }
}

sub buildRegex {
   my $orig = shift;
   # make sure to not muck up the original
   my $regex = $orig;

   $regex =~ s/\s/\\s/g;
   $regex =~ s/\*/\.\*/g;
   
   return $regex;
}

sub extractDate {
   my $finalDate = shift; #expects a reference to a hash
   my $buff = shift; #expects a line of text from the logfile
                     #expects buff in the form MM DD HH:MM:SS
   my @date = split " ", $buff;
   my @time = split ":", $buff;

   $time[0] =~ s/$date[0]\s$date[1]\s//;

   $finalDate->{month} = $date[0];
   $finalDate->{day} = $date[1];
   $finalDate->{hour} = $time[0];
   $finalDate->{minute} = $time[1];

   my @splitline = split " ", $time[2];
   $finalDate->{second} = $splitline[0];
}
