#!/usr/bin/bash
#
# NAME
#
#  reconbatchjobs
#
# SYNOPSIS
#
#  reconbatchjobs logfile cmdfile1 [cmdfile2 ...]
#
# DESCRIPTION
#
#  reconbatchjobs is a worker-bee for the recon-all script, to
#  support running multiple instances of a binary (ie running
#  in parallel).  The main hurdles to running recon-all binaries
#  in parallel is making sure to get the return code, and to
#  buffer the log files (otherwise, if the output of parallel jobs
#  are simultaneously sent to the log file, then the log file
#  becomes an interleaved mess).
#
#  reconbatchjobs takes at least two arguments.  The first is the
#  filename to which command output should be appended when the
#  command (job) is finished.
#  The next argument(s) are files containing the command string
#  to execute.
#  For example usage, look in the recon-all script in the 'multi-strip'
#  section of the skull-strip stage.
#
#  Note: the commands are assumed to be independent of each other,
#  and a dependency chain is not supported (and so commands that need
#  to run in sequence should be handled by the caller, eg. recon-all)
#
# Original Author: Nick Schmansky
#
# Copyright © 2021 The General Hospital Corporation (Boston, MA) "MGH"
#
# Terms and conditions for use, reproduction, distribution and contribution
# are found in the 'FreeSurfer Software License Agreement' contained
# in the file 'LICENSE' found in the FreeSurfer distribution, and here:
#
# https://surfer.nmr.mgh.harvard.edu/fswiki/FreeSurferSoftwareLicense
#
# Reporting: freesurfer@nmr.mgh.harvard.edu
#
#

if [ $# -lt 2 ] ; then
  echo "Usage: reconbatchjobs logfile cmdfile1 [cmdfile2 ...]"
  echo "See recon-all script for examples."
  exit 1
fi

MAIN_LOG_FILE=$1

# launch jobs found in command files (shift past first logfile arg).
# job output goes to a logfile named after the command file, which
# later gets appended to MAIN_LOG_FILE
PIDS=()
LOGS=()
shift
for cmd in $*; do
  JOB=`cat $cmd`
  LOG=$cmd.log
  echo "" >& $LOG
  echo " $JOB" >> $LOG
  echo "" >> $LOG
  exec $JOB >> $LOG 2>&1 &
  PIDS=(${PIDS[@]} $!)
  LOGS=(${LOGS[@]} $LOG)
  rm -f $cmd
done

# wait till all processes have finished
PIDS_STATUS=()
for pid in "${PIDS[@]}"; do
  echo "Waiting for PID $pid of (${PIDS[@]}) to complete..."
  wait $pid
  PIDS_STATUS=(${PIDS_STATUS[@]} $?)
done

# now append their logs to the main log file
for log in "${LOGS[@]}"
do
  cat $log >> $MAIN_LOG_FILE
  rm -f $log
done

echo "PIDs (${PIDS[@]}) completed and logs appended."

# and check for failures
for pid_status in "${PIDS_STATUS[@]}"
do
  if [ $pid_status != 0 ] ; then
      exit 1
  fi
done

exit 0
