#!/bin/bash
#===========================================================
# rds - ReminD run Status
#===========================================================
# description: rds is a shell script that provides  
#   information about REMIND1.6 runs (e.g. run name, algo,
#   iterations, run status and job ID)
# author: Jerome Hilaire
# email: hilaire@pik-potsdam.de
# history:
#   - 2015-04-17: Update Nash output (now includes 
#     modelstat information)
#   - 2015-04-02: Bug fix for defic sum display in Negishi 
#     (for # iteration > 12)           
#   - 2015-01-14: Debugging Nash mode
#   - 2014-09-25: Code cleaning and debugging
#   - 2014-09-18: Updated Nash run status, 2 digit iteration 
#   - 2014-09-17: Bug fix
#   - 2014-09-11: More information for Nash runs
#   - 2014-09-09: Adding legend information. Updated nash
#     and negishi display. Display info about last 4 iter
#     in negishi
#   - 2014-09-04: Adding options help (show help) and 
#     pattern (apply grep [pattern] on folder list).
#   - 2014-09-02: Check last iteration status, provide more
#     info when run failed
#   - 2014-08-25: Adding p80_defic_sum info
#   - 2014-08-22: Update (using bash function for printing,
#     adding Hard Wall Clock limit case)
#   - 2014-08-15: Creation
#===========================================================
# TODO:
#  - export parameters: s_cnptfile, s05_inic_switch, o_modelstat, sol_itr, iteration, cm_iteration_max, 
#  - flexible output: choose what you want to display
#  - select between converged, failed and stopped runs
#  - read folders only

#-- Initialisation -----------------------------------------
# Debug mode
declare debug
debug=0

# Variables
declare    optalgo   # Name of the optimisation algorithm
declare    iter
declare    sol
declare    usr
declare    jobid
declare    jobstat
declare -i f_check_jobList
declare -i f_check_runStarted
declare -i f_check_runStopped
# Negishi only
declare -i maxiter   # Maximum algorithm iterations
declare -i maxsolit  # Maximum solution iterations
declare -a last_itr  # Algorithm iterations
declare -a last_sol  # Solution iterations
declare -a last_mos  # Model status
declare -a list_lastIterInfo   #
declare -i nbop
declare -i nblo
declare -i nbub
declare -i nbin
declare -i nbli
declare -i nbii
declare -i nbno
declare -i laop
declare -i lalo
declare -i laub
declare -i lain
declare -i lali
declare -i laii
declare -i lano
declare    defic
# Nash only
declare    lastiter
declare    conv_nash
declare    failmkt

# Functions
function printline() {

  declare -a argAry=("${!2}")

  printf "\e[1$1m%-4s"          "${argAry[0]}"
  printf "\e[1$1m%-40s"         "${argAry[1]}"
  printf "\e[1$1m%-12s"         "${argAry[2]}"
  printf "\e[1$1m%7s"           "${argAry[3]}"
  printf "\e[1$1m%7s"           "${argAry[4]}"
  printf "\e[1$1m%12s"          "${argAry[5]}"
  printf "\e[1$1m%15s"          "${argAry[6]}"
  printf "\e[1$1m%-60s\e[0m\n"  "${argAry[7]}"

}

function showhelp() {
  echo "rds - ReminD run Status"
  echo " "
  echo "rds [options] [path]"
  echo " "
  echo "options:"
  echo "-h,                show brief help"
  echo "-d,                debug mode"
  echo "-l,                show legend information"
  echo "-p,                specify pattern to apply on folders list"
  exit 0
}

