#!/bin/sh

#TODO: debugging
#logfile="/tmp/`basename $0`.log"
#exec 3<> "$logfile"
#exec >&3
#exec 2>&3

#set -x

. /lib/functions.sh
. /usr/lib/configsync_lib.sh

CS_SERVICE_COMMON=cswireless
CS_SERVICE_24=cswireless24
CS_SERVICE_5=cswireless5
CS_SERVICE_SON=cswifi_son
SERVICE=wireless

CS_SERVICE=

my_logger() {
    logger -t configsync_executor "${SERVICE}" "${@}"
}

copy_iface_to_cs() {

    config_get iface_device $1 device

    if [ "$2" = "$iface_device" ] ; then

        local entry=$(uci_cs add ${CS_SERVICE} wifi-iface)

        # Note: UCI lists are not supported by this construct
        # TODO: complete the set of options
        synced_options="device
disabled
ssid
encryption
key
dvl_main
dvl_guest
network
mode
wds
ieee80211w
wps_config
uapsd
rrm
wnm
rsn_preauth
ieee80211r
hidden
isolate
maxassoc
wps_config"

        for synced_option in $synced_options; do
            config_get VALUE $1 $synced_option
            uci_cs set ${CS_SERVICE}.$entry.$synced_option="$VALUE"
        done
    fi
}


write_radio_to_cs() {
    config_get HWMODE $1 hwmode

    # TODO: consider require_mode '11n' too?
    case "$HWMODE" in
        11a)
            # 5GHz
            CS_SERVICE=$CS_SERVICE_5
            RADIO_5=1
            ;;
        11g)
            # 2,4GHz
            CS_SERVICE=$CS_SERVICE_24
            RADIO_24=1
            ;;
        *)
            my_logger "ERROR: Illegal value of \$HWMODE: '$HWMODE'\n\n"
            return 1
    esac

    # === radio options ===

    uci_cs set ${CS_SERVICE}.radio=wifi-device

    # Note: UCI lists are not supported by this construct. They are
    # awkward in handling anyways and thus should not be used if
    # possible.
    # TODO: complete the set of options
    synced_options="htmode
disabled
cfg_disabled
country"

    for synced_option in $synced_options; do
        config_get VALUE $1 $synced_option
        uci_cs set ${CS_SERVICE}.radio.$synced_option="$VALUE"
    done

    # === iface options ===

    # Remove unnamed sections in CS config files completely and
    # recreate them from scratch
    delete_sections_cs ${CS_SERVICE} wifi-iface

    config_foreach copy_iface_to_cs wifi-iface $1
}

##### check_common_wifi_settings process #####

check_iface_config()
{
    local device dvl_main
    config_get device "$1" device
    config_get dvl_main "$1" dvl_main
    [ "$dvl_main" = "1" ] || return
    config_get ssid "$1" ssid

    case "$device" in
        wifi0)
            SSID_WIFI0=$ssid;;
        wifi1)
            SSID_WIFI1=$ssid;;
    esac
}

check_common_wifi_settings()
{
    # check common_wifi_settings
    local UCI_CONFIG_DIR="$CS_CONFIGURATION_PATH"
    config_load cswireless24
    config_foreach check_iface_config wifi-iface
    config_load cswireless5
    config_foreach check_iface_config wifi-iface
    [ "$SSID_WIFI0" = "$SSID_WIFI1" ]
}

##### sync_common_wifi_settings process #####

get_iface_config()
{
    local device dvl_type
    config_get device "$1" device
    [ "$device" = "wifi0" ] || return
    config_get dvl_type "$1" "$2"
    [ "$dvl_type" = "1" ] || return
    config_get ssid "$1" ssid
    config_get key "$1" key
    config_get encryption "$1" encryption
}

set_iface_config()
{
    local device dvl_type
    config_get device "$1" device
    [ "$device" = "wifi1" ] || return
    config_get dvl_type "$1" "$2"
    [ "$dvl_type" = "1" ] || return
    uci_cs set ${CS_SERVICE_5}.${1}.ssid="$ssid"
    uci_cs set ${CS_SERVICE_5}.${1}.key="$key"
    uci_cs set ${CS_SERVICE_5}.${1}.encryption="$encryption"
}

sync_common_wifi_settings()
{
    local COMMON_MODE=$1
    local UCI_CONFIG_DIR="$CS_CONFIGURATION_PATH"
    # check wifi common config
    if [ "$COMMON_MODE" = "1" ]; then
        config_load cswireless24
        config_foreach get_iface_config wifi-iface dvl_main
        config_load cswireless5
        config_foreach set_iface_config wifi-iface dvl_main
    fi
    # guest wifi common config
    config_load cswireless24
    config_foreach get_iface_config wifi-iface dvl_guest
    config_load cswireless5
    config_foreach set_iface_config wifi-iface dvl_guest
}

######################################

