#!/usr/bin/perl -W

use strict;
use Getopt::Long;
use File::Basename;
use File::Spec;
use File::Copy;
use Compress::Zlib;
use Pod::Text;
use Pod::Man;

# GENERAL INSTALLATION INFORMATIONS
my $ALLOW_SYMBOLIC_LINK;
my $INSTALLDIRECTORY;
my $BINDIRECTORY;
my $ETCDIRECTORY;
my $MANDIRECTORY;
my $STYDIRECTORY;

sub dbg(@) {
	use Data::Dumper;
	die(Dumper(@_));
}

#------------------------------------------------------------------------------------------
sub substShellPatterns($) {
	my $t = '';
	$t = "$_[0]" if ($_[0]);
	if ($t) {
		$_[0] =~ s/^~([a-z_0-9]+)/
			my @l = getpwnam("$1");
			if (@l>=8) {
				"$l[7]";
			}
			else {
				"~$1";
			}
			/e;
		$_[0] =~ s/^~\//$ENV{'HOME'}\//;
	}
	return $_[0];
}

#------------------------------------------------------------------------------------------
sub gzipfct($) {
	my $targetfile = shift;
	local *IN;
	my $gz = gzopen("$targetfile.gz","wb") or die("$targetfile.gz: $!");
	open(*IN, "<", "$targetfile") or die("$targetfile: $!");
	while (<IN>) {
		$gz->gzwrite($_);
	}
	close(*IN);
	$gz->gzclose();
	unlink "$targetfile";
}

#------------------------------------------------------------------------------------------
sub rm($) {
	my $delfile = shift;
	if (-f "$delfile") {
		print "delete $delfile\n";
		unlink "$delfile";
	}
}

#------------------------------------------------------------------------------------------
sub getFilesRec($@) {
	my $directory = shift;
	my $pattern = shift;
	my @list = ();
	if (($pattern)&&(-d "$directory")) {
		# Make a pattern
		$pattern =~ s/\./\\./g;
		$pattern =~ s/\*/.*/g;

		# Get the directory content
		my @subdirs = ();
		local *DIR;
		opendir(*DIR,"$directory")
			or die("$directory: $!\n");
		while (my $d = readdir(*DIR)) {
			if (($d ne File::Spec->curdir())&&($d ne File::Spec->updir())&&
			    ($d =~ /^$pattern$/)) {
				my $full = File::Spec->catfile($directory,$d);
				if (-d "$full") {
					push @subdirs, "$full";
				}
				elsif (!@_) {
					push @list, "$full";
				}
			}
		}
		closedir(*DIR);

		# Go into sub directories
		foreach my $d (@subdirs) {
			my @l = &getFilesRec("$d",@_);
			push @list, @l;
		}
	}
	return @list;
}
sub getFiles(@) {
	my $firstpart = shift;
	if ($firstpart) {
		return getFilesRec('.',$firstpart,@_);
	}
	else {
		return getFilesRec(FileSpec->rootdir(),@_);
	}
}

#------------------------------------------------------------------------------------------
sub getDirectories(@) {
	my @list;
	local *DIR;
	foreach my $d (@_) {
		if (-d "$d") {
			opendir(*DIR,"$d") or die("$d: $!\n");
			while (my $sd = readdir(*DIR)) {
				if (($sd ne File::Spec->curdir())&&($sd ne File::Spec->updir())) {
					my $full = File::Spec->catfile($d,$sd);
					if (-d "$full") {
						push @list, "$full";
					}
				}
			}			
			closedir(*DIR);
		}
	}
	return @list;
}

#------------------------------------------------------------------------------------------
sub getDirectoryBasenames(@) {
	my @list;
	local *DIR;
	foreach my $d (@_) {
		if (-d "$d") {
			opendir(*DIR,"$d") or die("$d: $!\n");
			while (my $sd = readdir(*DIR)) {
				if (($sd ne File::Spec->curdir())&&($sd ne File::Spec->updir())) {
					my $full = File::Spec->catfile($d,$sd);
					if (-d "$full") {
						push @list, "$sd";
					}
				}
			}			
			closedir(*DIR);
		}
	}
	return @list;
}

