#!/bin/bash
# Author: Jan Stepanek

version='1.2.1'

if [ -z "$SGE_ROOT" ] || [ ! -d "$SGE_ROOT" ] ; then
    echo "SGE_ROOT is not set, this machine does not seem to be a SGE cluster queue manager!" >&2
    exit 66
fi

btred='/net/data/ufalhome/common/exec/runbtred'
pack_size=15
job_name=$USER-$$
tmp=/tmp
work="$HOME"/.jtred$$
sleep=0.05
outdir="$work"/o
errdir="$work"/e
sge_priority=-25

function usage {
    cat <<-__USAGE
	Usage:
	  ${0##*/} [-jB btred ] [-js packet-size] [-jn job-name]
            [-jS sleep-interval] [-jt lrc-tmp-dir] [-jw work-dir] [-jq] [-jo sge-option=value]*
            [-jp sge-priority] { -l file-list | file... }
            -jb btred-options...
	Defaults:
	    btred           $btred
	    packet-size     $pack_size
	    job-name        $job_name
	    sleep-interval  $sleep
	    tmp-dir         $tmp
	    sge-priority    $sge_priority
	    work-dir        $work
	  -jq shows only btred messages.
	  -jo is great for -q='*@*&!overloaded-host'
	Do not enter any files nor file-lists after -jb.
	Do not use wildcards in filelists.
	__USAGE
}

# remove temp files on break
trap '
  echo INT-TERM-KILL trapped >&2
  qdel "$job_name".$$.\*
  rm -f "$tmp"/"$job_name".$$.????
  rm -rf "$outdir"
  rm -rf "$errdir"
  rmdir "$work"
  exit 
  ' INT TERM KILL

# show usage if no parameters given
if (( ${#@} == 0 )) ; then
    usage
    exit 67
fi

# parse options
quiet=0
file_i=0 # index to file array
while ((${#@})) ; do
    option=''
    if [[ ! ${1:0:3} =~ ^-(j[BsnSltwbopq]|l) ]] ; then
        file[$((file_i++))]=$1 # not an option, thus a file
    elif [[ $1 == -jq ]] ; then
        quiet=1
    elif (( ${#1} > 3 )) || [[ $1 == -l?* ]]; then
        idx=2
        if [[ $1 == -l?* ]] ; then
            idx=1
        fi
        option=${1:$((idx++)):1}
        value=${1:$idx}
    else
        idx=2
        if [[ $1 == -l ]] ; then
            idx=1
        fi
        option=${1:$idx}
        shift
        value=$1
    fi
    case $option in 
        B) btred=$value ;;
        s) pack_size=$((value)) ;;
        n) job_name=$value ;;
        S) sleep=$value ;;
        l) filelist=$value ;;
        t) tmp=$value ;;
        w) work=$value ;;
        o) value=${value/=/ }; sge_options+=($value) ;;
        p) sge_priority=$value ;;
        b) break ;; # following options go to btred
    esac
    shift
done

# check whether we can proceed
if  (( ! $file_i )) && [[ ! -f $filelist || -z $filelist || ! -r $filelist ]] ; then
    echo Ivalid file-list. >&2
    exit 68
elif [[ $job_name =~ ^[0-9]|/ ]] ; then
    echo Invalid job name. >&2
    exit 69
elif (( pack_size <= 0 )) ; then
    echo Invalid packet-size. >&2
    exit 70
elif [[ ! -x "$btred" ]] ; then
    echo Cannot run btred: "$btred" >&2
    exit 71
elif ((sge_priority >= 0)) || ((sge_priority < -1023)) ; then
    echo "Invalid priority $sge_priority (highest -1 >= int >= lowest -1023)" >&2
    exit 74
fi

if ( [[ ! -d $outdir ]] && ! mkdir -p "$outdir" ) || [[ ! -w $outdir ]]; then
    echo Cannot access tmp $outdir >&2
    exit 72
fi
if ( [[ ! -d $errdir ]] && ! mkdir -p "$errdir" ) || [[ ! -w $errdir ]]; then
    echo Cannot access tmp $errdir >&2
    exit 73
fi

# Quoting
btred_flags=("$@")
for i in `seq 0 $(( ${#btred_flags[@]}-1 ))`; do
    btred_flags[i]=${btred_flags[i]//"'"/"'"'"'"'"'"'"'"}
    btred_flags[i]="'${btred_flags[i]}'"
done

function mute () {
    if (( ! $quiet )) ; then
        cat 1>&2
    fi
}

renice 10 $$ | mute
# prepare btred scripts
(
    if (( ${#file} )) ; then
        # list all files, quote special chars
        ls --quoting-style=shell "${file[@]}"
    fi
    if [[ $filelist ]] ; then
        dir=$(readlink -f $filelist)
        dir=${dir%/*}
        while read -r line ; do # -r prevents '\' from evaluation
            if [[ ${line:0:1} != / ]] ; then
                # convert relative path to absolute FROM the filelist dir
                line="$dir/$line"
            fi
            ls --quoting-style=shell "$line" # quote special chars
        done < "$filelist"
   fi # list all files from filelist
    ) | \
        xargs -d'\n' -n$pack_size echo 'hostname >&2 ; renice 10 $$>/dev/null;. /net/work/projects/perl_repo/admin/bin/setup_platform;'"'$btred'" "${btred_flags[@]}" | \
        split -a4 -l1 - "$tmp"/"$job_name".$$.
# give $pack_size files to one line, prepend command and split into scripts

# run scripts
for script in "$tmp"/"$job_name".$$.???? ; do
    qsub -S /bin/bash -cwd -V -p $sge_priority -o "$outdir"/"${script##*/}".o -e "$errdir"/"${script##*/}".e "${sge_options[@]}" "$script" \
        | mute
    sleep $sleep;
done;

eval echo Waiting for jobs to finish... | mute
while qstat -r -j "$job_name".$$.'*' > /dev/null 2>&1; do sleep 2 ; done

# send stderr of scripts to stderr and stdout of them to stdout
cat "$errdir"/"$job_name".$$.????.e >&2 &
cat "$outdir"/"$job_name".$$.????.o >&1 &
wait

# remove temp data
rm -f "$tmp"/"$job_name".$$.????
rm -rf "$outdir"
rm -rf "$errdir"
rmdir "$work"
