#!/bin/bash
# config-scripts/src/share/svc--win-out/win-out.sh
# 
#  Copyright: ©2013, Güralp Systems Ltd.
#  Author: Laurence Withers <lwithers@guralp.com>
#  License: GPLv3
#

mode="$1"
name="$2"
sel="$3"

# Handle navbar "quickly"
if [ "${mode}" = "--navbar" ]
then
    echo "servicestop           Services"
    echo "servicessub/win-out   WIN sender"
    echo "win-out/${sel}        ${sel}"
    exit 0
fi



script_dir="`dirname "$0"`"
. "${script_dir}/functions.sh"
. "${script_dir}/svc_funcs.sh"
. "${script_dir}/gdi-base_link.sh"



CFGFILE="${CONFIGDIR}/${name}/${sel}.local"
CTLFILE="${CONFIGDIR}/${name}/${sel}.ctl.local"
SRVBASE="${SERVDIR}/${name}"



read_config() {
    local gdi_socket=""
    local i dup src tmp dest nchans host
    local -a chans

    gcs_svc_read || return 1

    gcs_var     "d_hour_offset"         "9"

    nchans=0
    if [ -r "${CFGFILE}" ]
    then
        # list config file entries in [channel_map] which will give us a table:
        #       gdi-name channel-number
        while read -r src dest
        do
            gcs_var "o_channel_map_src${nchans}"  "${src}"
            gcs_var "o_channel_map_dest${nchans}" "${dest}"
            chans[${nchans}]="${src}"
            ((++nchans))
        done < <(gcs_rwvar "gcs_list_varcf2" "${CFGFILE}" "channel_map")

        # list config file entries in [destinations] which gives us an arbitrary
        # name (ignored) and a variable in the form proto,host,service
        i=0
        while read -r tmp dest
        do
            # an empty hostname (for TCP server "bind to all" address) is saved
            # as a dash; undo that for the config template
            host="`echo ${dest} | cut '-d,' -f2`"
            [ "${host}" = "-" ] && host=""
            gcs_var "o_destination_proto${i}"       "`echo ${dest} | cut '-d,' -f1`"
            gcs_var "o_destination_host${i}"        "${host}"
            gcs_var "o_destination_service${i}"     "`echo ${dest} | cut '-d,' -f3`"
            ((++i))
        done < <(gcs_rwvar "gcs_list_varcf2" "${CFGFILE}" "destinations")

        gcs_var "o_hour_offset"         "`gcs_rwvar "gcs_get_varcf2" "hour_offset" "${CFGFILE}" ""`"
        gdi_socket="`gcs_rwvar "gcs_get_varcf2" "gdi_socket" "${CFGFILE}" ""`"
    fi

    gcs_gdi_base_iselect "${gdi_socket}" "sink"

    # pre-populate the channel map table with channel names from the running
    # gdi-base instance
    while read -r chan
    do
        # don't add to the table if we already loaded an entry for it from the
        # [channel_map] section
        i=0
        dup=0
        while [ "${i}" -lt "${nchans}" ]
        do
            if [ "${chans[${i}]}" = "${chan}" ]
            then
                dup=1
                break
            fi
            ((++i))
        done

        [ "${dup}" -eq 0 ] || continue

        gcs_var "o_channel_map_src${nchans}" "${chan}"
        ((++nchans))
    done < <(gdi-list-channels -s "${GDI_SOCKET_PATH}")
}



