#!/bin/bash

# Command-line parameters:
	cachedir=$1
shift;	dir=$1
shift;	exec=$1
shift;	jrv_i=$1
shift;	jrv_s=$1
shift;	lim=$1
shift;	log=$1
shift;	master=$1
shift;	mkdir=$1
shift;	nodes=$1
shift;	nth=$1
shift;	opts=$1
shift;	pcs=($1)
shift;	rjrv=$1
shift;	rm=$1
shift;	robust=$1
shift;	scache=$1
shift;	usecache=$1
shift;	verbosity=$1
shift;	wait=$1

# Other variables:
ls="/bin/ls"		# The common alias ls='ls --color' causes problems
alone="RJRVSINGLE"
jrv="$JR_HOME/jrv/jrv"
nopara="RJRVDONTPARALLEL"
worker="$JR_HOME/rjrv/worker"
wstr="2jr$|^javac?$|^jr?go[tx]?$|^jr[ct]?$|run$"



if [ $robust -eq 1 ]; then
	endl=""
	declare -i pos=0

	if [ $verbosity -ge 0 ]; then
		endl="\n"
		echo -e "\nConnecting to the workers..."
	fi

	while [ $pos -lt $nodes -a $pos -lt ${#pcs[*]} ]; do
		pc=${pcs[$pos]}
		$wait $lim ssh $opts $pc date &> /dev/null

		if [ $? -ne 0 ]; then
			pcs[$pos]=""
			pcs=(${pcs[*]})
		else
			pos+=1
			echo -n "."
		fi
	done

	echo -e "$endl"
fi



cd $dir
$mkdir $cachedir
pcs=(${pcs[*]:0:$nodes})
declare -i L1=0 L2=0 nodes=${#pcs[*]}

first="."
second="."
cache="$cachedir/n$nodes-t$nth"

if [ $usecache -eq 0 ]; then
	nodirs=`find . -mindepth 2 -maxdepth 2 -name Script 2> /dev/null | grep -v "/\." | cut -d'/' -f2`
	files=`$ls -l | grep -v "$nodirs" | grep "^d" | sed 's, \+, ,g' | cut -d' ' -f8`
	files="$cache\n$files\n$master\n$rjrv\n$scache"

	latest=`$ls -ltd $(echo -e "$files") 2> /dev/null | head -2 | sed 's, \+, ,g' | cut -d' ' -f8`
	first=`echo $latest | cut -d' ' -f1`
	second=`echo $latest | cut -d' ' -f2`
fi

if [ $first = $cache -o $first = $scache -a $second = $cache -o -f $cache -a $usecache -eq 1 ]; then
	last=`tail -1 $cache`

	if [ "$last" = "$" ]; then
		L1=1
		L2=1

		if [ $usecache -eq 1 ]; then
			touch $cache $scache
		fi
	fi
elif [ $first = $scache -o -f $scache -a $usecache -eq 1 ]; then
	last=`tail -1 $scache`

	if [ "$last" = "$" ]; then
		L1=1

		if [ $usecache -eq 1 ]; then
			touch $scache
		fi
	fi
fi

if [ $usecache -eq -1 ]; then
	L1=0
	L2=0
fi








if [ $L1 -eq 0 ]; then
	if [ $verbosity -ge 0 ]; then echo "Searching for Script files..."; fi
	dont=`find . -name $nopara 2> /dev/null | grep -v "/\." | sed "s,/$nopara$,,g" | sort`

	if [ -z "$dont" ]; then
		leaves=`find . -name Script 2> /dev/null | grep -v "/\." | sed 's,/Script$,,g' | sort`
	else
		leaves=`find . -name Script 2> /dev/null | grep -v "/\." | grep -v "$dont" | sed 's,/Script$,,g' | sort`
	fi



	# Calculate the total work load:
	declare -a list=() nums=()
	declare -i big=0 ndirs=0 total=0

	for nodir in $dont; do
		declare -i sum=0
		others=`find $nodir -name Script 2> /dev/null | grep -v "/\." | sed 's,/Script$,,g'`
	
		for leaf in $others; do
			cmds=`grep -h "^[^#]" $leaf/Script | cut -d' ' -f2`
			work=`echo "$cmds" | egrep "$wstr" | wc -l`
			if [ $work -eq 0 ]; then work=1; fi

			sum+=$work
			ndirs+=1
		done

		list[$sum]="${list[$sum]}:$nodir"
		nums=(${nums[*]} $sum)
		total+=$sum
	done

	for leaf in $leaves; do
		tweak="$leaf/$alone"

		if [ -f $tweak ]; then
			work=999999999999
			big+=1
		else
			cmds=`grep -h "^[^#]" $leaf/Script | cut -d' ' -f2`
			work=`echo "$cmds" | egrep "$wstr" | wc -l`
			if [ $work -eq 0 ]; then work=1; fi
			total+=$work
		fi

		list[$work]="${list[$work]}:$leaf"
		nums=(${nums[*]} $work)
		ndirs+=1
	done
	nums=(`echo ${nums[*])} | sed 's, ,\n,g' | sort -nr | uniq`)



	declare -a new_list=()
	declare -i bins=${#nums[*]}-1
	for i in `seq 0 $bins`; do
		n=${nums[$i]}
		new_list[$i]="$n${list[$n]}:"
	done
	list=(${new_list[*]})

	$rm $scache
	echo "big: $big" >> $scache
	echo "ndirs: $ndirs" >> $scache
	echo "total: $total" >> $scache
	echo "list: ${list[*]}" >> $scache
	echo "$" >> $scache
else
	if [ $L2 -eq 0 -a $verbosity -ge 0 ]; then
		echo "Using the rjrv search cache."
	fi

	big=`grep "^big: " $scache | cut -d' ' -f2`
	ndirs=`grep "^ndirs: " $scache | cut -d' ' -f2`
	total=`grep "^total: " $scache | cut -d' ' -f2`
fi



declare -i max=$total/$(($nth*$nodes - $big))+1

if [ $L2 -eq 0 ]; then
	if [ $verbosity -ge 0 ]; then echo "Creating a balanced list of jobs..."; fi
	list=(`grep -h "^list" $scache | cut -d' ' -f2-`)
	declare -i bins=${#list[*]}-1
	$rm $cache

	# Generate the list of jobs:
	while [ -n "`echo ${list[*]} | sed 's, *,,g'`" ]; do
		leaves=()
		new_list=(${list[*]})
		declare -i total=0 new_total

		for i in `seq 0 $bins`; do
			item=${list[$i]}
			n=`echo $item | cut -d: -f1`
			leaf=`echo $item | cut -d: -f2`
			new_total=$total+$n

			while [ -n "$item" -a $new_total -le $max -o $total -eq 0 ]; do
				total=$new_total
				item=`echo $item | sed -e "s,:$leaf:,:,g" -e "s,^$n:$,,g"`

				new_total=$total+$n
				leaves=(${leaves[*]} $leaf)
				leaf=`echo $item | cut -d: -f2`
			done

			new_list[$i]=$item
			if [ -z "$item" ]; then bins+=-1; fi
			if [ $total -ge $max ]; then break; fi
		done

		list=(${new_list[*]})
		echo "$total ${leaves[*]}" | sed 's, ,:,g' >> $cache
	done

	echo "$" >> $cache
elif [ $verbosity -ge 0 ]; then
	echo "Using the rjrv job list cache."
fi



declare -a pids=()
declare -a list=(`head -n -1 $cache`)
declare -i iter=0 length=${#list[*]} pos=0
astr="Initializing remote threads on $nodes machines..."
vstr="\nmax = $max\nnodes = $nodes\nwork = $total\nStart Directory: $dir\n\n"

if [ $verbosity -ge 0 ]; then echo "$astr"; fi
if [ $verbosity -ge 1 ]; then echo -e "$vstr"; fi

# Break the work up among the machines:
while [ $pos -lt $length ]; do
	for pc in ${pcs[*]}; do
		file="$pc.$iter"
		total=`echo ${list[pos]} | cut -d: -f1`
		leaves="`echo ${list[pos]} | cut -d: -f2- | sed 's,:, ,g'`"
		list[pos]=""
		pos+=1

		if [ $exec -eq 1 ]; then
			cmd="$worker $dir $jrv \"$jrv_i\" \"$jrv_s\" \"$leaves\" $log/$file"
			ssh $opts $pc $cmd &
			pids=(${pids[*]} $!)
		fi

		if [ $verbosity -ge 1 ]; then
			echo -e "\n$pc work=$total $leaves"
		else
			echo -n "."
		fi

		if [ $pos -eq $length ]; then break; fi
	done

	iter+=1
done








# Now wait for all the threads to finish:
echo
me=`whoami`
prev=$length
declare -i alive=-1 dots
astr="Waiting for all remote threads to finish..."
if [ $verbosity -ge 0 ]; then echo "$astr"; fi

while [ $alive -ne 0 ]; do
	alive=0
	new_pids=()
	ps=`ps -o pid -u $me | grep -v PID | sed 's, *,,g'`

	for pid in ${pids[*]}; do
		if [ -n "`echo -e \"$ps\" | grep \"^$pid$\"`" ]; then
			alive+=1
			new_pids=(${new_pids[*]} $pid)
		fi
	done

	dots=$prev-$alive
	pids=(${new_pids[*]})
	prev=$alive

	if [ $dots -ne 0 ]; then
		echo -n $(seq 1 $dots)" " | sed 's,[0-9]\+ ,.,g'
	fi
done

echo
