#!/usr/bin/perl
#
# Common scenario running functions
# Bryan Horling - Jun 2004
# ##################################################################

# ###
# Note: this script assumes you have passwordless ssh logins enabled
# from the originating server (the one you run this script on) to 
# a collection of other servers (the ones specified by @AGENT_HOSTS).
# This script uses ssh to spawn remote plugins and agents on those
# hosts to distribute the load of the simulation.  You should change
# the @AGENT_HOSTS array to specify your set of local machines, and
# ensure that the farm package is available on those machines at the
# same location (e.g. it exists at /home/<username>/research/farm or
# similar)
# ###

# Agent hosts. ** You will need to edit this **
#@AGENT_HOSTS = (ogma, angus, dino, crush, otho, tiamat, ramses, narsil, qed, mulan, mas8);
@AGENT_HOSTS = (localhost);	# Use this to run everything locally

# Simulator host, the machine it will be run from
$SIMULATOR_HOST = `uname -n`; chomp($SIMULATOR_HOST);

# Set to something if property owners are to be used
$PROPOWNERS = "";

# Additional plugin arguments, if any
#$PLUGARGS = "-host $SIMULATOR_HOST -fw -ap";
$PLUGARGS = "-host $SIMULATOR_HOST";

### Temp stuff for property distribution analysis
if ($ARGV[0] == 0) {
	#$PROPOWNERS = "-propertyowners ../propertyowners.txt";
} elsif ($ARGV[0] == 1) {
	# Nothing
} elsif ($ARGV[0] == 2) {
	$PLUGARGS = "-host $SIMULATOR_HOST -gw";
} elsif ($ARGV[0] == 3) {
	$PLUGARGS = "-host $SIMULATOR_HOST -gw -ap";
} elsif ($ARGV[0] == 4) {
	$PLUGARGS = "-host $SIMULATOR_HOST -gr";
} elsif ($ARGV[0] == 5) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fr";
} elsif ($ARGV[0] == 6) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fr -ap";
} elsif ($ARGV[0] == 7) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fw";
} elsif ($ARGV[0] == 8) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fw -ap";
} elsif ($ARGV[0] == 9) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fw -rp";
} elsif ($ARGV[0] == 10) {
	$PROPOWNERS = "-propertyowners ../bandit/propertyowners.txt";
	$PLUGARGS = "-host $SIMULATOR_HOST -rp";
} elsif ($ARGV[0] == 11) {
	$PLUGARGS = "-host $SIMULATOR_HOST -fr -rp";
}
print "Running simulation $ARGV[0]\n..."; 
shift @ARGV if ($ARGV[0] =~ /^\d+$/);
$PLUGARGS .= " " . join(" ", @ARGV);
### End temp stuff

# The intended remote X display
$DISPLAY="$SIMULATOR_HOST:13.0";
#$DISPLAY=$ENV{'DISPLAY'};

