#!/bin/bash

#####################################################################################################################################################
#
# The MervisIDE passes configuration in two arguments:
#  $1: instance name (e.g. default)
#  $2: configuration parameters as a single string !!!
#
# e.g.: /etc/mervis/configure-enet default 'change wlan wlan0 disabled ssid "CAT S31" security wpa2personal password "faster 123" dhcp'
#
#####################################################################################################################################################

#load configuration
. "$(dirname "$0")/config.sh"

# load additional functions
. /etc/mervis/enet-lib

INTERFACES_D="/etc/network/interfaces.d"
TMP_INTERFACES_D="/tmp/interfaces.d"

# remount the / for writing
unlock_fs

if [ ! -d "$TMP_INTERFACES_D" ]; then
    echo "$TMP_INTERFACES_D does not exist, creating one"
    mkdir "$TMP_INTERFACES_D"
fi

#check the first parameter, a.k.a "instance"
instance="$1"
if [ -z "$instance" ]; then
    echo "Instance is required" >&2
    exit 1
fi
echo "Instance: $instance"

# Rest of the config parameters are stored as a string which may contain parameters in double quotes, e.g SSID name, password,...
# We will evaluate the string as array to preserve all the parameters
eval "params=($2)"
if [ "${#params[@]}" == "0" ]; then
    echo "Parameters are required" >&2
    exit 1
fi


