#!/usr/bin/perl
use strict;
$|=1;

# window to the stars (WTTS) installer for Linux/Mac

# currently text only : but I will work on that ;)

# requires: perl, cp, wget, unzip (standard stuff!) etc.

# V0.04 04/12/2011

# current directory
my $pwd=$ENV{'PWD'};
my $ppwd=parentdir($pwd);

# current path
my $path=$ENV{'PATH'};

# root URL for WTTS files
my $rooturl='http://www.astro.uni-bonn.de/~izzard/code/wtts';

# home directory
my $home=$ENV{'HOME'};

# wget : or similar program to get stuff from the web
my $wget='/usr/bin/wget -c';# -nc -c';

# other commands : these are standard locations, but yours 
# may be a little different (so you'll need to edit this!)
my $unzip='/usr/bin/unzip';
my $cp='/bin/cp';
my $rm='/bin/rm';
my $gmake='/usr/bin/make';
my $cmake='/usr/bin/cmake';
my $nohup='/usr/bin/nohup';

# temporary directory, make it and go there
# NB this should be /tmp/...
my $tmp='/tmp/wtts_installer';
makedir($tmp);
openlog($tmp);
changedir($tmp);
welcome();

my $ncpus=ncpus();

# get perl version : crude!
my $perlv;
my $perl5lib;
{
    my $x=execcmd('perl -v');
    if($x=~/This is perl, v(\S+) /)
    {
	$perlv=$1;
    } 
    elsif($x=~/v(\d+\.\d+\.\d+)/)
    {
	$perlv=$1;
    }
    else
    {
	Dprint("Failed to determine perl version\n",1);
	exit;
    }
}

$perl5lib=make_perl5lib($perlv);

Dprint("Perl5lib $perl5lib\n",0);

# output directories
my $bindir=$ENV{'HOME'}.'/bin';
my $answer=question("You need to choose a binary ('executable') directory - where should it be? (must be in your \$PATH) [$bindir]");
$bindir=$answer if(defined($answer));
Dprint("bindir=$bindir\n",0);

my $datadir=$ENV{'HOME'}.'/wtts';
$answer=question("Where would you like to install WTTS and TWIN data files? [$datadir]");
$datadir=$answer if(defined($answer));
Dprint("datadir=$datadir\n",0);

# append this to $perl5lib
$perl5lib.=":$datadir";

# determine fortran compiler
my $fort=determine_default_fortran_compiler();
$answer=question("What is your fortran compiler? [$fort]");
$fort=$answer if(defined($answer));
Dprint("fort=$fort\n",0);

map
{
    $_=checkdir($_);
    makedir($_);
}($bindir,$datadir);

Dprint("WTTS bin directory : $bindir\n",1);
Dprint("WTTS data file directory : $datadir\n",1);
Dprint("Fortran compiler : $fort\n",1);

# get rob's modules, unzip them, find the .pm files
Dprint("Getting WTTS perl modules ... \n",1);
my $mod;
foreach $mod ('rob_misc','STARS')
{
    unlink "$mod.zip";
    execcmd("cd $tmp; $wget $rooturl/$mod\_perl_module.zip -O $mod.zip");
    if(-s "$tmp/$mod.zip" < 100)
    {
	Dprint("Failed to get $mod perl module from $rooturl/$mod\_perl_module.zip - OOPS\n",1);
	exit;
    }
    execcmd("cd $tmp; $unzip -o $mod.zip");
    execcmd("cd $tmp; $cp $mod/lib/$mod.pm $datadir");
}

# Check for Perl modules
Dprint("Checking for required Perl modules from CPAN...\n",1);