function showlegend() {
  fmt_header=";30;107"
  items=("#" "Run name" "Optim." "Iter." "Sol." "Stat." "Defic sum" "  Run status")
  printline $fmt_header items[@]
#  items=("1" "2" "3" "4" "5" "6" "7" "  8")
#  printline $fmt_header items[@]
  echo " "

  echo "1 (#)         : Run ID"
  echo "2 (Run name)  : Run name (corresponding to the folder name, limited to 39 characters)"
  echo "3 (Optim.)    : Optimisation algorithm: negishi, nash or testoneregi"
  echo "4 (Iter.)     : Last algorithm iteration"
  echo "5 (Sol.)      : [negishi only] Last solution iteration"
  echo "6 (Stat.)     : [negishi only] Information on the last 4 negishi iterations (both algorithm and solution iterations (see below)."
  echo "7 (Defic sum) : [negishi only] Value of the defic sum in the last iteration"
  echo "8 (Run status): Status of the run"
  
  echo " "
  printf '\e[1;42;37m%1s\e[0m' "-"
  printf '\e[1m%17s\e[0m' " Locally Optimal / "
  printf '\e[1;44;37m%1s\e[0m' "-"
  printf '\e[1m%11s\e[0m' " Unbounded / "
  printf '\e[1;45;37m%1s\e[0m' "-"
  printf '\e[1m%20s\e[0m' " Locally Infeasible / "
  printf '\e[1;41;37m%1s\e[0m' "-"
  printf '\e[1m%11s\e[0m' " Infeasible / "
  printf '\e[1;43;37m%1s\e[0m' "-"
  printf '\e[1m%25s\e[0m\n' " Intermediate Non-Optimal"
  echo "Additional information:"
  echo " - Numbers indicate negishi/nash iterations."
  echo " - When a negishi iteration requires X solution iterations, the same number is displayed X times"
  echo " "
  printf '\e[1;4m%s\e[0m\n' "Example:"
  printf '\e[1;45m%1s\e[0m' "2"
  printf '\e[1;43m%1s\e[0m' "2"
  printf '\e[1;42m%1s\e[0m' "3"
  printf '\e[1;42m%1s\e[0m\n' "4"
  exit 0
}

function check_modelCompilation() {
  # This function returns 1 if the model has been compiled 
  # properly by checking if full.gms exists in the run 
  # directory
  
  local -i out=0
  
  # Check existence of full.gms
  if [[ -e "$1/full.gms" ]] 
  then
    out=1
  else
    out=0
  fi
  
  echo $out
  
  exit $out
  
}

function check_jobList() {
  # This function checks if a directory (argument 1) belongs
  # to a list of queue jobs
  case $debug in
    1) echo "  > Entering check_jobList(). Input value=$1"
  esac
  
  local -i out
  local line

  #line=`printf '%s\n' "${arr[@]}" | grep -n $1 | cut -d ':' -f1`
  if [[ ${#list_wd[@]} -ne 0 ]] 
  then
    case $debug in
      1) echo "    > Listing values in job list:"
    esac
    ok=0
    for (( i = 0; i < ${#list_wd[@]}; i++ ))
    do
      tst=$(echo "${list_wd[$i]}" | grep $1 | cut -d ':' -f2 | sed "s/ //")
      case $debug in
        1) echo "      - $(basename $tst)"
      esac
      if [[ "$tst" != "" ]]
      then
        if [[ $(basename $tst) == $1 ]]
        then
          ok=1
          break
        fi
      fi
    done
  else
    case $debug in
      1) echo "    > Job list is empty."
    esac
    ok=0
  fi

  if [[ $ok -eq 1 ]]
  then
    out=1
  else
    out=0
  fi
  
  f_check_jobList=$out
  
  case $debug in
    1) echo "  > Exiting check_jobList(). Output value=$out"
  esac

}

function check_runStarted() {
  # This function checks if a run has started by
  # looking at the existence of full.log and 
  # the existence of the statement 
  # "Starting REMIND..." in it
  case $debug in
    1) echo "  > Entering check_runStarted(). Input value=$1"
  esac
  
  local -i out
  
  if [[ -e $1/full.log && -e $1/full.lst && -e $1/log.txt ]]
  then
  
    case $debug in
      1) echo "    > full.log, full.lst and log.txt exist."
    esac
    
    line=$(grep "Starting REMIND..." $1/log.txt)
    if [[ "$line" != "" ]]
    then
      case $debug in
        1) echo "    > 'Starting REMIND...' has been found!"
      esac
    
      out=1
    else
      case $debug in
        1) echo "    > 'Starting REMIND...' has not been found!"
      esac
      
      out=0
    fi
  else
    case $debug in
      1) echo "    > one of the files full.log, full.lst and log.txt does not exist."
    esac
    
    out=0
  fi  
  
  export f_check_runStarted=$out
  
  case $debug in
    1) echo "  > Exiting check_runStarted(). Output value=$out"
  esac
}