#------------------------------------------------------------------------------------------
sub mkdirrec(@) {
	foreach my $dir (@_) {
		my @parts = File::Spec->splitdir($dir);
		my @np = ();
		foreach my $d (@parts) {
			if ($d) {
				my $rep = @np ? File::Spec->catdir(@np,$d) : $d;
				unless (-d "$rep") {
					mkdir("$rep") or die("$rep: $!\n");
					chmod 0755, "$rep";
				}
			}
			push @np, $d;
		}		
	}
}

#------------------------------------------------------------------------------------------
sub install($$;$) {
	my $sourcefile = shift;
	my $targetdir = shift;
	my $newbasename = shift || basename("$sourcefile");
	mkdirrec($targetdir);
	print "installing $sourcefile into $targetdir\n";
	my $fullname = File::Spec->catfile($targetdir,$newbasename);
	copy("$sourcefile","$fullname")
		or die("$sourcefile: $!\n");
	chmod 0644, "$fullname";	
	return $fullname;
}

#------------------------------------------------------------------------------------------
sub installLink($$;$) {
	return '' unless ($ALLOW_SYMBOLIC_LINK);
	my $sourcefile = File::Spec->rel2abs(shift);
	my $targetdir = File::Spec->rel2abs(shift);
	my $newbasename = shift || basename("$sourcefile");
	mkdirrec($targetdir);
	print "installing link $sourcefile into $targetdir\n";
	my $fullname = File::Spec->catfile($targetdir,$newbasename);
	my $linkname = File::Spec->abs2rel("$sourcefile","$targetdir");
	unlink("$fullname") if (-e "$fullname");
	symlink("$linkname","$fullname")
		or die("$sourcefile: $!\n");
	return $fullname;
}

#------------------------------------------------------------------------------------------
sub installExec($$;$) {
	my $fullname = install($_[0],$_[1],$_[2]);
	chmod 0755, "$fullname";	
	return $fullname;
}

#------------------------------------------------------------------------------------------
sub installCfg($;$) {
	return install($_[0],$ETCDIRECTORY,$_[1]);
}

#------------------------------------------------------------------------------------------
sub installBin($;$) {
	return installExec($_[0],$BINDIRECTORY,$_[1]);
}

#------------------------------------------------------------------------------------------
sub installLinkedBin($$;$) {
	my $fullname = installExec($_[0],$_[1]);
	my $linkname = installLink($fullname,$BINDIRECTORY,$_[2]);
	return ($fullname,$linkname);
}

#------------------------------------------------------------------------------------------
sub installMan(@) {
	my @result = ();
	my %mandirectories = ();
	foreach my $man (@_) {
		my @parts = File::Spec->splitdir($man);
		my @files = getFiles(@parts);
		die("$man: no manual file found\n") unless (@files);
		foreach my $f (@files) {
			my $base = basename($f);
			if ($base =~ /^(.*?)\.([a-z_]+)\.([0-9]+\.gz)$/) {
				my $lang = "$2";
				my $name = "$1.$3";
				unless ($mandirectories{"$lang"}) {
					my @l = File::Spec->splitdir($MANDIRECTORY);
					my $last = pop @l;
					push @l, $lang;
					push @l, $last;
					$mandirectories{"$lang"} = File::Spec->catfile(@l);
				}
				install($f,$mandirectories{"$lang"},$name);
			}
			else {
				push @result, install($f,$MANDIRECTORY);
			}
		}
	}
	return @result;
}

#------------------------------------------------------------------------------------------
sub installInto($@) {
	my $target = shift;
	my @result = ();
	foreach my $fileToInstall (@_) {
		push @result, install($fileToInstall, $target);
	}
	return @result;
}

#------------------------------------------------------------------------------------------
sub installExecInto($@) {
	my $target = shift;
	my @files = installInto($target,@_);
	foreach my $file (@files) {
		chmod 0755, "$file";
	}
	return @files;
}