# note that File::Copy and File::Basename are included in Perl 5.8.8 by default
# (but in older Perls ...???? )
my %modules=(#'1 ExtUtils::PkgConfig','http://search.cpan.org/CPAN/authors/id/R/RM/RMCFARLA/Gtk2-Perl/ExtUtils-PkgConfig-1.07.tar.gz',
	     '1 ExtUtils::PkgConfig','http://search.cpan.org/CPAN/authors/id/T/TS/TSCH/ExtUtils-PkgConfig-1.12.tar.gz',

	     #'2 ExtUtils::Depends','http://search.cpan.org/CPAN/authors/id/R/RM/RMCFARLA/Gtk2-Perl/ExtUtils-Depends-0.205.tar.gz',
	     '2 ExtUtils::Depends','http://search.cpan.org/CPAN/authors/id/F/FL/FLORA/ExtUtils-Depends-0.304.tar.gz',
	     
	     #'3 Glib','http://search.cpan.org/CPAN/authors/id/T/TS/TSCH/Glib-1.120.tar.gz',
	     '3 Glib','http://search.cpan.org/CPAN/authors/id/X/XA/XAOC/Glib-1.241.tar.gz',
	     
	     #'4 Gtk2','http://search.cpan.org/CPAN/authors/id/T/TS/TSCH/Gtk2-1.122.tar.gz',
	     '4 Gtk2','http://search.cpan.org/CPAN/authors/id/X/XA/XAOC/Gtk2-1.241.tar.gz',

	     # do we need this?
	     #'5 Gtk2::Gdk::Keysyms','http://search.cpan.org/CPAN/authors/id/T/TS/TSCH/Gtk2-1.122.tar.gz',
	     #'5 Gtk2::Gdk::Keysyms','http://search.cpan.org/CPAN/authors/id/T/TS/TSCH/Gtk2-1.181.tar.gz',

	     '6 File::Tail','http://search.cpan.org/CPAN/authors/id/M/MG/MGRABNAR/File-Tail-0.99.3.tar.gz',
	     '7 File::Copy','',
	     '8 File::Basename','',
	     
	     #'9 Compress::Zlib','http://www.cpan.org/modules/by-module/Compress/Compress-Zlib-1.14.tar.gz',
	     '9 Compress::Zlib','http://search.cpan.org/CPAN/authors/id/P/PM/PMQS/IO-Compress-2.044.tar.gz',

	     #'10 File::Which','http://search.cpan.org/CPAN/authors/id/P/PE/PEREINAR/File-Which-0.05.tar.gz',
	     '10 File::Which','http://search.cpan.org/CPAN/authors/id/A/AD/ADAMK/File-Which-1.09.tar.gz',

	     #'11 Archive::Zip','http://search.cpan.org/CPAN/authors/id/A/AD/ADAMK/Archive-Zip-1.18.tar.gz',
	     '11 Archive::Zip','http://search.cpan.org/CPAN/authors/id/A/AD/ADAMK/Archive-Zip-1.30.tar.gz',

	     '12 Gtk2::TrayIcon','http://search.cpan.org/CPAN/authors/id/B/BO/BORUP/Gtk2-TrayIcon-0.06.tar.gz',
	     '13 Proc::ProcessTable','http://search.cpan.org/CPAN/authors/id/D/DU/DURIST/Proc-ProcessTable-0.45.tar.gz'
	     );