# Find the farm directory
$FARM_DIR  = `pwd`; chomp($FARM_DIR);
$FARM_DIR =~ s/$ENV{'HOME'}\/*//;
$FARM_DIR =~ s/\/[^\/]*$//;
print $FARM_DIR
# Find the home directory
$HOME_DIR = $ENV{'HOME'};

# Get the java cmd from the makefile
$JAVA=`make runjava`; chomp($JAVA);
$JAVA .= " ";

# The Metagents.  Adjust NUM_AGENTS to control how many metagents are
# spawned, and the AGENTS assignment line to control which metagent
# is used.  The format is $AGENTS{"<java arguments>"} = "<run path>";
%AGENTS = ( );

# The plugins.  Add new plugins to this list as needed.  The format
# is roughly the same as the agents above.
%PLUGINS = ( );

# Locally run plugins.  These will be run on the local machine,
# instead of being propogated to remote hosts.
%LOCALPLUGINS = ( );

# Simulator.  This is used to spawn the simulator.
%SIMULATORS = ( );

# Kill the simulator.  This is used to kill the simulator.
%KILLSIMULATORS = (
	"farm.generic.plugins.drivers.KillDriver -host $SIMULATOR_HOST" => "$FARM_DIR/simulator"
);

###################################################################
# You shouldn't need to change anything below this line
###################################################################

sub run {
    if ($ARGV[0] eq "kill") {
	killscenario();
    } else {
	runscenario();
    }
}

###################################################################
###################################################################

sub runscenario {

	# Run the registry
	runregistry();
	sleep(1);

	# Run the simulator
	print " running simulator...\n";
	foreach $key (keys %SIMULATORS) {
		if (fork()) { runsim($SIMULATORS{$key}, $key); }
	}
	sleep(3);	# Assumes the simulator can be up and
			# running in 3 seconds, you may need
			# to adjust this (note: we need a better
			# way to solve this problem...)

	# Run the agents
	print " running metagents...\n";
	foreach $key (keys %AGENTS) {
		if (fork()) { runpluginlocal($AGENTS{$key}, $key); }
		else { $PLUGIN_HOST++; }
	}
	sleep(3);

	# Run the plugins
	print " running plugins...\n";
	foreach $key (keys %PLUGINS) {
	    if (fork()) { runpluginlocal($PLUGINS{$key}, $key); }
	    else { $PLUGIN_HOST++; }
	}
	foreach $key (keys %LOCALPLUGINS) {
		if (fork()) { runpluginlocal($LOCALPLUGINS{$key}, $key); }
		else { $PLUGIN_HOST++; }
	}
}

sub killscenario {

	foreach $key (keys %KILLSIMULATORS) {
		runpluginlocal($KILLSIMULATORS{$key}, $key, 1);
	}

	foreach $host (@AGENT_HOSTS) {
		if (fork()) { remotecmd($host, "", "killall -q -9 java"); }
	}
}

###################################################################
###################################################################

# Run the registry
sub runregistry {
	my $PSREG = `ps auxww | grep rmiregistry | grep -v grep`;
	if ($PSREG eq "") {
		print " running registry...\n";
		system("make registry");
	}
}

# Run the simulator locally
sub runsim {
	local($dir, $class, $exit) = @_;

	local $cmd = $JAVA . $class;

	localcmd($dir, $cmd, $exit);
	#remotecmd($SIMULATOR_HOST, $dir, $cmd, $exit);
}

# Run a plugin locally
sub runpluginlocal {
	local($dir, $class, $exit) = @_;

	local $cmd = $JAVA . $class;

	localcmd($dir, $cmd, $exit);
}

# Run a plugin remotely
sub runpluginremote {
	local($dir, $class, $exit) = @_;

	local $cmd = $JAVA . $class;

	remotecmd($AGENT_HOSTS[$PLUGIN_HOST % @AGENT_HOSTS], $dir, $cmd, $exit);
}

# Do a local command
sub localcmd {
	($dir, $cmd, $exit) = @_;
	$NAME = "/tmp/runfarm.$$." . rand();
	chomp($host);

	# Write out the command
	open (FILE, "> $NAME");
	print FILE "cd $HOME_DIR\n";
	print FILE "cd $dir\n";
	print FILE "$cmd\n";
	close FILE;

	# Run the command
	print "local > $cmd\n";
	$CMD = "bash $NAME";
	system ($CMD);
	unlink $NAME;
	exit unless $exit;
}

# Do a remote command
sub remotecmd {
	($host, $dir, $cmd, $exit) = @_;

	$NAME = "/tmp/runfarm.$$." . rand();
	chomp($host);

	# Write out the command
	open (FILE, "> $NAME");
	print FILE "ssh -T -X -Y $host bash <<EOF\n";
	# run bash when you ssh to remote. But the script itself is run within bash
	print FILE "export DISPLAY=$DISPLAY\n";
	print FILE "cd $dir\n";
	print FILE "pwd\n";
	print FILE "$cmd\n";
	print FILE "EOF\n";
	close FILE;

	# Run the command
	print "**remote $cmd\n";
	$CMD = "bash $NAME";
	system ($CMD);
#	system("ssh -T -X -Y $host \"cd $dir;$cmd\"");
	
	print "**remote DONE $cmd\n";
	#system ("cat $NAME");

	unlink $NAME;
	exit unless $exit;
}
