#!/usr/bin/perl

#Install and configuration utility for disperse.
# Johan Stenberg
#
# Copyright (c) 2008 Johan Stenberg
# This file is part of Disperse.
#
# Disperse is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Disperse is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Disperse; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

use strict;
my $err;

#Write startup message
print "Disperse installation and configuration utility\n";
print "\n";
print "Current OS is $^O\n";
my $iswin = $^O eq "MSWin32";

print "\n";
print "Checking prerequisites...\n";

#Check for perl
print "  Checking that perl is on the PATH...\n";
if ( system("perl -e 1") >> 8 == 0 ) {
	print "OK   perl is on the PATH\n";
}
else {
	print "FAIL perl is not on the PATH\n";
}
print "\n";

close STDERR;
open( STDERR, '>', $err );

#Check for CPAN to enable auto-install of missing modules
print "  Checking that cpan is on the PATH...\n";
my $cpan = 0;
if ( system("cpan -v") >> 8 == 0 ) {
	print "OK   cpan is on the PATH. Will try to auto-install any missing perl modules.\n";
	$cpan = 1;
}
else {
	print "WARN cpan is not on the PATH. Auto-install of missing perl modules is disabled.\n";
}
print "\n";



print "  Looking for required perl modules...\n";
checkModule("FindBin");
checkModule("FileHandle");
checkModule("File::Spec");
checkModule("Getopt::Long");
checkModule("LWP::Simple");
checkModule("Log::Log4perl");
print "\n";
use File::Spec;
use FindBin;

#Check for java
print "  Checking that java is on the PATH...\n";
if ( system("java -version") >> 8 == 0 ) {
	print "OK   java is on the PATH\n";
}
else {
	print "FAIL java is not on the PATH\n";
	print "Aborting";
	exit(1);
}
print "\n";

#Run the setup script
$err = "";
close STDERR;
open( STDERR, '>', $err );

print "Running the setup script...\n";
my $setup = $iswin ? "setup.bat" : "./setup.sh";
if ( system($setup) >> 8 == 0 ) {
	print "OK   setup script completed\n";		
	if (!$iswin) {
		print "  Changing file permission for executables...\n";
		if ( system("chmod +x *.sh") >> 8 == 0 ) {
			print "OK   permissions changed\n";
		}
		else {
			print "FAIL changing permission failed. Do 'chmod +x *.sh' manually\n";
			print "$err\n";	
		}
	}
}
else {
	print "FAIL setup script returned an error:\n";
	print "$err\n";
	print "Aborting";
	exit(1);
}
print "\n";

print "Checking default configuration...\n";
my $changes = 0;

# Create config file filehandle
my $config_file = $FindBin::Bin . "/config/default_config.properties";
my $config_fh;
my $copen = open( $config_fh, $config_file );

my %config = ();
if ($copen) {
	print "OK   Default config file is: $config_file\n";

	# Create hash for config key and value pairs using config file

	while (<$config_fh>) {
		chomp;
		if (/(.*)=(.*)/) {
			$config{$1} = $2;
			print "  $1 = $2\n";
		}
	}
	close($config_fh);
}
else {
	print "FAIL Could not open default config file '$config_file':\n  $!\n";
	print "\nConfiguration aborted.\n";
	exit(1);
}
print "\n";

#Check the presence of the fastacmd program
my $fastacmd_done = 0;
while ( !$fastacmd_done ) {
	if ( checkFastacmd() ) {
		$fastacmd_done = 1;
	}
	else {
		print "\nEnter the path to your fastacmd program (leave empty to skip): ";
		my $line = <STDIN>;
		chomp($line);
		if ( $line eq "" ) {
			$fastacmd_done = 1;
		}
		else {
			$config{'path.fastacmd'} = $line;
			$changes = 1;
		}
	}
}

#Check the presence of a blast database
my $blastdb_done = 0;
while ( !$blastdb_done ) {
	if ( checkBlastDB() ) {
		$blastdb_done = 1;
	}
	else {
		print "\nEnter the path to the blast database, excluding .nin or .nal extension (Leave empty to skip): ";
		my $line = <STDIN>;
		chomp($line);
		if ( $line eq "" ) {
			$blastdb_done = 1;
		}
		else {
			$config{'resource.blastDb'} = $line;
			$changes = 1;
		}
	}
}

#Check the presence of the ccds datafile
my $ccds_done = 0;
while ( !$ccds_done ) {
	if ( checkCCDS() ) {
		$ccds_done = 1;
	}
	else {
		print "\nEnter the path to the ccds file (Leave empty to skip or download): ";
		my $line = <STDIN>;
		chomp($line);
		if ( $line eq "" ) {
			print "Do you wish to download a CCDS file ('y' to download, leave empty to skip)? ";
			my $opt = <STDIN>;
			chomp($opt);						
			
			if ($opt eq "y") {
				print "Downloading CCDS file...\n";
				my $ccdsurl = "http://ftp.bioinformatics.org/pub/disperse/data/ccds-latest.txt";
				my $ccdsfile = get_abs_config_entry("data/ccds-latest.txt",$FindBin::Bin."/".$FindBin::Script);				
				$changes = 1;
				$config{'resource.ccdsFile'} = $ccdsfile;
				my $ok = system("lwp-download -a $ccdsurl \"$ccdsfile\"") >> 8 == 0;
								
				if (!$ok) {
					print "Download failed. Try downloading manually from the disperse web site.\n";
				}
				
			}
			else {					
				$ccds_done = 1;
			}												
		}
		else {
			$changes = 1;
			$config{'resource.ccdsFile'} = $line;
		}
	}
}