function check_runStopped() {
  # This function checks if a run has stopped properly
  # by checking the existence of the proper statements 
  # in full.log and log.txt
  case $debug in
    1) echo "  > Entering check_runStopped(). Input value=$1"
  esac
  
  local -i out
  
  f_remindStop=$(grep "REMIND run finished!" $1/log.txt)
  f_jobstop=$(tail -1 $1/full.log | grep "Stop" | cut -d ' ' -f4)
  
  if [[ "$f_remindStop" != "" ]]
  then
    out=1
    if [[ "$f_jobstop" == "Stop" ]]
    then
      out=2
    fi
  else
    out=0
  fi
  
  f_check_runStopped=$out
  
  case $debug in
    1) echo "  > Exiting check_runStopped(). Output value=$out"
  esac
}

function check_solverStatus() {

  local -i out
  local solve
  
  solve=$(grep "*** SOLVE aborted" $1/full.log | wc -l)
  
  if [[ $solve -eq 0 ]]
  then
    out=1
  else
    out=0
  fi
  
  echo $out

}

function check_memoryError() {
  
  local -i out
  local mem
  
  mem=$(grep "*** Out of Memory" $1/log.txt | wc -l)
  
  if [[ $mem -eq 0 ]]
  then
    out=1
  else
    out=0
  fi
  
  echo $out

}

function get_optimAlgo() {
  # This function fetches the name of the optimisation
  # algorithm used in a REMIND run.
  
  optalgo=$(grep "setGlobal optimization" $1/full.gms | cut -d ' ' -f4)
  
  echo $optalgo
  
  exit 0
}

function get_maxIterInfo_negishi() {
  # This function get the values of maximum iterations
  # defined in full.gms
  
  maxiter=$(grep "cm_iteration_max =" $1/full.gms | cut -d '=' -f2 | cut -d';' -f1 | sed 's/ //')
  maxsolit=$(grep "cm_sol_itr_max   =" $1/full.gms | cut -d '=' -f2 | cut -d';' -f1 | sed 's/ //')

}

function get_maxIterInfo_nash() {
  # This function get the values of maximum iterations
  # defined in full.gms
  case $debug in
    1) echo "  > Entering get_maxIterInfo_nash(). Input value=$1"
  esac
  
  maxiter=`grep "cm_iteration_max =" $1/full.gms | awk "NR == 2" | cut -d '=' -f2 | cut -d';' -f1 | sed 's/ //'`

  case $debug in
    1) echo "  > Exiting get_maxIterInfo_nash(). Output value=$maxiter"
  esac
  }

function get_iterInfo_negishi() {

  local -i nbelts
  local -i liicnt

  # Get number of iterations: Locally Optimal, Locally Infeasible and Intermediate Non-Optimal 
  IFS=$'\n'
  list_itr=$(grep -E "L O O P S.*iteration" $1/full.lst | sed "s/L O O P S//g" | sed "s/^ *//g" | cut -d' ' -f2)
  list_sol=$(grep -E "\      sol_itr [0-9]" $1/full.lst | sed "s/^ *//g" | cut -d' ' -f2)
  list_mos=$(grep "MODEL STATUS" $1/full.lst | awk 'NR > 3'| sed "s/\*\*\*\* //" | sed 's/MODEL STATUS//g' | sed 's/^ *//g')
  unset IFS
  
  # Get information on the last iterations
  list_lastIterInfo=("")
  nbelts=$(printf '%s\n' "${list_mos[@]}" | wc -l)
  if [[ "$nbelts" != "" ]]
  then
    lastitr=$(($nbelts-3<0?1:$nbelts-3))
    liicnt=0
    for (( i = $lastitr ; i <= $nbelts ; i++ ))
    do  
      cur_itr=$(printf '%s\n' "${list_itr[@]}" | awk "NR == $i")
      cur_sol=$(printf '%s\n' "${list_sol[@]}" | awk "NR == $i")
      cur_mos=$(printf '%s\n' "${list_mos[@]}" | awk "NR == $i")
      list_lastIterInfo[$liicnt]="${cur_itr}.${cur_sol}.${cur_mos}"          
      liicnt=$(expr $liicnt + 1)
    done
  fi
  
  # Get last iteration number (iteration and sol_itr)
  iter=$(printf '%s\n' "${list_itr[@]}" | tail -1)
  if [[ "$iter" == "" ]]; then iter="0"; fi;
  sol=$(printf '%s\n' "${list_sol[@]}" | tail -1)
  if [[ "$sol" == "" ]]; then sol="?"; fi;
  
  # Get number of Locally Optimal, Locally Infeasible ... 
  nbop=$(printf '%s\n' "${list_mos[@]}" | grep "1 Optimal" | wc -l | sed 's/ //')
  nblo=$(printf '%s\n' "${list_mos[@]}" | grep "2 Locally Optimal" | wc -l | sed 's/ //')
  nbub=$(printf '%s\n' "${list_mos[@]}" | grep "3 Unbounded" | wc -l | sed 's/ //')
  nbin=$(printf '%s\n' "${list_mos[@]}" | grep "4 Infeasible" | wc -l | sed 's/ //')
  nbli=$(printf '%s\n' "${list_mos[@]}" | grep "5 Locally Infeasible" | wc -l | sed 's/ //')
  nbii=$(printf '%s\n' "${list_mos[@]}" | grep "6 Intermediate Infeasible" | wc -l | sed 's/ //')
  nbno=$(printf '%s\n' "${list_mos[@]}" | grep "7 Intermediate Nonoptimal" | wc -l | sed 's/ //')
  
  # Get model status in last iteration (cm_iteration or sol_itr) 
  laop=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "1 Optimal" | wc -c)
  lalo=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "2 Locally Optimal" | wc -c)
  laub=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "3 Unbounded" | wc -c)
  lain=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "4 Infeasible" | wc -c)
  lali=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "5 Locally Infeasible" | wc -c)
  laii=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "6 Intermediate Infeasible" | wc -c)
  lano=$(printf '%s\n' "${list_mos[@]}" | tail -1 | grep "7 Intermediate Nonoptimal" | wc -c)
  
}

