package SPARCplug;

use strict;
use Data::Dumper;

our $maxNumberProcesses = 6;
our @cmdList            = ();
our %processList        = ();
our %usedDirectories	= ();
our $tmpDirPrefix		= "SPARCplugTmpDir";

sub queue_cmds {
	my $cmd = shift();
	my $inputFile = shift();
	my $label = shift();
	my $log = shift();

	push @cmdList, {cmd=>$cmd, inputFile=>$inputFile, label=>$label, log=>$log};
	print "Queued process $label\n";
	start_subps();
}

sub start_subps {

	while ($#cmdList ne -1
		&& $maxNumberProcesses gt scalar keys(%processList) )
	{
		my ($dir, $wdir);
		foreach $_ (1..$maxNumberProcesses) {
			if (!defined $usedDirectories{$_}){
				$dir = $_;
				last;
			}
		}
		$wdir = "${tmpDirPrefix}/${dir}";
		system("mkdir -p ${wdir}");
		my $cmdEntry = shift(@cmdList);
		my $cmd = "( cp $$cmdEntry{inputFile} ${wdir}; cd ${wdir}; $$cmdEntry{cmd} )";
		$cmd .= " >>  $$cmdEntry{log} 2>&1" if defined($$cmdEntry{log}) && $$cmdEntry{log} ne "";
		system("echo '$cmd' > $$cmdEntry{log}");
#		printf "CMD: $cmd\n";
		my $pid = fork();
		die "Fork failed $!" unless defined $pid;
		if ( !$pid ) {
			exec $cmd;
		}
		$usedDirectories{$dir} = $pid;
		$processList{$pid} = $cmdEntry;
		print "Process $pid started in ${wdir}: $$cmdEntry{label}\n";
		printf "Process list: %d queued, %d running\n",
			  scalar @cmdList,
			  scalar keys(%processList) if $#cmdList ne -1;
		
	}
}

sub wait_for_subps {
	my $pid;
	$pid = 0;
	while ( $pid != -1 ) {
		$pid = wait();
		if ( $pid ne -1 ) {
			my $cmdEntry = $processList{$pid};
			print "Process $pid finished: $$cmdEntry{label}\n";
			delete $processList{$pid};
			foreach my $dir (1..$maxNumberProcesses) {
				delete $usedDirectories{$dir} if defined $usedDirectories{$dir} && $usedDirectories{$dir} eq $pid;
			}
			
			printf "Process list: %d queued, %d running\n",
			  scalar @cmdList,
			  scalar keys(%processList)if $#cmdList eq -1;
			start_subps();
		}
	}
}

sub test_parallelProcessing {
	queue_cmds("date;sleep 2;date;","sleeper1 2 seconds","");
	queue_cmds("date;sleep 3;echo `date`>test.dat;","sleeper1 3 seconds","log");
	queue_cmds("date;sleep 4;date;","sleeper1 4 seconds");
	queue_cmds("sleep 5","sleeper1 5 seconds");
	queue_cmds("sleep 6","sleeper1 6 seconds");
	queue_cmds("sleep 2","sleeper1 2 seconds");
	queue_cmds("sleep 3","sleeper1 3 seconds");
	queue_cmds("sleep 4","sleeper1 4 seconds");
	wait_for_subps();
	print "Naechste Runde\n";
	queue_cmds("sleep 1","sleeper2 1 seconds");
	queue_cmds("sleep 2","sleeper2 2 seconds");
	queue_cmds("sleep 3","sleeper2 3 seconds");
	queue_cmds("sleep 4","sleeper2 4 seconds");
	queue_cmds("sleep 2","sleeper2 2 seconds");
	queue_cmds("sleep 2","sleeper2 2 seconds");
	queue_cmds("sleep 2","sleeper2 2 seconds");
	queue_cmds("sleep 2","sleeper2 2 seconds");
	wait_for_subps();
}
#test_parallelProcessing();
1;