#Check the presence of the variation file
my $snp_done = 0;
while ( !$snp_done ) {
	if ( checkMasterSNP()) {
		$snp_done = 1;
	}
	else {
		print "\nEnter the path to the master variation file (Leave empty to skip or download): ";
		my $line = <STDIN>;
		chomp($line);
		if ( $line eq "" ) {
			print "Do you wish to download a master variation file ('y' to download, leave empty to skip)? ";
			my $opt = <STDIN>;
			chomp($opt);						
			if ($opt eq "y") {
				print "Downloading master variation file...\n";
				my $snpurl = "http://ftp.bioinformatics.org/pub/disperse/data/dbSNP-latest.txt";
				my $snpfile = get_abs_config_entry("data/dbSNP-latest.txt",$FindBin::Bin."/".$FindBin::Script);
				$changes = 1;				
				$config{'resource.masterSnpFile'} = $snpfile;
				my $ok = system("lwp-download -a $snpurl \"$snpfile\"") >> 8 == 0;
				if (!$ok) {
					print "Download failed. Try downloading manually from the disperse web site.\n";
				}
			}
			else {					
				$snp_done = 1;
			}												
		}
		else {
			$changes = 1;
			$config{'resource.masterSnpFile'} = $line;
		}
	}
}



print "\nDone. Current configuration is:\n";
my $key;
my $value;
while(($key, $value) = each(%config)) {
	print "  $key = $value\n"; 
}

if ($changes) {}
print "Store configuration to file (y to store, leave blank to skip)?";

my $store = <STDIN>;
chomp($store);
if ($store eq "y") {
	
	$copen = open( $config_fh, ">$config_file" );
	
	while(($key, $value) = each(%config)) {
		print $config_fh "$key=$value\n"; 
	}	
	
}

close STDERR;
print "Completed\n";

sub checkFastacmd {
	
	my $FASTACMD_BIN = $config{'path.fastacmd'};
	$FASTACMD_BIN = get_abs_config_entry( $FASTACMD_BIN, $config_file );
	
	my $ok       = system("\"$FASTACMD_BIN\" -d dummy") >> 8 == 2;
	if ($ok) {
		print "OK   fastacmd program available at $FASTACMD_BIN\n";
	}
	else {
		print "FAIL fastacmd program not found at $FASTACMD_BIN\n";
	}
	return $ok;
}

sub checkBlastDB {

	my $FASTACMD_BLASTDB = $config{'resource.blastDb'};
	$FASTACMD_BLASTDB = get_abs_config_entry( $FASTACMD_BLASTDB, $config_file );
		
	my $ok       = -r $FASTACMD_BLASTDB.".nin" || -r $FASTACMD_BLASTDB.".nal";
	if ($ok) {
		print "OK   blast database $FASTACMD_BLASTDB found\n";
	}
	else {
		print "FAIL blast database $FASTACMD_BLASTDB not found or could not be read\n";
	}
	return $ok;
}

sub checkCCDS {

	my $CCDS_FILE = $config{'resource.ccdsFile'};
	$CCDS_FILE = get_abs_config_entry( $CCDS_FILE, $config_file );
	
	my $ok       = -e $CCDS_FILE && -f $CCDS_FILE && -r $CCDS_FILE;
	if ($ok) {
		print "OK   ccds file $CCDS_FILE found\n";
	}
	else {
		print "FAIL ccds file $CCDS_FILE not found or could not be read\n";
	}
	return $ok;
}

sub checkMasterSNP {

	my $MASTER_SNP_FILE  = $config{'resource.masterSnpFile'};
	$MASTER_SNP_FILE  = get_abs_config_entry( $MASTER_SNP_FILE,  $config_file );
	
	my $ok       = -e $MASTER_SNP_FILE && -f $MASTER_SNP_FILE && -r $MASTER_SNP_FILE;
	if ($ok) {
		print "OK   master variation file $MASTER_SNP_FILE found\n";
	}
	else {
		print "FAIL master variation file $MASTER_SNP_FILE not found or could not be read\n";
	}
	return $ok;
}

sub checkModule {
	my ($module) = @_;
	if ( system("perl -M$module -e 1") >> 8 == 0 ) {
		print "OK   $module found\n";		
	}
	else {
		print "FAIL $module doesn't seem to be installed\n";
		if ($cpan) {
			print "Trying to install $module using cpan...\n";
			if ( system("cpan $module") >> 8 == 0 ) {
				print "OK   $module installed\n";		
			}			
			else {
				print "FAIL $module install failed. Try to install manually.\n";
				exit(1);
			}
		}		
	}

}

sub get_abs_config_entry {
	my ( $entry, $abs_base ) = @_;
	if ( File::Spec->file_name_is_absolute($entry) ) {	 
		return $entry;
	}	
	my ( $base_vol, $base_dir, $base_file ) = File::Spec->splitpath($abs_base);
	my ( $entry_vol, $entry_dir, $entry_file ) = File::Spec->splitpath($entry);
	my $catdir = File::Spec->catdir( $base_dir, $entry_dir );
	my $retval = File::Spec->catpath( $base_vol, $catdir, $entry_file );	
	return $retval;
}
