#!/usr/bin/perl 

# patpat.pl - tool to apply patterns to patent documents.
# Dennis Moul 3/24/13
# Copyright (C) 2013 All Rights Reserved
#
# v1.1 - work around limitation in mac perl 5.12; doesn't have /r operator.

use strict;
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser;
use LWP::Simple;
use URI;
use File::Copy;

# These are the variables you might want to adjust for your own preference.
my $cachedir = "/cygdrive/d/temp/cache";
my $maxMatches = 30;

if ($#ARGV != 2) {   #note argument count starts at 0
print <<END;

ERROR: Invalid paramter count.

usage: $0 PatternFile InputFile OutputFile

Takes an input spreadsheet and fetches each listed patent document, then applies a
regular expression pattern to find all matches of a pattern and its surrounding context.
The matches and context are then inserted as additional columns in the OutputFile.

NOTE:
PatternFile must be live perl code to perform the regular expression match.
InputFile must be a <=2003 Excel sheet with bare URLs as the 2nd column.
OutputFile will be overwritten if it exists.
END

exit 1;
}

my $src = $ARGV[1];
my $dest = $ARGV[2];
my $matchedFileCount = 0;

# make a copy of the file so we can add our matches to it
copy($src,$dest) || die "cannot copy $src to $dest due to $!\n";

# Verify pattern file is readable and non-zero
(-s $ARGV[0] && -r $ARGV[0]) || die "could not read pattern file $ARGV[0] due to $!\n";

# SaveParser module lets us modify existing sheet instead of copying cell-by-cell
# which loses formats.
my $parser  = new Spreadsheet::ParseExcel::SaveParser;
my $inBook  = $parser->Parse($dest) || die "could not parse $dest due to $!\n";
my $inSheet = @{$inBook->{Worksheet}}[0];

my $orgMaxCol = $inSheet->{MaxCol};	# we use this +1 for where to start writing the matches
$inSheet->AddCell(0,$orgMaxCol+1,"#Matches");	# Add column header for match count

print "input sheet $src is $inSheet->{MaxRow} rows x $orgMaxCol columns\n";

foreach my $row (1 .. $inSheet->{MaxRow}) {	# loop through all the rows, skiping the header (row 0)

  my $urlcell = $inSheet->{Cells}[$row][1];	# assumes bare URL in column 1 (zero based; is column "B")
  my $url = $urlcell->{Val};
  print "$row of $inSheet->{MaxRow}. $url: ";

  my $urlobj = URI->new($url);			# we'll use URI module for validity test & url cleanup
  $urlobj->scheme || die "invalid URL \"$url\" on row $row\n";	# scheme will be undef if URI->new had bogus URL
  $urlobj = $urlobj->canonical();		# clean up URL as much as possible unconvert %xx, etc

  (my $pathname = $urlobj->path) =~ s:/:-:g; 	# use whole URL path for cache file; replace any / with - in filename
  my $basename = $urlobj->host . $pathname;	# file name in cache dir will be host + full URL path
  my $fullname = "$cachedir/$basename";

  if (! -e $fullname) {
    print "(fetch) ";
    my $fetchstatus = getstore($url,$fullname); 	# getstore fetches URL and stores into file
    die "Error $fetchstatus on $url" unless is_success($fetchstatus);
  } else {
    print "(cache) ";
  }

  open(IN, "<$fullname") || die "Can't open $fullname: $!";
  our $filecontents = do { local $/; <IN> };	# slurp whole file at once rather than line-by-line.
  close(IN);

  # PATTERN MATCH GOES HERE, pulled in via "do" from external file.
  # This lets us try various patterns without editing the main script.
  our @res;
  do $ARGV[0];
  # Pattern match is now all done.

  print "Total matches: ", my $matchCount = int(($#res+1)/2), "\n";

  $inSheet->AddCell($row,$orgMaxCol+1,$matchCount);

  if ($matchCount > 0) {	#now loop through matches and add to sheet
    $matchedFileCount++;

    # remember @res contains tuples of (context,temp)[...] so we increment by two
    for (my $i = 0; ($i <= $#res-1) && ($i <= $maxMatches*2-1); $i+=2) {  
      my $matchNum     = int($i/2)+1;
      my $matchContext = $res[$i];
      my $matchValue   = $res[$i+1]; 
      $inSheet->AddCell($row,$orgMaxCol+1+$i+1,$matchValue);
      $inSheet->AddCell($row,$orgMaxCol+1+$i+2,$matchContext);
      $inSheet->AddCell($row,$orgMaxCol+1+$i+3," ");		# keeps last cell display narrow
    }
  } 

} # end foreach loop through spreadsheet rows

print "$matchedFileCount files matched.\n";

$inBook->SaveAs($dest);

