#!/usr/bin/perl -w

use     Getopt::Long;
use 	File::Basename;

#globals
my $config_file;
my $session_file;
my %config;
my $rc = 0;
my $pid;

$rc = init();
if ($rc) {
    exit $rc;
}

$rc = pvfs_tmpdir("create", $config{'WORKINGDIR'});

#make ionodefile, compnodefile
$rc = create_nodefiles(\%config);
if ($rc) {
    print "returning $rc\n";
    exit($rc);
}

$rc = create_pvfs2config(\%config);
if ($rc) {
    print "returning $rc\n";
    exit($rc);
}

#make pvfstab
$rc = create_pvfs2tab(\%config);
if ($rc) {
    print "returning $rc\n";
    exit($rc);
}

#copy binaries in
if ($config{'COPYBINS'} > 0) {
    $rc = copy_pvfsbinaries(\%config);
    if ($rc) {
       print "returning $rc\n";
       exit($rc);
    }
}

#make session file
$rc = create_sessionfile(\%config);
if ($rc) {
	print "could not create sessionfile\n";
	exit($rc);
}

#$rc = pvfs_tmpdir("remove", $config{'WORKINGDIR'});
#@foo = @{$config{'IONODES'}};
#print "FOO: @foo\n";

exit(0);

# local staging: copy from source to working directory
sub copy_pvfsbinaries {
    my $href = shift;

    foreach $prog ($href->{'SERVER'}, $href->{'PINGPROG'}) {
	if (-f "$prog") {
	    $cmd = "cp -f $prog " . $href->{'WORKINGDIR'};
	    $rc = system("$cmd");
	    if ($rc) {
		print STDERR "ERROR: copying file with command: '$cmd'\n";
		return(1);
	    }
	    system ("$cmd");
	} else {
	    print STDERR "ERROR: no such file $prog found, check configs\n";
	    return(1);
	}
    }
    return(0);
}

sub create_nodefiles {
    my $href = shift;

    my $ofile = $href->{'WORKINGDIR'} . "/ionodes";

    if (!open(FH, ">$ofile")) {
	print STDERR "ERROR: cannot open file: $ofile\n";
	return(2);
    }

    my @ionodes = @{$href->{'IONODES'}};
    foreach $node (@ionodes) {
	print FH "$node\n";
    }

    close(FH);

    $ofile = $href->{'WORKINGDIR'} . "/metanodes";

    if (!open(FH, ">$ofile")) {
	print STDERR "ERROR: cannot open file: $ofile\n";
	return(2);
    }

    my @metanodes = @{$href->{'MGR'}};
    foreach $node (@metanodes) {
	print FH "$node\n";
    }

    close(FH);

    $ofile = $href->{'WORKINGDIR'} . "/compnodes";

    if (!open(FH, ">$ofile")) {
	print STDERR "ERROR: cannot open file: $ofile\n";
	return(1);
    }

    my @compnodes = @{$href->{'COMPNODES'}};
    foreach $node (@compnodes) {
	print FH "$node\n";
    }

    close(FH);
    return(0);
}

sub create_pvfs2config 
{
    my $href = shift;
    my $conffile = $href->{'WORKINGDIR'} . "/fs.conf";
    my $ioservers = '';
    my $metaservers = '';
    my $rc = -1;

    foreach $server (@{$href->{'IONODES'}}) {
    	if ($ioservers ne "") {
		$ioservers .= ",";
	}
	$ioservers .= $server;
    }
    foreach $server (@{$href->{'MGR'}}) {
    	if ($metaservers ne "") {
		$metaservers .= ",";
	}
	$metaservers .= $server;
    }

    my $cmd = $href->{'GENCONFIG'} 
    		. " --protocol " . $href->{'PROTOCOL'};
    foreach (split(',', $href->{'PROTOCOL'})) {
	my $big = $_;
	$big =~ y/a-z/A-Z/;
	my $var = "PVFS" . $big . "PORT";
	$cmd .= " --" . $_ . "port " . $href->{$var};
    }
    $cmd       .= " --ioservers ". $ioservers
		. " --metaservers " . $metaservers
		. " --logfile "  . $href->{'SERVERLOG'} . "/pvfs2.log"
		. " --storage "  . $href->{'STORAGE'}
		. " --trove-method " . $href->{'TROVEMETHOD'}
		. " --quiet "    . $conffile;
    if ($href->{'TROVESYNC'} == 0) {
    	$cmd .= " --notrovesync";
    }

    $rc = system($cmd);
    return $rc;
}