function get_iterInfo_nash() {
 
  local -i nbelts
  local -i liicnt

  case $debug in
    1) echo "  > Entering get_iterInfo_nash(). Input value=$1"
  esac
 
  # Get number of iterations: Locally Optimal, Locally Infeasible and Intermediate Non-Optimal 
  IFS=$'\n'
  list_mos=$(grep "PARAMETER o_modelstat" $1/full.lst | tail -4 | cut -d' ' -f 26)
  unset IFS

  # Get information on the last iterations
  list_lastIterInfo=("")
  nbelts=$(printf '%s\n' "${list_mos[@]}" | wc -l)
  if [[ "$nbelts" != "" ]]
  then
    lastitr=$(($nbelts-3<0?1:$nbelts-3))
    liicnt=0
    for (( i = $lastitr ; i <= $nbelts ; i++ ))
    do
      cur_mos=$(printf '%s\n' "${list_mos[@]}" | awk "NR == $i")
      list_lastIterInfo[$liicnt]="${cur_mos}"
      liicnt=$(expr $liicnt + 1)
    done
  fi
 
  # Get last iteration number
  lastiter=$(grep LOOPS $1/full.log | cut -d' ' -f5 | awk "NR % 11 == 0" | tail -1)

  case $debug in
    1) echo "  > Exiting get_iterInfo_nash(). Output value=$lastiter"
  esac
}

