#!/bin/bash
#
# PatchControl
#
# This script helps the shifter to easily operate both the line and
# the DAQ processes until the ControlUnit will be finalised.
#
# Author: Carmelo Pellegrino <carmelo.pellegrino@bo.infn.it>
#

# The configuration of this very script is perfomed via shell variables.
# Here the list of parameters is reported
#
# DM_EXE_DIR  -> the absolute path of the folder which contains DetectorControl.exe
# DM_DATA_DIR -> the absolute path of the folder which contains the detectorfile
# PC_CONF_DIR -> the absolute path of the pc.cfg configuration file
# DAQ_SERVER  -> IP address of the DAQ Server
# DAQ_USER    -> user name on the DAQ Server

SELF_PIPE_PORT=45757

function log() {
  [ ! -d ${HOME}/.km3_private ] && mkdir -p ${HOME}/.km3_private
  local logfile="${HOME}/.km3_private/pc.log"
  echo "$(date): ${*}" >>${logfile}
}

function check_config() {
  local missing=()
  [ -n "${DM_EXE_DIR+x}"  ] || missing+=(DM_EXE_DIR)
  [ -n "${DM_DATA_DIR+x}" ] || missing+=(DM_DATA_DIR)
  [ -n "${PC_CONF_DIR+x}" ] || missing+=(PC_CONF_DIR)
  [ -n "${DAQ_SERVER+x}"  ] || missing+=(DAQ_SERVER)
  [ -n "${DAQ_USER+x}"    ] || missing+=(DAQ_USER)

  if [ ! ${#missing} -eq 0 ]; then
    zenity --error \
           --title "Error (at $(date))" \
           --text "The following configuration environment variables are missing:\n${missing[*]}\nPlease set them before run again this program."

    return 1
  fi

  return 0
}

function put_lock() {
  touch /tmp/pc.lock
}

function rm_lock() {
  unlink /tmp/pc.lock
}

function test_lock() {
  if [ -e /tmp/pc.lock ]; then
    return 1
  else
    return 0
  fi
}

function on_exit() {
  if [ "${LOCK_OWNER}" == "True" ]; then
    rm_lock
  fi

  local pid

  for pid in ${PROCS[*]}; do
    kill -9 ${pid}
  done
  unset pid

  log "Quit"
}

function get_run_setup_file() {
  local LIST=()
  local line

  while IFS=';' read -ra line; do
    LIST+=("FALSE" "${line[@]}")
  done < ${PC_CONF_DIR}/pc.cfg

  zenity --title "Run Setup Selector (at $(date))" \
         --list \
         --text "Select one of the following Run Setups:" \
         --radiolist \
         --width=600 \
         --height=400 \
         --column="Selection" \
         --column="Run Setup file" \
         --column="Run Setup name" \
         --column="Description" \
         --hide-column=2 "${LIST[@]}"
}

function dm_driver() {
  echo "set session target = On"
  echo "set session target = Run"

  sleep $1

  echo "set session target = Off"

  nc -l ${SELF_PIPE_PORT} 2>/dev/null 1>/dev/null

  echo exit
  echo y
}

function nowUTC() {
  # print the number of seconds elapsed since Jan 1 1970 00:00 in UTC
  date -u +%s
}

function get_run_number() {
  [ ! -d ~/.km3_private ] && mkdir -p ~/.km3_private
  [ ! -e ~/.km3_private/last_run_number ] && echo 0 >~/.km3_private/last_run_number
  local last_run_number=`cat ~/.km3_private/last_run_number`
  local run_number

  let "run_number = ${last_run_number} + 1"

  echo ${run_number} > ~/.km3_private/last_run_number
  echo ${run_number}
}

# Script begins here
check_config || exit 1

test_lock || { zenity --error --text="There is another instance running of this program." --title="Error (at $(date))"; exit 1;}

put_lock
LOCK_OWNER="True"

trap on_exit EXIT

while [ 1 ]; do

  # Ask for the run setup

  rs_file=`get_run_setup_file`

  if [ -z "${rs_file}" ]; then
    zenity --error --text="No Run Setup file selected, aborting" --title="Error (at $(date))"
    exit -1
  fi

  # Ask for run duration

  run_duration=`zenity --title "Run duration (at $(date))" \
                       --list \
                       --text "Select one of the following duration:" \
                       --radiolist \
                       --column="Selection" \
                       --column="Minutes" \
                       --column="Duration" \
                       --hide-column=2 \
                       --cancel-label=Back \
                       FALSE 5 "5 minutes" TRUE 10 "10 minutes" FALSE 20 "20 minutes" FALSE 240 "4 hours" FALSE 480 "8 hours" FALSE 900 "15 hours"`

  if [ "${run_duration}" == "" ]; then
    continue
  fi

  # Ask for duty cycle

  duty_cycle=`zenity --list \
                     --title "oDF' duty cycle (at $(date))" \
                     --text "Select one of the following duty cycles:" \
                     --radiolist \
                     --column="Selection" \
                     --column="N" \
                     --column="Duty cycle" \
                     --hide-column=2 \
                     --cancel-label=Back \
                     TRUE 1 100% FALSE 2 50% FALSE 10 10% FALSE 20 5% FALSE 50 2%`

  if [ "${duty_cycle}" == "" ]; then
    continue
  fi

  break

done

# Wait 10 seconds
i=0;
while [ $i -lt 100 ]; do
  let "i = $i + 10"
  echo $i
  sleep 1
done | zenity --progress \
              --auto-close \
              --text="You have 10 seconds to cancel the current operation:\nrunsetup: ${rs_file}\nduration: ${run_duration} minutes\nduty cycle: 1/${duty_cycle}" \
              --auto-kill

# Peak the run number

run_number=`get_run_number`

ROOT_FILE=`printf "KM3NeT_%08d.root" ${run_number}`
ssh ${DAQ_USER}@${DAQ_SERVER} "[ -e ${ROOT_FILE} ]" && {
  log "A root file for the current run already exists. Run ${run_number} canceled."
  zenity --error --text="A root file for the current run already exists. Run ${run_number} canceled." --title="Error (at $(date))"
  exit 1
}

let "run_duration_seconds = ${run_duration} * 60"

declare -a PROCS

daq_log_file=~/.km3_private/daq_`printf "%08d" ${run_number}`.log
JGetMessage -H ${DAQ_SERVER} -T MSG -d 3 >${daq_log_file} &
PROCS+=($!)

# Copy selected run setup file, changing the run number
cat ${rs_file} | sed -e "s/RUNNUMBER/${run_number}/" >${DM_DATA_DIR}/dm.detectorfile

run_start_time=`nowUTC`

log "Run ${run_number} ready to start. \
Run start time = ${run_start_time}, \
run duration = ${run_duration} minutes, \
duty cycle = 1 / ${duty_cycle}, \
run setup file = ${rs_file}."

# Launch the DAQ
log "Launching the DAQ with the following command line: daq.sh ${run_number} ${run_start_time} ${run_duration_seconds} ${DAQ_SERVER} ${DAQ_USER} ${duty_cycle}"
daq_driver_log_file=~/.km3_private/daq_driver_`printf "%08d" ${run_number}`.log
daq.sh ${run_number} ${run_start_time} ${run_duration_seconds} ${DAQ_SERVER} ${DAQ_USER} ${duty_cycle} >${daq_driver_log_file} &
DAQ_PROC_ID=$!
PROCS+=(${DAQ_PROC_ID})

# Launch the DM
dm_driver ${run_duration_seconds} | mono ${DM_EXE_DIR}/DetectorControl.exe --control --reset --jollytoken jollyroger &
PROCS+=($!)

# Put notification mark in the system tray
zenity --notification --text="Run ${run_number} is on going." &
PROCS+=($!)

# Point the browser to the correct address, if required
zenity --question \
       --text="Would you like to open the DetectorManager GUI?" \
       --title="Question (at $(date))" \
       --cancel-label="No, thanks" && firefox http://localhost:8102/gui/main.htm &
PROCS+=($!)

# Wait the end of the run
end_run_time=`nowUTC`
let "end_run_time=${end_run_time} + ${run_duration_seconds}"
while [ `nowUTC` -lt ${end_run_time} ]; do
  let "eta=${end_run_time} - `nowUTC`"
  notify-send "Run ${run_number} is on going. It will end in ${eta} seconds. Total run duration: ${run_duration} minutes."
  sleep 10
done

wait ${DAQ_PROC_ID}

log "Run ${run_number} finished."

echo quit | nc localhost ${SELF_PIPE_PORT}

zenity --info --text="Run ${run_number} finished at $(date)! The DAQ log file is located in ${daq_log_file}." --title="Info (at $(date))"

exit 0