#------------------------------------------------------------------------------------------
sub DO_compile(\%) {
	print "DO AUTOLATEX COMPILATION...\n";

	my $text_parser = Pod::Text->new('sentence'=>0,);

	print "Generating README...\n";
	$text_parser->parse_from_file(
		File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.pod'),
		File::Spec->catfile($_[0]->{'directory'},'README'));

	print "Generating README_FR...\n";
	$text_parser->parse_from_file(
		File::Spec->catfile($_[0]->{'directory'},'pod','autolatex_fr.pod'),
		File::Spec->catfile($_[0]->{'directory'},'README_FR'));

	my $man_parser = Pod::Man->new('release'=>$_[0]->{'version'}, section => 1);

	print "Generating manual page autolatex.1.gz...\n";
	my $targetfile = File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.1');
	$man_parser->parse_from_file(
		File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.pod'),
		$targetfile);
	gzipfct($targetfile);

	print "Generating manual page autolatex.fr.1.gz...\n";
	$targetfile = File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.fr.1');
	$man_parser->parse_from_file(
		File::Spec->catfile($_[0]->{'directory'},'pod','autolatex_fr.pod'),
		$targetfile);
	gzipfct($targetfile);

	local *DIR;
	local *DIR2;
	my $directory = File::Spec->catdir($_[0]->{'directory'},'po');
	opendir(*DIR,"$directory") or die("$directory: $!\n");
	while (my $topdir = readdir(*DIR)) {
		if (($topdir ne File::Spec->curdir())&&($topdir ne File::Spec->updir())) {
			my $subdirectory = File::Spec->catdir($directory,$topdir,'LC_MESSAGES');
			opendir(*DIR2,"$subdirectory") or next;
			while (my $pofile = readdir(*DIR2)) {
				if ($pofile =~ /\.po$/i) {
					print "Generating translations for $pofile...\n";
					my $mofile = $pofile;
					$mofile =~ s/\.po/.mo/i;
					system('msgfmt','-v','-o',
						File::Spec->catfile("$subdirectory","$mofile"),
						File::Spec->catfile("$subdirectory","$pofile"));
				}
			}
			closedir(*DIR2);
		}
	}
	closedir(*DIR);
}

#------------------------------------------------------------------------------------------
sub DO_install(\%) {
	print "DO AUTOLATEX INSTALLATION...\n";
	if (($_[0]->{'create-links'})&&($_[0]->{'create-bin-links'})) {
		installLinkedBin('autolatex.pl', $INSTALLDIRECTORY,'autolatex');
		installLinkedBin('autolatex-gtk.pl',$INSTALLDIRECTORY,'autolatex-gtk');
	}
	else {
		installExec('autolatex.pl', $INSTALLDIRECTORY);
		installExec('autolatex-gtk.pl',$INSTALLDIRECTORY);
	}
	install('AUTHORS', $INSTALLDIRECTORY);
	install('VERSION', $INSTALLDIRECTORY);
	if (($_[0]->{'create-links'})&&($_[0]->{'create-etc-links'})) {
		my $cfgFile = installCfg('default.ist');
		installLink($cfgFile,$INSTALLDIRECTORY);
		$cfgFile = installCfg('default.cfg','config');
		installLink($cfgFile,$INSTALLDIRECTORY,'default.cfg');
	}
	else {
		install('default.ist',$INSTALLDIRECTORY);
		install('default.cfg',$INSTALLDIRECTORY);
	}

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'mkfiles'),
		getFiles('mkfiles','*'));

	installExecInto(
		File::Spec->catfile($INSTALLDIRECTORY,'scripts'),
		getFiles('scripts','*'));

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'pm','AutoLaTeX'),
		getFiles('pm','AutoLaTeX','*.pm'));

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'pm','AutoLaTeX','GUI'),
		getFiles('pm','AutoLaTeX','GUI','*.pm'));

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'pm','AutoLaTeX','GUI'),
		getFiles('pm','AutoLaTeX','GUI','*.png'));

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'pm','AutoLaTeX','GUI','Gtk'),
		getFiles('pm','AutoLaTeX','GUI','Gtk','*.pm'));

	my @directories = getDirectoryBasenames('po');
	foreach my $lang (@directories) {
		installInto(
			File::Spec->catfile($INSTALLDIRECTORY,'po',"$lang",'LC_MESSAGES'),
			getFiles('po',"$lang",'LC_MESSAGES','*.mo'));
	}

	installInto(
		File::Spec->catfile($INSTALLDIRECTORY,'pod'),
		getFiles('pod','*.pod'));

	installMan('pod/autolatex.*.1.gz',
		   'pod/autolatex.1.gz');

	installInto(
		$STYDIRECTORY,
		getFiles('sty','*'));
	
}

