#!/usr/bin/with-contenv bash
# shellcheck shell=bash disable=SC1091,SC2015,SC2016

#---------------------------------------------------------------------------------------------
# Copyright (C) 2023, Ramon F. Kolb (kx1t)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program.
# If not, see <https://www.gnu.org/licenses/>.
#---------------------------------------------------------------------------------------------

APPNAME="mlat-client"
echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] Started as an s6 service"

source /scripts/common
source /scripts/interpret_ultrafeeder_config

MLAT_CMD="/usr/bin/mlat-client"

RESTARTTIMER=15
declare -A pid_array

if [[ -z "${MLAT_CONFIG}" ]]
then
    echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] Warning: MLAT_CONFIG not defined - MLAT will be disabled."
    sleep infinity
fi

if [[ -z "${MLAT_USER}" ]] && [[ -z "${UUID}" ]]
then
    echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: either UUID or MLAT_USER must be defined - MLAT will be disabled."
    sleep infinity
fi

if [[ -z "$LAT$READSB_LAT" ]]; then
    echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_LAT or LAT must be defined - MLAT will be disabled."
    sleep infinity
fi

if [[ -z "$LONG$READSB_LON" ]]; then
    echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_LON or LONG must be defined - MLAT will be disabled."
    sleep infinity
fi
if [[ -z "$ALT$READSB_ALT" ]]; then
    echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_ALT or ALT must be defined - MLAT will be disabled."
    sleep infinity
fi

# MLAT_CONFIG has the following format:
# MLAT_CONFIG=mlatserver_1,mlatserver_port_1,x1,y1,z1;mlatserver_2,mlatserver_port_2,x2,y2,z2 etc
# where x1,y1,z1; x22,y2,z2; etc are optional and are interpreted as follows:
# if it's a number, we'll assume it's a port number for return messages
# if it starts with 'uuid=', it's a UUID number for that instance
# anything else will be appended as extra parameter(s) to the mlat-client command line

# parse MLAT_CONFIG string into mlat_configs array
# Strip any extraneous spaces:
MLAT_CONFIG="${MLAT_CONFIG#"${MLAT_CONFIG%%[![:space:]]*}"}"   # strip leading space
MLAT_CONFIG="${MLAT_CONFIG//; /;}"
readarray -td ";" mlat_configs < <(printf '%s' "${MLAT_CONFIG}")