system_to_configsync()
{
    my_logger "This is ${0} system_to_configsync()!"

    # if there are current changes pending to $SERVICE or $CS_SERVICE, quit
    # uci_changes_service="$( uci changes ${SERVICE} )"
    # uci_changes_csservice="$( uci_cs changes )"
    # if [ ! -z "$uci_changes_service" || ! -z "$uci_changes_service" ] ; then
        # my_logger   "ERROR: pending changes to UCI configuration! Exiting." \
                    # "Output is:" \
                    # "$uci_changes_service\n" \
                    # "$uci_changes_csservice"
        # return 1
    # fi


    # Configsync sets md5sum for config files it writes itself.
    # This is done to distinguish own writes from others, e.g. by webpage.
    # Also, when configsync writes config files, it triggers sync events.
    # The following check makes sure, the just-written config is not synced again.


    # set common wifi parameter

    config_get VALUE wps min_hold_time
    uci_cs set ${CS_SERVICE_COMMON}.wps.min_hold_time="$VALUE"

    config_get VALUE wps max_hold_time
    uci_cs set ${CS_SERVICE_COMMON}.wps.max_hold_time="$VALUE"

    config_get VALUE qcawifi atf_mode
    uci_cs set ${CS_SERVICE_COMMON}.qcawifi.atf_mode="$VALUE"

    config_get VALUE guest_wifi auto_switch_off
    uci_cs set ${CS_SERVICE_COMMON}.guest_wifi.auto_switch_off="$VALUE"

    config_get VALUE guest_wifi interval
    uci_cs set ${CS_SERVICE_COMMON}.guest_wifi.interval="$VALUE"

    config_get VALUE guest_wifi starttime
    uci_cs set ${CS_SERVICE_COMMON}.guest_wifi.starttime="$VALUE"

    config_get VALUE son enabled
    uci_cs set ${CS_SERVICE_SON}.son.enabled="${VALUE}"

    config_get VALUE son airtimefairness
    uci_cs set ${CS_SERVICE_SON}.son.airtimefairness="${VALUE}"

    config_get VALUE son bandsteering
    uci_cs set ${CS_SERVICE_SON}.son.bandsteering="${VALUE}"

    config_get VALUE son ieee80211k
    uci_cs set ${CS_SERVICE_SON}.son.ieee80211k="${VALUE}"

    config_get VALUE son ieee80211v
    uci_cs set ${CS_SERVICE_SON}.son.ieee80211v="${VALUE}"

    config_get VALUE son ieee80211r
    uci_cs set ${CS_SERVICE_SON}.son.ieee80211r="${VALUE}"

    (check_common_wifi_settings) && local COMMON_MODE=1 # call as subshell (no config_load merging)

    # loop though radios, get their device names (e.g. wifi0),
    # detect type (2,4 GHz vs 5 Ghz) and work through the corresponding interfaces
    config_foreach write_radio_to_cs wifi-device

    if [ "$RADIO_24" = "1" -a "$RADIO_5" != "1" ]; then
        # only 2.4 GHz radio available"
        (sync_common_wifi_settings $COMMON_MODE) # call as subshell (no config_load merging)
    fi

    uci_cs commit ${CS_SERVICE_COMMON}
    uci_cs commit ${CS_SERVICE_24}    # returns error if no 2.4GHz radio available
    uci_cs commit ${CS_SERVICE_5}     # returns error if no 5GHz radio available
    uci_cs commit ${CS_SERVICE_SON}
}


initialize_radio() {
    config_get HWMODE $1 hwmode

    # TODO: consider require_mode '11n' too?
    case "$HWMODE" in
        11a)
            # 5GHz
            >${CS_CONFIGURATION_PATH}/${CS_SERVICE_5}
            uci_cs set ${CS_SERVICE_5}.configsync=info
            uci_cs set ${CS_SERVICE_5}.configsync.version=1
            ;;
        11g)
            # 2,4GHz
            >${CS_CONFIGURATION_PATH}/${CS_SERVICE_24}
            uci_cs set ${CS_SERVICE_24}.configsync=info
            uci_cs set ${CS_SERVICE_24}.configsync.version=1
            ;;
        *)
            my_logger "ERROR: Illegal value of \$HWMODE: '$HWMODE'\n\n"
            return 1
    esac
    return 0
}
        
init()
{
    my_logger "This is ${0}/init()!"
    if [ ! -d ${CS_CONFIGURATION_PATH} ]; then
        mkdir -p ${CS_CONFIGURATION_PATH}
    fi

    # initialize common wireless config file
    
    # clear the current CS config to avoid accidental merging
    >${CS_CONFIGURATION_PATH}/${CS_SERVICE_COMMON}
    >${CS_CONFIGURATION_PATH}/${CS_SERVICE_SON}
    
    # setup needed sections
    uci_cs set ${CS_SERVICE_COMMON}.configsync=info
    uci_cs set ${CS_SERVICE_COMMON}.configsync.version=1
    uci_cs set ${CS_SERVICE_COMMON}.wps=wps
    uci_cs set ${CS_SERVICE_COMMON}.qcawifi=qcawifi
    uci_cs set ${CS_SERVICE_COMMON}.guest_wifi=guest_wifi

    uci_cs set ${CS_SERVICE_SON}.son=son

    # initialize radio config files
    config_foreach initialize_radio wifi-device

    system_to_configsync init
}

if [ "${1}" = "init" ] || [ "${1}" = "system_to_configsync" ]; then
    config_load wireless
    "${@}"
else
        my_logger "Unknown command ${1} in ${0}!"
fi