eval 'exec perl -x $0 ${1+"$@"}' # -*-perl-*-
  if 0;
#!perl -w
# Compile a latex document, by any of a number of means.
# Diego Zamboni, Jan 9, 2001.
#
# The algorithm is as follows:
# - If the argument is a file:
#   - Process it with any of prv, latexmk or latex, in that order. The program to
#     use can also be specified in the LATEX environment variable. If none exist,
#     fail.
# - If the argument is a directory:
#   - If there is a Makefile or makefile, run "make". If the file MakeArgs
#     exists, its contents is passed as argument to make.
#   - Otherwise, if a file called "main.tex" exists, it is processed as
#     if that file was the argument.
#   - Else, fail.

use strict;
use vars qw(
	    $prv
	    $make
	    $xdvi
	    $gv
	    $lpr
	    $xterm
	    $AppDir
	    $action
	    @validactions
	    @PATH $LATEX $MAKE $XDVI $GV $LPR
	   );
use Env qw(@PATH $LATEX $MAKE $XDVI $GV $LPR);
use File::Basename;

unless (@ARGV) {
  my $xmsg=which("xmessage", "wmessage", "xsay");
  system("$xmsg 'Drop a LaTeX file or directory on me, and I will compile it for you.'");
  exit;
}

$AppDir=dirname($0);

# Find how to process latex files.
$prv=$LATEX || which("prv", "latexmk", "latex");
# Find make
$make=$MAKE || which("make", "gmake");
# Find how to view dvi files
$xdvi=$XDVI || which("xdvi", "kdvi");
# Find how to view postscript files
$gv=$GV || which("gv", "ghostview");
# Find how to print
$lpr=$LPR || which("lpr", "lp");
# Find a terminal program
$xterm=which("xterm", "rxvt", "aterm", "Eterm");
# Valid actions
@validactions=qw(latex viewdvi viewps print);

$action=undef;
# Check action flags
if ($ARGV[0] =~ /^--(\w+)/) {
  shift @ARGV;
  foreach (@validactions) {
    $action=$1,last if $1 eq $_;
  }
  die "Invalid flag --$1 (valid choices are --".join(" --",@validactions).")\n"
    unless $action;
}
$action="latex" unless $action;

@ARGV=get_files() unless @ARGV;

foreach (@ARGV) {
  s!^file://[^/]+/!/!;
  process($_);
}

exit;

# Find an executable in PATH.
sub which {
  my @files=@_;
  foreach my $file (@files) {
    foreach (@PATH) {
      if (-x "$_/$file") {
	return "$_/$file";
      }
    }
  }
  return undef;
}

# Find any of a number of files in any of a number of directories.
# Syntax: findfile(dir, file1, file2, ...)
#         findfile([dir1, dir2,...], file1, file2, ...)
# Returns the first one found and readable.
sub findfile {
  my $dirarg=shift;
  my @files=@_;
  my @dirs;
  if (ref($dirarg)) {
    @dirs=@$dirarg;
  }
  else {
    @dirs=($dirarg);
  }
  foreach my $dir (@dirs) {
    foreach my $file (@files) {
      my $try="$dir/$file";
      if (-f $try && -r $try) {
	return $try;
      }
    }
  }
  return undef;
}

# Process a file or directory
sub process {
  my $what=shift;
  if (-f $what) {
    # If it's a file...
    # Act according to $action
    if ($action eq "latex") {
      execute($prv, $what, dirname($what), $what,
	      "$0: Could not find any programs to process latex files\n");
    }
    elsif ($action eq "viewdvi") {
      $what=~s/\.tex/\.dvi/;
      execute($xdvi, $what, dirname($what), $what,
	      "$0: Could not find any programs to view dvi files\n");
    }
    elsif ($action eq "viewps") {
      $what=~s/\.tex/\.ps/;
      execute($gv, $what, dirname($what), $what,
	      "$0: Could not find any programs to view postscript files\n");
    }
    elsif ($action eq "print") {
      # Assume we are printing .ps for now
      $what=~s/\.tex/\.ps/;
      execute($lpr, $what, dirname($what), $what,
	      "$0: Could not find any programs to print postscript files\n");
    }
    else {
      die "Invalid action: $action\n";
    }
    return;
  } elsif (-d $what) {
    # If it's a directory...
    if (my $makefile=findfile($what, "Makefile", "makefile")) {
      my $makeargs=findfile([$what, $AppDir], ".makeargs", "MakeArgs")||"";
      if ($action ne "latex") {
	$makeargs="$action $makeargs";
      }
      execute($make, $makeargs, $what, $what,
	      "There is a makefile, but I can't find make in PATH.\n");
      return;
    }
    elsif (my $file=findfile($what, "main.tex")) {
      process($file);
    }
    else {
      die "Don't know how to process directory $what\n";
    }
  }
  else {
    die "Don't know how to process this file: $what\n";
  }
}

# Execute a command from the given directory (as a second argument), using the
# third optional argument as the window title.
sub execute {
  my $cmd=shift;
  my $arg=shift;
  my $dir=shift;
  my $title=shift;
  my $error=shift || "There was an error executing a command\n";
  unless ($cmd) {
    die "Dying: $error";
  }
  if ($dir) {
    chdir $dir
      or die "$0: Could not chdir to $dir: $!\n";
  }
  if ($title) {
    $title="-title 'Processing $title'";
  }
  else {
    $title="";
  }
  $cmd.=" $arg";
  # If possible, open a new terminal. If not, just execute it.
  if ($xterm) {
    system("$xterm $title -e $AppDir/RunInXterm $cmd");
  }
  else {
    system("$cmd");
  }
}

# If no files are provided, prompt for some
sub get_files {
  my @files=`dropbox -l "Drop a file or directory here for processing"`;
  foreach (@files) {
    chomp;
    s!^file://[^/]+/!/!;
  }
  return @files;
}