function get_jobInfo() {
  
  #local -i line
  
  line=0
  cnt=1
  for (( i = 0; i < ${#list_wd[@]}; i++ ))
  do
    tst=$(echo "${list_wd[$i]}" | grep $1 | cut -d ':' -f2 | sed "s/ //")
    if [[ "$tst" != "" ]]
    then
      if [[ $(basename $tst) == $1 ]]
      then
        # Get job id from list of job ids and position computed in previous step
        jobid=$(echo "${list_jobid[$i]}"  | cut -d ':' -f2 | sed 's/ //')
        jobstat=$(echo "${list_stat[$i]}" | cut -d ':' -f2 | sed 's/ //')
        break
      fi
    fi
    cnt=$(expr $cnt + 1)
  done

  #line=$(printf '%s\n' "${list_wd[@]}" | grep -n $k | cut -d ':' -f1)

  # Get job id from list of job ids and position computed in previous step
  #jobid=$(printf '%s\n' "${list_jobid[@]}" | head -$line | tail -1 | cut -d ':' -f2 | sed 's/ //')
  #jobstat=$(printf '%s\n' "${list_stat[@]}" | head -$line | tail -1 | cut -d ':' -f2 | sed 's/ //')
  
}

function get_deficSum() {

  local defline
  local f_dispdefic
  local deficlast

  # Get defic sum information (take the "last" line before the display of pm_nw)
  defline=$(grep -n p80_defic_sum $1/full.lst | tail -1 | cut -d':' -f1)
  nwline=$(grep -n 'PARAMETER pm_nw' $1/full.lst | tail -1 | cut -d':' -f1)
  f_dispdefic=$(head -$defline $1/full.lst | tail -1 | grep "PARAMETER")

  # bugfix R1.7
  if [[ "$nwline" == "" ]]
  then
    nwline=$(grep -n 'PARAMETER p80_nw' $1/full.lst | tail -1 | cut -d':' -f1)
  fi

  if [[ "$f_dispdefic" != "" ]]
  then
    defline=$(expr $nwline - 3)
    defic=$(head -$defline $1/full.lst | tail -1 | sed "s/,    /\n/g" | tail -1 | tail -c+2 | sed "s/ //g" | tail -c12 )
  else
    defic="NA"
  fi

  # using new parameter introduced by RP if available
  deficlast=$(grep p80_defic_sumLast $1/full.lst | grep "\-\-\-\-" | tail -1)
  if [[ "$deficlast" != "" ]]
  then
    defic=$(echo "$deficlast" | cut -d'=' -f2 | cut -d't' -f1 | cut -d'T' -f1 | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
  fi

}

function get_deficSum_nash() {

  defic=$(grep "p80_defic_sum " $1/full.lst | tail -1 | cut -d'=' -f2 | cut -c1-13 | tr -d '[[:space:]]')

}

function check_conv_nash() {

  # Get Nash Solution Report
  # nsr_start=$(grep -nE "#### Nash Solution Report|####################################  Nash Solution Report" $1/full.lst | tail -1 | cut -d':' -f1)
  # nsr_lgth=45
  # IFS=$'\n'
  # full_nsr=$(tail +$nsr_start $1/full.lst | head -$nsr_lgth | cut -d' ' -f1,2 --complement | grep -v '^$')
  # unset IFS

  conv_nash=$(grep -n p80_messageFailedMarket $1/full.lst | awk "NR > 5" | cut -d':' -f1)

}

function get_failMarkets() {
  
  local conv
  
  conv=$(expr $conv_nash + 2)
  failmkt=$(tail +$conv $1/full.lst | head -1 | sed "s/pe/, pe/g" | sed "s/good/, good/g" | sed "s/ //g" | awk '{print substr($1,2)}')
}

# Check options
iflg=''
pattern=''
path=''

while getopts 'hlidfcp:' flag; do
  case "${flag}" in
    h) showhelp    ;;
    l) showlegend  ;;
    i) iflg='true' ;;
    d) debug=1 ;;
    c) cflg='true' ;;
    p) pattern="${OPTARG}" ;;
    *) error "Unexpected option ${flag}. Type 'rds -h' to get help." ;;
  esac
done

shift $(($OPTIND-1))