# Now loop through the MLAT_CONFIG items and start up an Mlat_client for each of them:
for instance in "${mlat_configs[@]}"
do
    [[ -z "${instance}" ]] && continue || true
    # put individual params into the $params array:
    readarray -td "," params < <(printf '%s' "${instance}")

    uuid_arg=false
    extra_args=""

    # Check if the params array has values for the mandatory elements:
    if [[ -z "${params[0]}" ]] || [[ -z "${params[1]}" ]]
    then
        echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR -- MLAT_CONFIG is malformed: \"${instance}\". Stopping MLAT execution."
         # shellcheck disable=SC2046
        kill $(ps -s $$ -o pid=)   
        sleep infinity
    fi

    # ------------------------------------------------
    # Build the MLAT parameter string:
    MLAT_PARAM=(--input-type "${MLAT_INPUT_TYPE}")
    MLAT_PARAM+=(--input-connect localhost:30005)
    MLAT_PARAM+=(--server "${params[0]}:${params[1]}")

    if [ -n "${LAT}" ]; then
        MLAT_PARAM+=(--lat "${LAT}")
    elif [ -n "${READSB_LAT}" ]; then
        MLAT_PARAM+=(--lat "${READSB_LAT}")
    fi

    if [ -n "${LONG}" ]; then
        MLAT_PARAM+=(--lon "${LONG}")
    elif [ -n "${READSB_LON}" ]; then
        MLAT_PARAM+=(--lon "${READSB_LON}")
    fi

    if [ -n "${ALT}" ]; then
        MLAT_PARAM+=(--alt "${ALT}")
    elif [ -n "${READSB_ALT}" ]; then
        MLAT_PARAM+=(--alt "${READSB_ALT}")
    fi

    if [[ -n "${MLAT_USER}" ]]; then 
        MLAT_PARAM+=(--user "${MLAT_USER}")
    else 
        rnd="${RANDOM}"
        echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] WARNING: MLAT_USER is not set - using random number \"${rnd}\" as MLAT_USER"
        MLAT_PARAM+=(--user "${rnd}")
    fi

    # Now process the rest of the arguments
    # The order doesn't matter, we'll do pattern matching:
    # If the argument is a number, then it must be the beast_results port
    # If the argument starts with "uuid=", then it must be a UUID
    # If the argument isn't any of the above, then it's an "extra argument"

    for ((i=2; i<${#params[*]}; i++))
    do
        if [[ -n "${params[i]}" ]] && [[ "${params[i]}" =~ ^[0-9]+$ ]]; then
            # It's a number so it must be the return port
            MLAT_PARAM+=("--results beast,listen,${params[i]}")

        elif header="${params[i]:0:5}" && [[ "${header,,}" == "uuid=" ]]; then
            # It's a UUID
            MLAT_PARAM+=("--uuid ${params[i]:5}")
            uuid_arg=true

        else
            # It's an Extra Args string
            extra_args="$extra_args ${params[i]}"

        fi
    done
    # If no UUID was set in the argument strings, check if we can use the generic UUID parameter
    if [[ $uuid_arg == false ]] && [[ -n "${UUID}" ]]; then
        MLAT_PARAM+=("--uuid ${UUID}")
    fi
    # Now add the extra_args, if any:
    [[ -n "${extra_args}" ]] && MLAT_PARAM+=("${extra_args}") || true

    # ------------------------------------------------
    # Create the command exec string:
    # shellcheck disable=SC2048,SC2086
    execstring="$(echo ${MLAT_CMD} ${MLAT_PARAM[*]} | xargs)"

    # ------------------------------------------------
    # Ready to launch, but wait until readsb is established...
    if ! pgrep readsb >/dev/null; then
        echo "[$(date +"%Y-%m-%d %H:%M:%S")][$APPNAME] Delaying start of MLAT client(s) until container is established..."
        while ! pgrep readsb >/dev/null
        do
            sleep 2
        done
    fi
    sleep 10     # sleep a bit so everything is well established - starting readsb may take a bit

    # run this Mlat_client instance in the background:
    echo  "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] starting: ${MLAT_CMD} ${MLAT_PARAM[*]}"

    if [[ -z "${LOGLEVEL}" ]] || [[ "${LOGLEVEL,,}" == "verbose" ]]; then
        { exec ${execstring} 2>&1 | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } &
    elif [[ "${LOGLEVEL,,}" == "error" ]]; then
        { exec ${execstring} 2>&1 >/dev/null | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } &
    elif [[ "${LOGLEVEL,,}" == "none" ]]; then
       { exec ${execstring} >/dev/null 2>/dev/null; } &
    fi

    # pid_array is indexed by the PID of each mlat_client and contains the MLAT_PARAMs for that instance
    # This is done so we can monitor them and restart them if needed
    pid_array[$!]="${MLAT_PARAM[*]}"
    sleep 5
done

# All MLAT Clients are up, so set the flag. This flag is read by MLATHUB as a sign that it's
# safe to start up
touch /run/mlathub_up

# Now iterate over all MLAT-client instances and check if they are still running:
while true
do
    for mlat_pid in "${!pid_array[@]}"
    do
        if ! kill -0 "${mlat_pid}" >/dev/null 2>&1
        then
            # it exited - let's restart:
            sleep "${RESTARTTIMER}"
            [[ "${LOGLEVEL,,}" != "none" ]] && echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] MLAT_Client $(awk '{print $6}' <<< "${pid_array[$mlat_pid]}") exited. Attempting to restart." || true
            # shellcheck disable=SC2086
            execstring="$(echo ${MLAT_CMD} ${pid_array[$mlat_pid]} | xargs)"

            if [[ -z "${LOGLEVEL}" ]] || [[ "${LOGLEVEL,,}" == "verbose" ]]; then
                { exec ${execstring} 2>&1 | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } &
            elif [[ "${LOGLEVEL,,}" == "error" ]]; then
                { exec ${execstring} 2>&1 >/dev/null | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } &
            elif [[ "${LOGLEVEL,,}" == "none" ]]; then
                { exec ${execstring} >/dev/null 2>/dev/null; } &
            fi

            pid_array[$!]="${pid_array[${mlat_pid}]}"
            unset "pid_array[${mlat_pid}]"
        fi
    done
    sleep 10
done