#!/usr/bin/perl

use English;
use Getopt::Declare; 



######################
# ARGUMENT PROCESSING
######################
#$inFilename = $ARGV[0];

use vars qw ($inFilename $POSTSCRIPT_OUTPUT $PDF_OUTPUT $PDFLATEX_OUTPUT $ALLOW_EMBEDDED_CODE $PARTIAL_DOCUMENT);

use vars qw ($EASYLATEXSTORE_MAIN_RESERVED_WORD $StorageIndex);

$StorageIndex = 0;

$EASYLATEXSTORE_MAIN_RESERVED_WORD = 'EASYLATEXSTORE-MAIN-RESERVED-WORD';

#test4


$argSpecification = q(
		      -ps	              Create a postscript output file (by calling latex, and then dvips)
		      {$POSTSCRIPT_OUTPUT = 1;} 

		      -pdf	              Create a pdf output file (by calling latex, and then dvipdf)
		      {$PDF_OUTPUT = 1;}

		      -pdflatex	              Create a pdf output file (by calling pdflatex -- use this if there's screwy errors in the file generated by -pdf)
		      {$PDFLATEX_OUTPUT = 1;}

		      --partial	              This file is not a full LaTeX document, just a partial one (to be \\include'd, for instance)
		      {$PARTIAL_DOCUMENT = 1;}

		      -e		 Allow execution of embedded code (advanced feature)
		      {$ALLOW_EMBEDDED_CODE = 1;}

		      <input>	     The input file
		      {$inFilename = $input;}
		      );



$args = new Getopt::Declare($argSpecification);

#print "ARG: $inFilename\n $j\nPO: $POSTSCRIPT_OUTPUT, PDF: $PDF_OUTPUT";

######################
# DEFINE GLOBAL CONSTANTS
######################

use vars qw($EASYLATEX_DIR @TRANSFORM_PATHS $PS_OUTPUT_COMMANDS $PDF_OUTPUT_COMMANDS $PDFLATEX_OUTPUT_COMMANDS $outFilename $stripFilename);

# doing both ways; todo; clean up global var declr

$PS_OUTPUT_COMMANDS = <<'EOF' ;
system('latex',$outFilename);
system('dvips',"${stripFilename}.dvi", "-o${stripFilename}.ps");
EOF

$PDF_OUTPUT_COMMANDS = <<'EOF' ;
system('latex',$outFilename);
system('dvipdf',"${stripFilename}.dvi");
EOF

$PDFLATEX_OUTPUT_COMMANDS = <<'EOF' ;


while ($out =~ /\{([^}]+?\.eps)\}/g) {
  push(@eps_files_to_convert, $1);
}

$out =~ s/\{([^}]+?)\.eps\}/{\1.pdf}/g;
foreach $file (@eps_files_to_convert) {
  system('epstopdf', $file);
}

open(OUT, '>'.$outFilename);
print OUT $out;
close(OUT);

system('pdflatex',$outFilename);
EOF


#
# I'll assume most distos have psfrag and leave this out for now...
#
#    use Cwd;
#$cwd = cwd();
#$ENV{TEXINPUTS} .= ":$cwd/psfrag";
#$ENV{DVIPSHEADERS} .= ":$cwd/psfrag";


######################
# MAIN
######################

init();

$in = readFile($inFilename);
$stripFilename = stripFilename($inFilename); 
$outFilename = $stripFilename . '.tex';

### preprocess the file

###   1) if it doesn't end with a newline, add one
if (substr($in,-1) ne "\n") {$in = $in . "\n";}