sub create_pvfs2tab {
    my $href = shift;

    my $ofile = $href->{'WORKINGDIR'} . "/pvfs2tab";
    
    my @metas = @{$href->{'MGR'}};

    if (!open(FH, ">$ofile")) {
	print STDERR "ERROR: cannot open file: $ofile\n";
	return(1);
    }
    my $pvfstab = "undefined pvfstab\n";
    my $protocol = $href->{'PROTOCOL'};

    # maybe change the encoding
    my $mntopts = "defaults";
    if (defined($href->{'ENCODING'})) {
	$mntopts = "encoding=" . $href->{'ENCODING'};
    }

    # string looks like this:
    # tcp://localhost:3334/pvfs2-fs /mnt/pvfs pvfs2 defaults 0 0

    my $num = 0;
    $pvfstab = "";
    foreach (split(',', $href->{'PROTOCOL'})) {
	my $big = $_;
	$big =~ y/a-z/A-Z/;
	my $var = "PVFS" . $big . "PORT";
	++$num;
	if ($num > 1) {
	    $pvfstab .= ",";
	}
	$pvfstab .= "$_://" . $metas[0] . ":" . $href->{$var} . "/pvfs2-fs";
    }

    $pvfstab .= " " .  $href->{'MOUNTPOINT'} .  " pvfs2 $mntopts 0 0";
    
    print FH "$pvfstab\n";
    
    close(FH);
    return(0);
}

sub usage {

    print<<EOF;
Usage: $prog_name [option]
-c -config        configuration file for PAV to use
-r -root          path to program root (default ./)
-m -machinefile   file with list of available nodes
-n -ionodecount   number of nodes to use for IO
-h -help          display this message
EOF
}

