#! /usr/bin/perl -wT

# rouilj@ieee.org
# a wrapper to make twiki and bool work better together.
# this detects when it is not a boolean string and turns it into an
# and boolean string respecting phrases surrounded by " or '.
# So typing:
#     "this phrase" twiki nothing else
# gets converted into:
#     "this phrase" and twiki and nothing and else
# rather than returing a syntax error.
use strict;
$ENV{'PATH'} = "/usr/bin";

sub boolwrap {
    my $bool = "/tools/bool-0.2.1/bin/bool";
    my $fgrep = "/bin/fgrep";
    my $debug = 0;

    print STDERR join(" | ", @_) . "\n" if $debug;
    my ($argument, $files, $searchstring);
    while ($_ = shift @_) {
	last if m/^--$/;
	$debug = 1, next if m/^-Dhelper/;
	$argument .= " $_", next if m/^-/;
	unshift @_, $_;
	last;
    }
    $argument .= " --";
    $searchstring = shift @_;
    $files = join(" ", @_);

    # strip fore and aft whitespace
    $searchstring =~ s/\s*$//;
    $searchstring =~ s/^\s*//;

  MODIFY: {
      # see if there are boolean commands in string. Pass through
      # unmolested. Bool will complain if its not well formed though 8-(.
      $searchstring = qq($searchstring), last MODIFY
	  if $searchstring =~ /\s(and|or|near|not)\s/i;

      # put 'and' between every whitespace delimited word or quoted
      # phrase. Walk through string locating quoted strings.

      my ($searchPart, $searchRest, $inQuote, @searchParts);

      $inQuote = 0;
      $searchRest = $searchstring;
      while ($searchRest) {
	  ($searchPart, $searchRest) = split(/\"/, $searchRest, 2);
	  $inQuote = 1 if !defined($searchPart) || $searchPart =~ /^\s*$/;
	  # had a quote at the beginning of searchRest.
	  if ($inQuote) {
	      if (defined($searchPart) && $searchPart !~ /^\s*$/) {
                  # put back quotes around phrase
		  push @searchParts, qq["$searchPart"];
		  $inQuote = 0;
	      }
	  } else {
	      push @searchParts, join(" and ", split(' ', $searchPart))
		  if  defined($searchPart) && $searchPart !~ /^\s*$/;
	      $inQuote = 1;
	  }
      }
      # recreate a new search string
      $searchstring = join(" and ", @searchParts);
      # escape characters special to bool
      $searchstring =~ s/([()])/\\$1/g;
  }
    
    # parse out a line assume that we have syntax of:
    # phrase := word op phrase | word
    # op := and, or, near, not
    # detaint. Replace 
  $searchstring =~ s/\"/&quot;'/g;
  $searchstring = $1 if $searchstring =~ m/(.*)/;
  $argument = $1 if $argument =~ m/ (.*)/;
  $files = $1 if $files =~ m/(.*)/;

  print STDERR "$0: args: '$argument'\n" if $debug;
  print STDERR "$0: search: '$searchstring'\n" if $debug;
  print STDERR "$0: files: '$files'\n" if $debug;

  if ( $files ne "" ) {  # that is we are searching files
    if ( $searchstring !~ m/^['"]*$/ ){ # look for stupid search
                                        # like for ' or "
      print STDERR "$0: $bool $argument \"$searchstring\" $files\n" if $debug;
      exec "$bool $argument \"$searchstring\" $files";
    } else {
      print STDERR "$0: meaningless query\n" if $debug;
    }
  } else {
    # bool is great, but it doesn't work for grepping matching patterns
    # from stdin 8-(. 
    print STDERR "$0: $fgrep $argument \"$searchstring\"\n" if $debug;
    exec "$fgrep $argument \"$searchstring\"";
  }
}

boolwrap(@ARGV);