#------------------------------------------------------------------------------------------
sub DO_clean(\%) {
	print "DO AUTOLATEX CLEANING...\n";
	#rm(File::Spec->catfile($_[0]->{'directory'},'README'));
	rm(File::Spec->catfile($_[0]->{'directory'},'README_FR'));
	rm(File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.1.gz'));
	rm(File::Spec->catfile($_[0]->{'directory'},'pod','autolatex.fr.1.gz'));

	local *DIR;
	local *DIR2;
	my $directory = File::Spec->catdir($_[0]->{'directory'},'po');
	opendir(*DIR,"$directory") or die("$directory: $!\n");
	while (my $topdir = readdir(*DIR)) {
		if (($topdir ne File::Spec->curdir())&&($topdir ne File::Spec->updir())) {
			my $subdirectory = File::Spec->catdir($directory,$topdir,'LC_MESSAGES');
			opendir(*DIR2,"$subdirectory") or next;
			while (my $mofile = readdir(*DIR2)) {
				if ($mofile =~ /\.mo$/i) {
					rm(File::Spec->catfile("$subdirectory","$mofile"));
				}
			}
			closedir(*DIR2);
		}
	}
	closedir(*DIR);

	rm(File::Spec->catfile($_[0]->{'directory'},'Makefile'));
}

#------------------------------------------------------------------------------------------
sub DO_createMakefile(\%) {
	print "CREATING MAKEFILE...\n";
	local *OUT;

	my @options = ();
	if ($_[0]->{'version'}) {
		push @options, '"--version='.$_[0]->{'version'}.'"';
	}
	if ($_[0]->{'prefix'}) {
		push @options, '"--prefix='.$_[0]->{'prefix'}.'"';
	}
	if ($_[0]->{'man-prefix'}) {
		push @options, '"--manprefix='.$_[0]->{'man-prefix'}.'"';
	}
	if ($_[0]->{'etc-prefix'}) {
		push @options, '"--etcprefix='.$_[0]->{'etc-prefix'}.'"';
	}
	if ($_[0]->{'tex-prefix'}) {
		push @options, '"--texprefix='.$_[0]->{'tex-prefix'}.'"';
	}
	if ($_[0]->{'create-links'}) {
		push @options, '"--link"';
	}
	else {
		push @options, '"--nolink"';
	}
	if ($_[0]->{'create-etc-links'}) {
		push @options, '"--etclink"';
	}
	else {
		push @options, '"--noetclink"';
	}
	if ($_[0]->{'create-bin-links'}) {
		push @options, '"--binlink"';
	}
	else {
		push @options, '"--nobinlink"';
	}

	my $options = join(' ',@options);

	my $filename = File::Spec->catfile($_[0]->{'directory'},"Makefile");
	open(*OUT, "> $filename") or die("$filename: $!\n");
	print OUT "all:\n";
	print OUT "\t@ perl ".__FILE__." $options compile\n\n";
	print OUT "install:\n";
	print OUT "\t@ perl ".__FILE__." $options install\n\n";
	print OUT "clean:\n";
	print OUT "\t@ perl ".__FILE__." $options clean\n\n";
	close(*OUT);
}

#------------------------------------------------------------------------------------------
my %options = ();
$options{'directory'} = File::Spec->rel2abs(dirname(__FILE__));
$options{'create-links'} = 1;
$options{'create-bin-links'} = 1;
$options{'create-etc-links'} = 1;

# Detect the version number
local *FILE;
open(*FILE,"<".File::Spec->catfile($options{'directory'},'VERSION'))
	or die(File::Spec->catfile($options{'directory'},'VERSION').":$!\n");
while (my $line = <FILE>) {
	if ($line =~ /^\s*autolatex\s*([0-9\-a-z\.]+)\s*$/i) {
		$options{'version'} = "$1";
	}
}
close(*FILE);

# Read command line
if (!GetOptions(
		'texprefix=s' => \$options{'tex-prefix'},
		'etcprefix=s' => \$options{'etc-prefix'},
		'manprefix=s' => \$options{'man-prefix'},
		'prefix=s' => \$options{'prefix'},
		'version=s' => \$options{'version'},
		'link!' => \$options{'create-links'},
		'binlink!' => \$options{'create-bin-links'},
		'etclink!' => \$options{'create-etc-links'},
		)) {
	exit(1);
}

# Detect action
$options{'action'} = 'unknow';
foreach my $act (@ARGV) {
	if ($act eq 'compile') {
		$options{'action'} = 'compile';
	}
	elsif ($act eq 'install') {
		$options{'action'} = 'install';
	}
	elsif ($act eq 'clean') {
		$options{'action'} = 'clean';
	}
}

# Set the paths
if (("$^O" eq 'MSWin32')||
    ("$^O" eq 'NetWare')||
    ("$^O" eq 'symbian')) {
	# Win32 compatible platform
	$ALLOW_SYMBOLIC_LINK = 0;

	my $PREFIX = substShellPatterns($options{'prefix'}) || File::Spec->catfile('C:','Program Files');
	my $ETCPREFIX = "$PREFIX";
	my $MANPREFIX = substShellPatterns($options{'man-prefix'}) || File::Spec->catfile('C:','Documents and Settings','All Users','Application Data');
	my $TEXPREFIX = substShellPatterns($options{'tex-prefix'}) || File::Spec->catfile($PREFIX,'autolatex','sty');

	$INSTALLDIRECTORY = File::Spec->catfile("$PREFIX",'autolatex');
	$BINDIRECTORY = File::Spec->catfile("$PREFIX",'autolatex');
	$ETCDIRECTORY = File::Spec->catfile("$ETCPREFIX",'autolatex');
	$MANDIRECTORY = File::Spec->catfile("$MANPREFIX",'autolatex','man','english');
	$STYDIRECTORY = File::Spec->catfile("$TEXPREFIX",'tex','latex','autolatex');
}
else {
	# Unix compatible platform
	$ALLOW_SYMBOLIC_LINK = 1;

	my $PREFIX = substShellPatterns($options{'prefix'}) || File::Spec->catfile('','usr','local');
	my $end = File::Spec->catfile('usr','local');
	if ($PREFIX =~ /\Q$end\E$/) {
		$end = File::Spec->catfile("$PREFIX",'..','..','etc');
	}
	else {
		$end = File::Spec->catfile("$PREFIX",'..','etc');
	}
	my $ETCPREFIX = substShellPatterns($options{'etc-prefix'}) || $end;
	my $MANPREFIX = substShellPatterns($options{'man-prefix'}) || File::Spec->catfile($PREFIX,'man');
	my $TEXPREFIX = substShellPatterns($options{'tex-prefix'}) || File::Spec->catfile($PREFIX,'share','texmf');

	$INSTALLDIRECTORY = File::Spec->catfile("$PREFIX",'lib','autolatex');
	$BINDIRECTORY = File::Spec->catfile("$PREFIX",'bin');
	$ETCDIRECTORY = File::Spec->catfile("$ETCPREFIX",'autolatex');
	$MANDIRECTORY = File::Spec->catfile("$MANPREFIX",'man1');
	$STYDIRECTORY = File::Spec->catfile("$TEXPREFIX",'tex','latex','autolatex');
}

# Run the action
if ($options{'action'} ne 'unknow') {
	eval("DO_".$options{'action'}.'(%options);');
	die"$@\n" if ($@);
}
else {
	DO_createMakefile(%options);
}

exit(0);

__END__