# Other printing functions
function printline_negishi() {

  declare -a argAry=("${!2}")
  declare -a iterAry=("${!3}")

  printf "\e[1$1m%-4s"          "${argAry[0]}"   # Run id
  printf "\e[1$1m%-40s"         "${argAry[1]}"   # Run name
  printf "\e[1$1m%-12s"         "${argAry[2]}"   # Negishi 
  printf "\e[1$1m%7s"           "${argAry[3]}"   # Negishi iterations
  printf "\e[1$1m%7s"           "${argAry[4]}"   # Solution iterations
  if [[ $# -gt 2 ]]
  then
    printf "%2s"          "  "
    cnter=0
    for (( i = 0 ; i < ${#iterAry[@]} ; i++ ))
    do
      cur_itr=$(echo "${iterAry[$i]}" | cut -d'.' -f1)
      cur_mos=$(echo "${iterAry[$i]}" | cut -d'.' -f3 | cut -d' ' -f1)
      if [[ $cur_itr -lt 10 ]]
      then
        case "${cur_mos}" in
          2) printf "\e[1;42;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          3) printf "\e[1;44;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          4) printf "\e[1;41;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          5) printf "\e[1;45;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          7) printf "\e[1;43;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          *) printf "\e[0m%2s\e[0m" "--"; cnter=$(expr $cnter + 1) ;;
        esac
      else
        case "${cur_mos}" in
          2) printf "\e[1;42;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          3) printf "\e[1;44;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          4) printf "\e[1;41;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          5) printf "\e[1;45;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          7) printf "\e[1;43;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
          *) printf "\e[0m%2s\e[0m" "--"; cnter=$(expr $cnter + 1) ;;
        esac
      fi
    done
    for (( i = $cnter ; i < 4 ; i++ ))
    do
      printf "\e[0m%2s"          " "
    done
    printf "\e[0m%2s"          "  "
  else
    printf "\e[0m%12s" "  --------  "
  fi
  printf "\e[1$1m%15s"          "${argAry[5]}" # defic sum
  printf "\e[1$1m%-60s\e[0m\n"  "${argAry[6]}" # Run status

}

function printline_nash() {

  declare -a argAry=("${!2}")
  declare -a iterAry=("${!3}")

  printf "\e[1$1m%-4s"          "${argAry[0]}"   # Run id
  printf "\e[1$1m%-40s"         "${argAry[1]}"   # Run name
  printf "\e[1$1m%-12s"         "${argAry[2]}"   # Negishi
  printf "\e[1$1m%7s"           "${argAry[3]}"   # Negishi iterations
  printf "\e[1$1m%7s"           "${argAry[4]}"   # Solution iterations
  if [[ $# -gt 2 ]]
  then
    printf "%2s"          "  "
    cnter=0
    for (( i = 0 ; i < ${#iterAry[@]} ; i++ ))
    do
      cur_itr=$(echo "${iterAry[$i]}" | cut -d'.' -f1)
      cur_mos=$(echo "${iterAry[$i]}" | cut -d'.' -f3 | cut -d' ' -f1)
      case "${cur_mos}" in
        2) printf "\e[1;42;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
        3) printf "\e[1;44;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
        4) printf "\e[1;41;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
        5) printf "\e[1;45;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
        7) printf "\e[1;43;37m%2s\e[0m" "$cur_itr"; cnter=$(expr $cnter + 1) ;;
      esac
    done
    for (( i = $cnter ; i < 4 ; i++ ))
    do
      printf "\e[0m%2s"          " "
    done
    printf "\e[0m%2s"          "  "
  else
    printf "\e[0m%12s" "  --------  "
  fi
  printf "\e[1$1m%15s"          "${argAry[5]}" # defic sum
  printf "\e[1$1m%-60s\e[0m\n"  "${argAry[6]}" # Run status

}

# Define formats
fmt_header=";30;107"  # black font colour, white background
fmt_conv=";32"        # green font colour
fmt_fail=";31"        # red font colour
fmt_run=";34"         # blue font colour
fmt_pend=";35"        # purple font colour

# Save current working directory
wd=`pwd`

# Select directory containing REMIND runs
if [[ $# -eq 0 ]]
then
  dir="."
  usr=$(pwd | cut -d'/' -f4)
else
  dir=$1
  usr=$(pwd | cut -d'/' -f4) # TODO: change pwd by the absolute path of $1
fi

# Save user jobs information
IFS=$'\n'
list_wd=($(llq -u $usr -l | grep "Initial Working Dir"))
list_jobid=($(llq -u $usr -l | grep "Job Name"))
list_class=($(llq -u $usr -l | grep "Class"))
list_stat=($(llq -u $usr -l | grep "Status"))
list_qtim=($(llq -u $usr -l | grep "Queue Date"))
list_etim=($(llq -u $usr -l | grep "Eligibility Time"))
list_dtim=($(llq -u $usr -l | grep "Dispatch Time"))
list_wchl=($(llq -u $usr -l | grep "Wall Clk Hard Limit"))
unset IFS


#== Process data ========================================
# Print header
items=("#" "Run name" "Optim." "Iter." "Sol." "Stat. " "Defic sum" "  Run status")
printline $fmt_header items[@] 

# Move to REMIND runs directory
cd $dir

# Get list of runs in current folder (apply pattern if required)
if [[ $pattern == "" ]]
then
  dirs=$(ls -d *)
else
  dirs=$(ls -d * | grep -E $pattern)
fi

# Loop over list of runs
mainloopcnt=1
for k in $dirs 
do
  # Initialise/Reinitialise variables
  line=""
  iter="?"
  sol="?"
  defic="NA"

  # Limit run name to the first 39 characters
  shortname=${k:0:39}

  # Has the model been compiled properly? (check: full.gms existence)
  if [[ $(check_modelCompilation $k) == "1" ]]
  then
    # Get optimisation algorithm
    optalgo=$(get_optimAlgo $k)

    # Select algorithm case
    case $optalgo in
    #----------------------------
    # Negishi case
    #----------------------------
      negishi)

        get_maxIterInfo_negishi $k    

        # Is the current run directory name in the jobs list?
        check_jobList $k
        if [[ f_check_jobList -eq 1 ]]
        then
          
          get_jobInfo $k

          # If the run has started...
          check_runStarted $k
          if [[ f_check_runStarted -eq 1 ]]
          then
            get_iterInfo_negishi $k
            get_deficSum $k

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  ($jobstat) $jobid")
            printline_negishi $fmt_run items[@] list_lastIterInfo[@]
          else

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "1.000" "  ($jobstat) $jobid")
            printline_negishi $fmt_pend items[@]
          fi

        # If the run has stopped...
        else
          # Has the run ever started ?
          check_runStarted $k
          if [[ f_check_runStarted -eq 1 ]]
          then
            # Has the job ended properly?
            check_runStopped $k
            if [[ f_check_runStopped -ge 1 ]]
            then
              get_iterInfo_negishi $k
              get_deficSum $k

              if [[ $lalo -gt 0 ]]
              then
                items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run converged)")
                printline_negishi $fmt_conv items[@] list_lastIterInfo[@]
              else
                if [[ $lali -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run failed) Last iter. Locally Infeasible")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $lain -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run failed) Last iter. Infeasible")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $lano -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run failed) Last iter. Intermediate Nonoptimal")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $laub -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run failed) Last iter. Unbounded")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                # The run has not ended something wrong happened
                if [[ $lali -eq 0 && $lain -eq 0 && $lano -eq 0 && $laub -eq 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "?/$maxiter" "?/$maxsolit" "NA" "  (Run failed) Check code, pre-triangular infes ...")
                  printline_negishi $fmt_fail items[@]
                fi
              fi
            # The run has not ended properly, something wrong happened
            else
              get_iterInfo_negishi $k
              get_deficSum $k
              
              items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run stopped) Cluster problem, HWCL exceeded ...")
              printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
            fi
          
          # The run has not started, something wrong happened
          else
            get_iterInfo_negishi $k
            get_deficSum $k
              
            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "$defic" "  (Run stopped) GAMS syntax error ...")
            printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
          fi
        fi
      ;;
    
    #----------------------------
    # Nash case
    #----------------------------
      nash)
        get_maxIterInfo_nash $k

        # Is the current run directory name in the jobs list?
        check_jobList $k
        if [[ f_check_jobList -eq 1 ]]
        then
          get_jobInfo $k
          
          # If the run has started...
          check_runStarted $k
          if [[ f_check_runStarted -eq 1 ]]
          then
            get_iterInfo_nash $k

            items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  ($jobstat) $jobid")
            printline_nash $fmt_run items[@] list_lastIterInfo[@]
          else

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "NA" "NA" "  ($jobstat) $jobid")
            printline_nash $fmt_pend items[@]
          fi

        # If the run has stopped...
        else
          # Has the run ever started ?
          check_runStarted $k
          if [[ f_check_runStarted -eq 1 ]]
          then
          
            get_iterInfo_nash $k
          
            # Has the job ended properly?
            check_runStopped $k
            if [[ f_check_runStopped -ge 1 ]]
            then
              solver=$(check_solverStatus $k)
              mempb=$(check_memoryError $k)
              check_conv_nash $k

              if [[ "$conv_nash" == "" && $solver -eq 1 && $mempb -eq 1 && $lastiter -gt 0 ]]
              then
                get_deficSum_nash $k

                items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "$defic" "  (Run converged)")
                printline_nash $fmt_conv items[@] list_lastIterInfo[@] 
              else
                if [[ $solver -eq 0 || $mempb -eq 0  || $lastiter -eq 0 ]]
                then
                  if [[ $lastiter -eq 0 ]]
                  then
                    lastiter=0
                  fi

                  if [[ $solver -eq 0 ]]
                  then
                    items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  (Run stopped) solver aborted")
                    printline_nash $fmt_fail items[@] list_lastIterInfo[@]
                  fi 
                  
                  if [[ $mempb -eq 0 ]]
                  then
                    items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  (Run stopped) memory prob")
                    printline_nash $fmt_fail items[@] list_lastIterInfo[@]
                  fi
             
                  if [[ $solver -ne 0 && $mempb -ne 0 ]]
                  then
                    items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  (Run stopped) undefined problem")
                    printline_nash $fmt_fail items[@] list_lastIterInfo[@]
                  fi
                else
                  get_failMarkets $k
                  
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  (Run failed) Failing markets: $failmkt")
                  printline_nash $fmt_fail items[@] list_lastIterInfo[@]
                fi
              fi
            else

              items=("$mainloopcnt" "$shortname" "$optalgo" "$lastiter/$maxiter" "NA" "NA" "  (Run stopped) Cluster problem, HWCL exceeded ...")
              printline_nash $fmt_fail items[@] list_lastIterInfo[@] 
            fi
          else
            items=("$mainloopcnt" "$shortname" "$optalgo" "0/$maxiter" "NA" "NA" "  (Run stopped) GAMS syntax error ...")
            printline_nash $fmt_fail items[@] list_lastIterInfo[@]
          fi
        fi
    ;;
    
    #----------------------------
    # testOneRegi case
    #----------------------------
      testOneRegi)

        get_maxIterInfo_negishi $k

        # Is the current run directory name in the jobs list?
        check_jobList $k
        if [[ f_check_jobList -eq 1 ]]
        then

          get_jobInfo $k

          # If the run has started...
          check_runStarted $k
          if [[ f_check_runStarted -eq 1 ]]
          then
            get_iterInfo_negishi $k
            #get_deficSum $k

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  ($jobstat) $jobid")
            printline_negishi $fmt_run items[@] list_lastIterInfo[@]
          else

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  ($jobstat) $jobid")
            printline_negishi $fmt_pend items[@]
          fi

        # If the run has stopped...
        else
          # Has the run ever started ?
          check_runStarted $k

          if [[ f_check_runStarted -eq 1 ]]
          then
            # Has the job ended properly?
            check_runStopped $k

            if [[ f_check_runStopped -ge 1 ]]
            then
              get_iterInfo_negishi $k

              if [[ $lalo -gt 0 ]]
              then
                items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run converged)")
                printline_negishi $fmt_conv items[@] list_lastIterInfo[@]
              else
                if [[ $lali -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run failed) Last iter. Locally Infeasible")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $lain -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run failed) Last iter. Infeasible")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $lano -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run failed) Last iter. Intermediate Nonoptimal")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                if [[ $laub -gt 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run failed) Last iter. Unbounded")
                  printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
                fi
                # The run has not ended something wrong happened
                if [[ $lali -eq 0 && $lain -eq 0 && $lano -eq 0 && $laub -eq 0 ]]; then
                  items=("$mainloopcnt" "$shortname" "$optalgo" "?/$maxiter" "?/$maxsolit" "NA" "  (Run failed) Check code, pre-triangular infes ...")
                  printline_negishi $fmt_fail items[@]
                fi
              fi

            # The run has not ended properly, something wrong happened
            else
              get_iterInfo_negishi $k

              items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run stopped) Cluster problem, HWCL exceeded ...")
              printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
            fi

          # The run has not started, something wrong happened
          else
            get_iterInfo_negishi $k

            items=("$mainloopcnt" "$shortname" "$optalgo" "$iter/$maxiter" "$sol/$maxsolit" "NA" "  (Run stopped) GAMS syntax error ...")
            printline_negishi $fmt_fail items[@] list_lastIterInfo[@]
          fi
        fi
      ;;
      *)
        echo "Case unknown: $optalgo"
      ;;
    esac
  else
    items=("$mainloopcnt" "$shortname" "NA" "NA"  "NA" "NA" "  (Run stopped) Compilation error, wrong gdx path...")
    printline_negishi $fmt_fail items[@]
  fi
  mainloopcnt=`expr $mainloopcnt + 1`
done

# Move back to original directory
cd $wd

exit 0