# validate the operation command
# currently we will support only "change" command
op="${params[0]}"
case "$op" in
    add|change)
        # is the default command, we will process the parameters later
        ;;
    commit)
        # commit is the last command, lock the filesystem and exit gracefully

        # put all current interfaces down
        for iface in $(ls "$INTERFACES_D"); do
            # check if the interfaces really exists
            if ip link show "$iface" >/dev/null 2>&1; then
                # it does, put it down forcefully (gracefully (put down only if up) doesn't work)
                echo "Putting interface $iface down..."
                /sbin/ifdown --force "$iface"
            else
                echo "Interface $iface doesn't exist"
            fi
        done

        echo
        ip -s -h a
        echo 

        # remove the current network settings
        if rm -r "$INTERFACES_D"; then
            if mv "$TMP_INTERFACES_D" "$INTERFACES_D"; then
                # put all desired interfaces up
                #first the eth*, then br* and then the wireless things
                cd "$INTERFACES_D" || true
                for iface in $(ls eth* 2>/dev/null); do
                    echo "Putting interface $iface up..."
                    if ! /sbin/ifup "$iface"; then
                        echo "Interface $iface refused to be put up" >&2
                    fi
                done
                for iface in $(ls br* 2>/dev/null); do
                    echo "Putting interface $iface up..."
                    if ! /sbin/ifup "$iface"; then
                        echo "Interface $iface refused to be put up" >&2
                    fi
                done
                for iface in $(ls w* 2>/dev/null); do
                    echo "Putting interface $iface up..."
                    if ! /sbin/ifup "$iface"; then
                        echo "Interface $iface refused to be put up" >&2
                    fi
                done
                cd -  >/dev/null || true
            else
                echo "Could not move the generated config fiiles in place"
            fi
        else
            echo "Could not remove the current interfaces.d"
        fi

        echo
        cat /etc/network/interfaces.d/*
        echo

        echo "This is the final state:"
        ip -s -h a

        sync

        lock_fs 
        exit 0
        ;;
    *)
        # operation name is not recognized, exit forcefully
        echo "Unknown operation '$op'" >&2
        exit 1
        ;;
esac
echo "Operation: $op"


# check whether interface type is set and is valid
type="${params[1]}"
if [ -z "$type" ]; then
    echo "Interface type is required" >&2
    exit 1
fi
case "$type" in
    card)
        ;;
    gsm)
        configure_gsm "${params[@]}"
        lock_fs 
        sync
        exit 0
        ;;
    wlan)
        ;;
    *)
        echo "Unsupported interface type ${type}" >&2
        exit 1
        ;;
esac
echo "Interface type: $type"


# validate the interface name
name="${params[2]}"
shift
if [ -z "$name" ]; then
    echo "Interface name is required" >&2
    exit 1
fi
# translate the "default" ethernet name
[ "$name" == "default" ] && name="eth0"
echo "Interface name: $name"


# reset all the variables
unset is_dhcp is_none address mask gateway ns security ssid password state

# default parameters
# the card 'default' doesn't have 'enabled' parameter, force it, hopefully it will work for all interfaces
state=1

# now iterate over the rest of the parameters
# if the parameter will be a known key, we will store the next parameter as its value
for ((i=3; i<${#params[@]}; i++ )); do
    # store the current parameter
    param="${params[$i]}"
    case "$param" in
        dhcp)
            # flag whether the network interface should obtain IP from DHCP
            is_dhcp=1
            echo "IP address: from DHCP"
            ;;
        none)
            # flag whether the network interface should be configured as manual
            is_dhcp=0
            is_none=1
            echo "IP address: manual"
            ;;
        address)
            # the static IP address for the interface
            i=$((i+1))
            address="${params[$i]}"
            echo "IP address: $address"
            ;;
        mask)
            # netmask for the interface
            i=$((i+1))
            mask="${params[$i]}"
            echo "Netmask: $mask"
            ;;
        gateway)
            # IP address of gateway for the interface
            i=$((i+1))
            gateway="${params[$i]}"
            echo "Default gateway: $gateway"
            ;;
        nameserver)
            # IP address of the nameserver
            i=$((i+1))
            ns="${params[$i]}"
            echo "DNS: $ns"
            ;;
        security)
            # wireless lan security type: open, wep, wpa2,...
            i=$((i+1))
            security="${params[$i]}"
            echo "Wireless security: $security"
            ;;
        ssid)
            # wireless SSID name
            i=$((i+1))
            ssid="${params[$i]}"
            echo "SSID: $ssid"
            ;;
        password)
            # wireless password
            i=$((i+1))
            password="${params[$i]}"
            echo "Wireless pasword: $password"
            ;;
        enabled)
            # flag whether the network setting should be enabled
            # resulting in file created at /etc/network/interfaces.d/
            state=1
            echo "State: enabled"
            ;;
        disabled)
            # flag whether the network setting should be disabled
            # resulting in file removed from /etc/network/interfaces.d/
            state=0
            echo "State: disabled"
            ;;
        *)
            # the parameter is unknown, skip it
            echo "Unknown parameter: $param"
            ;;
    esac
done

# check the desired state of the interface
if [ "$state" == "1" ]; then
    # interface should be enabled, let's configure it
    #the generation of new config file will be in temporary file for atomicity
    tmp="$TMP_INTERFACES_D/$name"
    if touch "$tmp"; then

        #all types of interfaces will contain "auto" directive
        echo "auto $name" >> "$tmp"

        #generate "iface" line based on the mode static/dhcp
        if [ "$is_dhcp" = "1" ]; then
            echo "iface $name inet dhcp" >> "$tmp"
            echo "Interface will obtain IP from DHCP"
        elif [ "$is_none" = "1" ]; then
            echo "iface $name inet manual" >> "$tmp"
            echo "IP configuration of this interface will be manual"
        else
            # configuration for static IP address
            {
                echo "iface $name inet static";
                echo "    address $address";
                echo "    netmask $mask";
                echo "    metric 5";
            } >> "$tmp"

            # add gateway IP if specified
            [ -n "$gateway" ] && echo "    gateway $gateway"  >> "$tmp"

            # add DNS IP if specified
            [ -n "$ns" ] && echo "    dns-nameservers $ns" >> "$tmp"
        fi

        # generate section specific for wireless device
        if [ "${type}" == "wlan" ] && [ "$state" == "1" ] && [ "$ssid" != "" ]; then
            # add SSID  
            echo "    wpa-ssid \"$ssid\""  >> "$tmp"
            # disable wpa-key_mgmt if using WEP or no security at all
            if [ "$security" == "none" ] || [ "$security" == "wep" ]; then
                echo "    wpa-key_mgmt NONE"  >> "$tmp"
            fi
            # add password if using WPA or WPA2
            if [ "$security" == "wpa2personal" ] || [ "$security" == "wpapersonal" ]; then
                echo "    wpa-psk \"$password\""  >> "$tmp"
            fi
            # add WEP password if using WEP
            if [ "$security" == "wep" ]; then
                echo "    wpa-wep_key0 $password" >> "$tmp"
                echo "    wpa-wep_tx_keyidx=0" >> "$tmp"
            fi
            # end of section for wireless specific stuff
        fi
        # end of section for generating new configuration
    else
        echo "Could not create temporary config file at $tmp"
    fi
    # end of section for enabled interface
fi

# and now we will either put it up or down, depends on the desired state
if [ "$state" == "0" ]; then
    #if the interface is wireless, disable it as well
    if [ "$type" == "wlan" ]; then
        echo "Disabling wifi..."
        echo 1 > /sys/class/rfkill/rfkill0/soft
    fi
    
    # SUPER CONFUSING SECTION
    # When the ETH1 is set to disabled state, it means we want to put it in a bridge with eth0
    # To do that, we need to set the eth0 and eth1 to manual mode and create br0 interface 
    # with the settings we have received for eth0. We will do that by renaming configuration
    # for eth0 to br0 and creating manual config for eth0 and eth1. This relies on the fact
    # that the configuration of eth0 is already in place
    if [ "$name" == "eth1" ]; then
        # move config for eth0 to br0
        if cd "$TMP_INTERFACES_D"; then
            mv eth0 br0
            # replace eth0 with br0
            sed -i "s/eth0/br0/" br0
            # add bridge specific parameter
            echo "    bridge_ports eth0 eth1" >> br0
            echo "    bridge_stp off" >> br0
            echo "    bridge_waitport 0" >> br0
            echo "    bridge_fd 0" >> br0

            # create manual configuration for eth0 and eth1
            echo "iface eth0 inet manual" > eth0
            echo "iface eth1 inet manual" > eth1

            #change to previous working directory
            cd - || true
       else
            echo "Could not change into interfaces.d directory"
       fi
    fi
    # END OF SUPER CONFUSING SECTION
    
    # end of section for putting interface down
else 
    # interface should be up
    
    # if the interface is wireless, enable it first
    if [ "$type" == "wlan" ]; then
        echo "Enabling wifi..."
        echo 0 > /sys/class/rfkill/rfkill0/soft
    fi

    # end of section for putting interface up
fi

echo "Nice and easy"
exit 0