for my $mod (sort {$a<=>$b} keys(%modules))
{
    my $url=$modules{$mod};
    $mod=~s/^\d+\s+//;
    Dprint("Check module $mod\n",1);
    my $x=execcmd("env PERL5LIB=$perl5lib perl -M$mod -e1 2>\&1");

    Dprint($x,1);

    if($x=~/Can\'t locate (\S+) in/)
    {
	my $y=$1;
	Dprint("Cannot locate requried $y\n",1);
	$y=~s/\.pm$//;
	Dprint("Please install $y before continuing: see CPAN http://search.cpan.org/search?query=$y&mode=all\n",1);
	if(defined($url))
	{
	    my $answer=question( "I could try to install for you from $url - would you like me to try? (y/N)\n");
	    if($answer=~/^[yY]$/)
	    {
		$answer=question("Would you like to install globally (as root) or locally (as you)?\n (g/L)");


		if($answer=~/^[gG]$/)
		{
		    # install globally
		    my $w=execcmd('whoami');
		    chomp $w;
		    if($w ne 'root')
		    {
			Dprint("To install perl modules globally you must be root - please log in as the superuser and then run this script again, or install the perl modules as a local user (see http://www.astro.uni-bonn.de/~izzard/code/wtts/INSTALL).\n",1);
			exit;
		    }
		    Dprint("OK, trying ... \n",1);
		    # this *should* install the module, provided there are not other problems
		    # such as missing dependencies
		    $url=~m!.*/(\S+)\.tar\.gz$!;
		    my $modname=$1;
		    my $modgz="$1.tar.gz";
		    execcmd("cd $tmp; $wget $url; tar -xzf $modgz; cd $tmp/$modname; perl Makefile.PL; make; make install");
		}
		else
		{
		    # install locally
		    $url=~m!.*/(\S+)\.tar\.gz$!;
		    my $modname=$1;
		    my $modgz="$1.tar.gz";
		    my $prefix="$home/lib/perl";
		    unlink $modgz;
		    Dprint("Installing locally (prefix $prefix)\n",1);
		    execcmd("cd $tmp; $wget $url; tar -xzf $modgz; cd $tmp/$modname; env PERL5LIB=$perl5lib PREFIX=$prefix perl Makefile.PL PREFIX=$prefix; env PERL5LIB=$perl5lib PREFIX=$prefix make; env PERL5LIB=$perl5lib PREFIX=$prefix make install");
		}

		# test if the installation failed
		 my $x=execcmd("env PERL5LIB=$perl5lib perl -M$mod -e1 2>\&1");
		
		if($x=~/Can\'t locate (\S+) in/)
		{
		    Dprint("Installation of the module failed! Sorry :(\n",1);
		    Dprint("If you're trying to install Glib(2) or Gtk(2), please install the appropriate glib-devel, glib2-devel, Gtk-devel, Gtk2-devel package as well\n",1);
		    exit;
		}
	    }
	    else
	    {
		Dprint("OK - but you must install the $y module manually for WTTS to work!\n",1);
		exit;
	    }
	}
    }
}

Dprint("You seem to have the required Perl modules\n",1);

# check for gnuplot
{
    my $r=`gnuplot --version`;
    my $v;
    if($r=~/gnuplot (\S+) patchlevel (\S+)/)
    {
	$v=$1.'.'.$2;
    }
    elsif($r=~/gnuplot (\S+)/)
    {
	$v=$1;
    }
    else
    {
	print "Could not deterine gnuplot version : do you have it installed in your \$PATH ?\n";
	exit;
    }
    print "Found gnuplot version $v\n";
    if($v<4.4)
    {
	print "Please install the latest gnuplot (at least V4.4!)\n";
	exit;
    }
}

# check for make and cmake
{
    if(`make --version`=~/GNU Make (\S+)/)
    {
	print "Found GNU Make version $1\n";
    }
    else
    {
	print "Could not determine GNU Make version : do you have it installed?\d\n";
	exit;
    }
      if(`cmake --version`=~/cmake version (\S+)/)
    {
	print "Found cmake version $1\n";
    }
    else
    {
	print "Could not determine cmake version : do you have it installed?\d\n";
	exit;
    }
}

# get stars.perlscript
Dprint("Getting stars perlscript...\n",1);
unlink 'stars.perlscript';
execcmd("cd $tmp; $wget $rooturl/stars.perlscript");
checkfile("$tmp/stars.perlscript");
execcmd("cd $tmp; $cp stars.perlscript $bindir/stars.pl");
chmod 0755, "$bindir/stars.pl";

# make wtts executor script
my $exec_script="$bindir/wtts";
if((-e $exec_script) && (-d $exec_script))
{
    # already exists (due to dodgy directory naming set by the user) try this
    $exec_script="$bindir/runwtts";
}

if(-e $exec_script)
{
    Dprint("Warning : exec script already exists! I will try to overwrite...\n",1);
}

open(FP,">$exec_script")||die;
print FP "\#!/bin/bash
env PERL5LIB=$perl5lib $nohup $bindir/stars.pl webserver=0 histograms=0 TWINroot=$datadir evcoderoot=$datadir vb=0 \$\@ >/dev/null 2>/dev/null
";
close FP;
chmod 0755, $exec_script;

# get TWIN, build with $fort (do this in the data dir)
Dprint("Getting TWIN\n",1);
unlink 'TWIN.zip';
execcmd("cd $tmp; $wget $rooturl/TWIN.zip");
checkfile("$tmp/TWIN.zip");
execcmd("cd $tmp; $cp TWIN.zip $datadir");
changedir( $datadir);
execcmd("cd $datadir; $unzip -o TWIN.zip");
Dprint("Making TWIN, please wait...\n",1);
execcmd("cd $datadir; mkdir -p build; cd build; $cmake ..; $gmake clean; $gmake FORT=$fort -j$ncpus");

# done, clean up, go back to PWD
Dprint("Finished\n",1);
changedir($pwd);
execcmd("$rm -rf $tmp");

Dprint("Window To The Stars should now be installed\nTry it with the command $exec_script\n",1);

exit;

sub changedir
{
    my $d=shift;
    chdir $pwd;
    chdir $d;
    `cd $pwd; cd $d`;
    my $p=`pwd`; chomp $p;
    Dprint("Change to dir $d (`pwd` =$p ; ENV PWD=".$ENV{'PWD'}.")\n",0);
}

sub makedir
{
    my $d=shift;
    chdir $pwd;
    mkdir $d;
}

sub question
{
    print $_[0],"\n";
    Dprint("Asking question \"$_[0]\"\n",0);
    my $x=<STDIN>;
    $x=~s/^\s+//o; $x=~s/\s+$//o;
    Dprint("Answer is \"$x\"\n",0);
    if($x ne '')
    {
	return $x;
    }
    else
    {
	return undef;
    }
}

sub checkdir
{
    my $d=shift;
    $d=~s!^./!$pwd/!;
    $d=~s!^../!$ppwd/!;
    $d=~s!//!/!go;
    return $d;
}

sub checkfile
{
    if(-s $_[0] < 100)
    {
	Dprint("Failed to get $_[0] from $rooturl/$_[0] - OOPS\n",1);
	exit;
    }
}

sub determine_default_fortran_compiler
{
    # somehow try to find a fortran compiler
    my $vb=0;
    
    my @fcompilers=('gfortran','ifort','g95','sunf95');

    # first, try to run the compiler to get version information
    foreach my $fc (@fcompilers)
    {
	my $x=execcmd("$fc -v 2>\&1");
	Dprint("$fc -v -> $x\n",1) if($vb);
	chomp $x;
	if((!($x =~/command not found/))&&(!($x=~/^\s*$/)))
	{
	    Dprint("Use $fc from version\n",1) if($vb);
	    return($fc);
	}
    }
    
    # try whereis
    foreach my $fc (@fcompilers)
    {
	my $x=execcmd("whereis -b $fc 2>/dev/null");
	$x=~s/$fc\://;
	chomp $x;
	Dprint("Whereis $fc -> $x\n",1) if($vb);

	if($x ne '')
	{
	    Dprint("Use $fc from whereis ($x)\n",1) if($vb);
	    return($fc);
	}
    }

    # try locate
    foreach my $fc (@fcompilers)
    {
	my $x=execcmd("locate $fc 2>/dev/null");
	chomp $x;
	if($x ne '')
	{
	    Dprint("Use $fc from locate\n",1) if($vb);
	    return($fc);
	}
    }

    Dprint("Failed to find any fortran compiler :( Please install one (e.g. @fcompilers ?)\n",1);

}

sub parentdir
{
    my $d=shift;
    $d=~s!(.*)/.*!$1!;
    return $d;
}

sub execcmd
{
    # use backticks to execute cmd
    my $cmd=shift;
    Dprint("Exec: \"$cmd\" (`pwd` = ".`pwd`." ENV PWD=".$ENV{'PWD'}.")\n",0);
    my $result=`$cmd`;
    Dprint("Command result \"$result\"\n",0);
    return $result;
}

sub Dprint
{
    # debug print string $s to logfile
    my $s=shift;
    my $screen=shift; # if true, output to the screen as well 
    print LOG $s;
    print STDOUT $s if($screen);
}

sub openlog
{
    # open log file
    my $tmp=shift;
    open(LOG,">/tmp/wtts_installer.log")||die("cannot open $tmp/wtts_installer.log logfile for output : please check $tmp exists\n");

    # output (perhaps) useful information
    print LOG
"
Start WTTS installer log at ".time()."
pwd=$pwd
ppwd=$ppwd
path=$path
rooturl=$rooturl
home=$home
wget=$wget
unzip=$unzip
cp=$cp
rm=$rm
gmake=$gmake
cmake=$cmake
nohup=$nohup
";

    # force flushing
    my $old_fh = select(LOG);
    $| = 1;
    select($old_fh);
}

sub make_perl5lib
{
    my $v=shift;
    my $h="$home/lib/perl";
    my $p5l=
	"$h/lib/perl5/site_perl/$v:$h/share/perl/$v:$h/$v";
    
    return $p5l;

}

sub welcome
{
    Dprint("Welcome to the Window To The Stars (WTTS) installer
(for Linux and Mac)

This script tries to install WTTS for you. However, every system
is different so it may fail. In the event of failure, please

1) Check the WTTS website http://www.astro.uni-bonn.de/~izzard/window.html
2) Check the FAQ http://www.astro.uni-bonn.de/~izzard/window-FAQ.html
3) Email Rob Izzard (see the website for current email address) and attach the file /tmp/wtts_installer.log 

Note that if you use Micro\$oft Windows you should consult the instructions
at http://www.astro.uni-bonn.de/~izzard/window-WTTS32.html and NOT use this
installer.

At questions you are usually given options, e.g. y/N. The default (which
will be activated if you just press 'return') is in upper case or in square brackets [..].

",1);
}


sub ncpus
{
    # count number of cpus or return 1
    my $n=0;
    my $cpufile='/proc/cpuinfo';
    if(-f $cpufile)
    {
	open(CPU_COUNT,'<'.$cpufile);
	while(<CPU_COUNT>)
	{
	    $n++ if(/processor/o);
	}
	close CPU_COUNT;
    }
    
    Dprint("Found $n CPUs\n",0);
    
    if($n>0)
    {
	return $n;
    }
    else
    {
	return 1;
    }
}