###   2) convert DOS-style newlines to UNIX-style (strip linefeeds)
while ($in =~ s/\r$//g) {}

###   3) store verbatims
$in = storeVerbatims($in);


## first, make a copy of the input
open(OUT, '>'.$outFilename);
print OUT $in;
close(OUT);

## now, run the transforms on it
foreach $transform (@TRANSFORM_PATHS) {
    if (-x $transform)
    {
	system("$transform", "$outFilename", "$EASYLATEX_DIR", @TRANSFORM_ARGS);

	unlink "$outFilename.bak";
	unlink "$outFilename.bak.bak";
    }
    elsif ($transform =~ /.*\.pl$/)
    {
	#print STDERR "about to do $transform\n";
	#$ENV{'PERL5OPT'} = 'i';
	use English;
        #print STDERR "$EXECUTABLE_NAME -i.bak $transform $outFilename $EASYLATEX_DIR $TRANSFORM_ARGS[0]\n";
	system("$EXECUTABLE_NAME -i.bak $transform", "$outFilename", "$EASYLATEX_DIR", @TRANSFORM_ARGS);
	
	unlink "$outFilename.bak";
	unlink "$outFilename.bak.bak";
    }
    else {
	print STDERR "Skipping $transform -- can't figure out how to execute it\
n";
    } 
    #print "\n\nJUST DID $transform\n\n";

    #print "\n\nJUST DID $transform on $outFilename\n\n";
#    system('cat', "$outFilename");
}

## first, make a copy of the input
open(OUT, $outFilename);
local undef $/;
my $out = <OUT>; 
close(OUT);


###   3) unstore verbatims
$out = unstoreVerbatims($out);

open(OUT, '>'.$outFilename);
print OUT $out;
close(OUT);


## do post-processing if requested
postProcess($out);


######################
# end of MAIN
######################



sub init
{
    findEasylatexDir();
    initListOfTransforms();
    if ($PARTIAL_DOCUMENT) {
	push(@TRANSFORM_ARGS, '--partial');
    }
    $TRANSFORM_ARGS = join(' ', @TRANSFORM_ARGS);
    #print "DBG: #$TRANSFORM_ARGS#\n";
}

sub postProcess {
    my ($out) = @_;


    open(FILE, $outFilename);
    local undef $/;
    my $file = <FILE>; 
    close(FILE);

    #TODO: may not work with pdflatex
    if ($file =~ /\\bibliography{(.*)\.bib}/) {
	system('latex',$outFilename);
	system('bibtex',$1);
    }

    system('latex',$outFilename);


    if ($POSTSCRIPT_OUTPUT)
    {
	eval $PS_OUTPUT_COMMANDS;
    }

    if ($PDF_OUTPUT)
    {
	eval $PDF_OUTPUT_COMMANDS;
    }

    if ($PDFLATEX_OUTPUT)
    {
	eval $PDFLATEX_OUTPUT_COMMANDS;
    }
}


###########################################################################
# findEasylatexDir
#   looks through a searchpath for the easylatex directory.
#   die if it can't find it.
###########################################################################
sub findEasylatexDir {
   local @easylatex_dir_searchpath;

    push(@easylatex_dir_searchpath,"./easylatex");
    push(@easylatex_dir_searchpath,"$ENV{HOME}/.easylatex");
    push(@easylatex_dir_searchpath,'/usr/lib/easylatex');

    $EASYLATEX_DIR = '';
    foreach $path (@easylatex_dir_searchpath)
    {
	if (( -e $path && -d $path)) {
	    $EASYLATEX_DIR = $path;
	}
    }

    errorCheckEasylatexDir();
}

####################################################
# errorCheckEasylatexDir
#    if the easylatex or the transform directories
#    don't exist or aren't directories, then die
####################################################
sub errorCheckEasylatexDir {    
    if (! $EASYLATEX_DIR)
    {
	die "Can't find easylatex directory. The program probably isn't installed correctly; please see documentation or run quickInstall. Aborting (looked for the directory in " . join(', ', @easylatex_dir_searchpath) . ")";
	
    }
    
    if (! ( -e "$EASYLATEX_DIR/transforms" && -d "$EASYLATEX_DIR/transforms"))
    {
	die "I found the easylatex directory at $EASYLATEX_DIR, but didn't find the directory $EASYLATEX_DIR/transforms. The program probably isn't installed correctly; please see documentation. Aborting.";
	
    }

# TODO: add to docs
}

###########################################################################
# initListOfTransforms
#   makes a list of the paths of the transforms to run
#     (1) lists the files in the transform directory,
#     (2) filters out files starting with '.' or '#' or ending with '~',
#     (3) sorts the resulting list,
#     (4) prepends the path to each file,
#     (5) leaves the result in the global variable @TRANSFORM_PATHS
###########################################################################
sub initListOfTransforms {

    my %fullPath;

##### list the files in the transform directory
    opendir(TRANSFORMDIR, "$EASYLATEX_DIR/transforms") || die "can't opendir $EASYLATEX_DIR/transforms. The program probably isn't installed correctly; please see documentation. Aborting.";
    @TRANSFORM_PATHS = readdir(TRANSFORMDIR);
    closedir(TRANSFORMDIR);

#### remember the path
    foreach $path  (@TRANSFORM_PATHS)
    {
	$fullPath{$path} = "$EASYLATEX_DIR/transforms/"  . $path;
    }


##### if allowed, add the embedded code transforms
    if ($ALLOW_EMBEDDED_CODE) {
	opendir(EMBEDDED_CODE_TRANSFORMDIR,"$EASYLATEX_DIR/embed_transforms");
	@EMBEDDED_CODE_TRANSFORM_PATHS = readdir(EMBEDDED_CODE_TRANSFORMDIR);
	closedir(EMBEDDED_CODE_TRANSFORMDIR);

	foreach $path  (@EMBEDDED_CODE_TRANSFORM_PATHS)
	{
	    $fullPath{$path} = "$EASYLATEX_DIR/embed_transforms/"  . $path;
	}

	push(@TRANSFORM_PATHS, @EMBEDDED_CODE_TRANSFORM_PATHS); 
	# add this to the @TRANSFORM_PATHS list
}



##### filter
    @TRANSFORM_PATHS = grep(!/^\./,@TRANSFORM_PATHS);
    @TRANSFORM_PATHS = grep(!/^\#/,@TRANSFORM_PATHS);
    @TRANSFORM_PATHS = grep(!/~$/,@TRANSFORM_PATHS);
    @TRANSFORM_PATHS = grep(!/math_mode_symbol_list.txt/,@TRANSFORM_PATHS);
    @TRANSFORM_PATHS = grep(!/config.txt/,@TRANSFORM_PATHS);

#### sort
    @TRANSFORM_PATHS = sort(@TRANSFORM_PATHS);


#### prepend the path
    foreach $path  (@TRANSFORM_PATHS)
    {
	$path = $fullPath{$path};
    }


#    use Data::Dumper; print Dumper(@TRANSFORM_PATHS);



}

######################
# UTILITY SUBROUTINES
######################

######################
# string readFile($fileName)
#   reads in and returns the contents of file $fileName
######################

sub readFile {
    my ($fileName) = @_;
    my $file;

    local undef $INPUT_RECORD_SEPARATOR;
    open(INFILE, $fileName);
    $file = <INFILE>;
    close INFILE;

    return $file;
}

######################
# string calculateOutFilename($inFilename)
######################

sub stripFilepath {
        my ($inFilename) = @_;
	my $stripFilepath;

	$stripFilename = $inFilename;
	
	$stripFilename =~ s/.txt//;

	return $stripFilepath;
	
}


sub stripFilename {
        my ($inFilename) = @_;
	my $stripFilename;

	$stripFilename = $inFilename;
	
	$stripFilename =~ s/.txt//;
	
	$stripFilename =~ s/.*\///;

	return $stripFilename;
	
}


######################
# "store" subroutines
######################

sub storeVerbatims {
    my ($file) = @_;

    ${notSlashRE_begin} = '(^|(?!\\).)';
    ${notSlashRE} = '(?!\\).';

    $file =~ s/(\\begin{verbatim}.*?\\end{verbatim})/store($1)/egs;
    $file =~ s/\\begin{latex}(.*?)\\end{latex}/store($1)/egs;
    $file =~ s/(\\newcommand.*)/store($1)/eg;
    $file =~ s/(\\includegraphics(?:\[[^\]]*\])?{[^}]+})/store($1)/egs;
     # TODO: there's a bug in the last line (i think, maybe)
    $file =~ s/(%%.*)/store($1)/eg;


    return $file;
}

sub unstoreVerbatims {
    my ($file) = @_;

#    print STDERR "UNSTORE:\n\n".$file;

    while ($file =~ s/ ?${EASYLATEXSTORE_MAIN_RESERVED_WORD}-(\d+)-${EASYLATEXSTORE_MAIN_RESERVED_WORD} ?/$Stored{$1}/egs) {}

    $file =~ s/\\begin{latex}//g;
    $file =~ s/\\end{latex}//g;

    return $file;
}



sub store {
    # got this idea from UseMod
  my ($toBeStored) = @_;

  $Stored{$StorageIndex} = $toBeStored;
#  print STDERR "STORED: $toBeStored\n";

#  print STDERR "REPLACEDW: ".${EASYLATEXSTORE_RESERVED_WORD}.'_' . $StorageIndex . '_'.${EASYLATEXSTORE_RESERVED_WORD};

  return ' '.${EASYLATEXSTORE_MAIN_RESERVED_WORD}.'-' . $StorageIndex++ . '-'.${EASYLATEXSTORE_MAIN_RESERVED_WORD}.' ';
}