sub init {
    GetOptions(\%args,
	       'c|config:s',
	       's|session:s',
	       'sd|sessiondir:s',
	       'r|root:s',
	       'm|machinefile:s',
	       'n|ionodecount:i',
	       'e|metacount:i',
	       'h|help'
	       );

    $prog_name = $0;
    $pid = $$;

    if ($args{'h'}) {
	usage();
	return(1);
    }

    %config = ('PVFSTCPPORT' => 7000,
               'PVFSGMPORT' => 6,
               'PVFSIBPORT' => 3334,
	       'WORKINGDIR' => "/tmp",
	       'IONCOUNT' => 4,
	       'METACOUNT' => 1,
	       'NODEFILE' => machine_file,
	       'PROTOCOL' => 0,
	       'UNIQUEMETA' => 0,
	       'STORAGE' => "/tmp/data",
	       'SERVERLOG' => "/tmp/log",
	       'MOUNTPOINT' => "/pvfs_auto",
	       'BINDIR' => "/tmp/bin",
	       'SERVER' => "pvfs2-server",
	       'PINGPROG' => "pvfs2-ping",
	       'GENCONFIG' => "pvfs2-genconfig",
	       'TROVESYNC' => 1,
	       'TROVEMETHOD' => "dbpf",
	       'COMPUTENODES_LAST' => 1,
	       'PROGROOT' => "./",
	       'COPYBINS' => 0
	       );
    
    ($config{'USERNAME'}) = getpwuid($>);
    my ($gid) = split(/\s*/, $();
    ($config{'GROUPNAME'}) = getgrgid($gid);

    $config{'PROGROOT'} = $args{'r'} || real_dir($0) || $config{'PROGROOT'};
    my $prog_root = $config{'PROGROOT'};
    require "$prog_root/pav_lib.pl";


    if ($args{'s'} || $args{'sd'}) {
	if ($args{'s'}) {
	    $session_file = $args{'s'};
	} elsif ($args{'sd'}) {
	    $session_file = $args{'sd'} . "/pvfs_autosession";
	}

	if (!-f $session_file) {
	    print STDERR "ERROR: cannot find session file: $session_file\n";
	    return(1);
	}
	
	$rc = read_sessionfile($session_file, \%config);

	if ($rc) {
	    print STDERR "ERROR: cannot read session file\n";
	    return(1);
	}
    } elsif ($args{'c'} || -f "~/pav.conf") {
	
	$config_file = $args{'c'} || "~/pav.conf";
	if (!-f $config_file) {
	    print STDERR "ERROR: cannot find config file: $config_file\n";
	    usage();
	    return(1);
	}    

	$rc = read_configfile($config_file, \%config);
	if ($rc) {
	    print STDERR "ERROR: reading config file\n";
	    return(1);
	}

	# override with command line options
	$config{'IONCOUNT'} = $args{'n'} || $config{'IONCOUNT'};
	$config{'METACOUNT'} = $args{'e'} || $config{'METACOUNT'};

	$rc = split_machines(\%config);
	if ($rc) {
	    return($rc);
	}


    } else {
	print STDERR "ERROR: must specify -c, -s, -sd or creat a default config file (~/pav.conf)\n";
	usage();
	return(1);
    }

    $config{'PROGROOT'} = $args{'r'} || $config{'PROGROOT'};
    $config{'NODEFILE'} = $args{'m'} || $config{'NODEFILE'};

    # backward compatibility
    if (defined($config{'PVFSPORT'})) {
	$config{'PVFSTCPPORT'} = $config{'PVFSPORT'};
    }
    
    return(0);
}

sub pvfs_tmpdir {
    my $mode = shift;
    my $dir = shift;
    my $rc;

#    $dir .= ".$pid";

    if ($mode eq "create") {
	$cmd = "mkdir -p $dir";
    } elsif ($mode eq "remove") {
	$cmd = "rm -rf $dir";
    }

    $rc = system("$cmd");

    if ($rc) {
	print STDERR "ERROR: running command '$cmd': rc=$rc\n";
	return(1);
    }

    return(0);
}


sub split_machines {
    my $href = shift;

    my @nodelist = (),
    @ionodes = (),
    @metanodes = ();
    @compnodes = ();
    @servernodes = ();

    my $count=0;

    # let's try something....if for whatever reason we cannot open NODEFILE,
    # let's assume it had one entry: localhost

    if (!open(FH, $href->{'NODEFILE'})) {
	print STDOUT "WARNING: cannot open nodefile $href->{NODEFILE}\n";
	print STDOUT "WARNING: using default 'localhost'\n";
	$count++;
	@nodelist = ("localhost");
    } else {

	    while(<FH>) {
		chomp;
		if (/^#/ || !$_) {
		    next;
		}
		my $line = $_;

		@nodelist = (@nodelist, $line);	
		$count++;
	    }
	    close(FH);
    }

    # decide how many total servers there will be
    if ($href->{'UNIQUEMETA'}) {
	$servernum = $href->{'IONCOUNT'} + $href->{'METACOUNT'};
    } else {
	# if servers are not unique, choose enough to satisfy larger of meta
	# or io requirement
	if ($href->{'METACOUNT'} >= $href->{'IONCOUNT'}) {
	    $servernum = $href->{'METACOUNT'};
	} else {
	    $servernum = $href->{'IONCOUNT'};
	}
    }

    if ($count < $servernum) {
	print STDERR "ERROR: requested more server nodes than are available\n";
	return(1);
    }

    my $ionum = $href->{'IONCOUNT'};
    my $metanum = $href->{'METACOUNT'};
    my $compnum = $count - $servernum;

    # split total set into servers and clients
    if ($href->{'COMPUTENODES_LAST'}) {
	@servernodes = @nodelist[0..($servernum-1)];
	@compnodes = @nodelist[$servernum..($count-1)];
    } else {
	@compnodes = @nodelist[0..($compnum-1)];
	@servernodes = @nodelist[$compnum..($count-1)];
    }

    # pick meta nodes 
    @metanodes = @servernodes[0..($metanum-1)];

    # pick io nodes
    if ($href->{'UNIQUEMETA'}) {
	@ionodes = @servernodes[$metanum..($servernum-1)];
    } else {
	@ionodes = @servernodes[0..($ionum-1)];
    }

    $href->{'MGR'} = \@metanodes;
    $href->{'IONODES'} = \@ionodes;
    $href->{'COMPNODES'} = \@compnodes;

    return(0);
}

sub real_dir {
   my ($file, $reldir, $suffix) = fileparse(shift);
   my ($realdir, $envpwd);

   if ($reldir =~ /^\//) {
      $realdir = $reldir;
   } else {
      if (!$ENV{PWD}) {
         chomp($envpwd = `pwd`);
      } else {
         $envpwd = $ENV{PWD};
      }
      $realdir = $envpwd . "/$reldir";
   }
   $realdir .= '/';
   $realdir =~ s#/./#/#g;
   $realdir =~ s#//#/#g;
   return($realdir);
}