check_config() {
    local i chi chn have_chans var_name src id proto host service
    local -a chan_ids chan_names

    gcs_read_vars
    gcs_svc_check
    gcs_gdi_base_dereference "sink"

    # we cannot use check_table_not_empty for channel_map, because it does not
    # work if we have a table such as:
    #   src       dest
    #   S1.Z
    #   S1.N      1
    #   S1.E
    # so we must implement our own channel map tester. This gives us an
    # opportunity to test for duplicate channel numbers etc.
    #
    # The chan_ids[] array is indexed by WIN channel number and stores the GDI
    # channel name for the source channel. The chan_names[] array is simply a
    # list of source channel names. These are both used to check for dups.

    i=0
    chn=0
    have_chans=0
    while [ "${i}" -lt "${new_channel_map_rows}" ]
    do
        var_name="new_channel_map_src${i}"
        src="${!var_name}"
        var_name="new_channel_map_dest${i}"
        id="${!var_name}"
        ((++i))

        if [ -n "${src}" ]
        then
            # probably pre-populated by read_config(). The user didn't provide
            # an ID/channel number so ignore it.
            [ -n "${id}" ] || continue

            # test if something is already using this channel number
            if [ -n "${chan_ids[${id}]}" ]
            then
                gcs_err "channel_map" "Duplicate channel number ${id} (${src} and ${chan_ids[${id}]})"
                continue
            fi

            # test if something is already using this GDI channel name
            chi=0
            while [ "${chi}" -lt "${chn}" ]
            do
                if [ "${src}" = "${chan_names[${chi}]}" ]
                then
                    gcs_err "channel_map" "Duplicate channel name ${src}"
                    break
                fi
                ((++chi))
            done

            [ "${chi}" -eq "${chn}" ] || continue

            # record new entry in dup-checking arrays
            have_chans="1"
            chan_ids[${id}]="${src}"
            chan_names[${chn}]="${src}"
            ((++chn))
        else
            # no GDI channel name present
            if [ -n "${id}" ]
            then
                gcs_err "channel_map" "Cannot have a channel number with an empty system name"
            fi
        fi
    done

    if [ "${have_chans}" -eq 0 ]
    then
        gcs_err "channel_map" "No channels have been configured"
    fi

    # check for null hostnames if service is UDP (must be provided as we are
    # pushing to a remote host)
    i=0
    have_chans=0
    while [ "${i}" -lt "${new_destinations_rows}" ]
    do
        var_name="new_destination_proto${i}"
        proto="${!var_name}"
        var_name="new_destination_host${i}"
        host="${!var_name}"
        var_name="new_destination_service${i}"
        service="${!var_name}"
        ((++i))

        if [ -n "${service}" ]
        then
            if [ "${proto}" = "UDP" -a -z "${host}" ]
            then
                gcs_err "destinations" "UDP destinations must have a hostname or IP address"
            fi
            have_chans=1
        else
            if [ -n "${host}" ]
            then
                gcs_err "destinations" "Hostname/IP '${host}' does not have a service/port"
            fi
        fi
    done

    if [ "${have_chans}" -eq 0 ]
    then
        gcs_err "destinations" "No destinations have been configured"
    fi
}



write_config() {
    local i tmpfile varname varname2 varname3 host

    if gcs_truefalse "${new_delete:-false}"
    then
        gcs_svc_delete "${name}" "${sel}"
        return 0
    fi

    check_config
    if [ "${gcs_errors}" -ne 0 ]
    then
        return 1
    fi

    tmpfile="`mktemp`"
    cat > "${tmpfile}" <<EOF
DESC="${desc}"
EOF
    mv "${tmpfile}" "${CTLFILE}" || return 1

    tmpfile="`mktemp`"
    cat > "${tmpfile}" <<EOF
application_description = ${new_desc}
hour_offset = ${new_hour_offset}
gdi_socket = ${new_gdi_socket}

[destinations]
EOF

    i=0
    while [ "${i}" -lt "${new_destinations_rows}" ]
    do
        varname="new_destination_service${i}"
        varname2="new_destination_proto${i}"
        varname3="new_destination_host${i}"
        ((++i))
        [ -n "${!varname}" ] || continue
        host="${!varname3}"
        [ -z "${host}" ] && host="-"
        echo "dest${i} = ${!varname2},${host},${!varname}" >> "${tmpfile}"
    done

    echo "[channel_map]" >> "${tmpfile}"
    i=0
    while [ "${i}" -lt "${new_channel_map_rows}" ]
    do
        varname="new_channel_map_src${i}"
        varname2="new_channel_map_dest${i}"
        ((++i))
        [ -n "${!varname}" ] || continue
        [ -n "${!varname2}" ] || continue
        echo "${!varname} = ${!varname2}" >> "${tmpfile}"
    done

    mv "${tmpfile}" "${CFGFILE}" || return 1
    gcs_update_svc "${name}" "${sel}" "${enable}" "${desc}" "${CFGFILE}" "${CTLFILE}" "${SRVBASE}" ""
    gcs_svc_reload "${name}" "${sel}"
}



if [ "${mode}" = "--check" ]
then
    check_config
elif [ "${mode}" == "--write" ]
then
    write_config
elif [ "${mode}" == "--read" ]
then
    read_config
else
    echo "Unknown mode '${mode}'." >&2
    exit 1
fi



gcs_cleanup
exit 0

# vim: ts=4:sw=4:expandtab
