#!/bin/bash
source /usr/lib/elive-tools/functions
[[ -z $HOME ]] && export HOME="/home/$(id -un)"
[[ -z $USER ]] && export USER="$(id -un)"

export NOREPORTS=1

. /lib/lsb/init-functions

# include sbin in our PATH since its needed sometimes, and there's nothing wrong by using it!
if [[ "$PATH" != *"/usr/sbin"* ]] ; then
    # needed for: arp
    export PATH="${PATH}:/usr/local/sbin:/usr/sbin:/sbin"
fi


# This tool is called as:   command eth1 up

update_conf_etc(){
    bios_mode_get

    if [ -n "${timezone}" ] ; then
        _AREA="$(echo "${timezone}" | cut -f1 -d '/')"
        _ZONE="$(echo "${timezone}" | cut -f2 -d '/')"
    else
        _AREA="Etc"
        _ZONE="UTC"
    fi

    el_explain 0 "Configuring machine timezone to __${timezone}, $_AREA, $_ZONE __"
    #log_progress_msg "Configuring machine timezone to ${timezone}, $_AREA, $_ZONE"

    # localtime file
    rm -f /etc/localtime
    ln -s "/usr/share/zoneinfo/${_AREA}/${_ZONE}" "/etc/localtime"
    echo "$_AREA/$_ZONE" > "/etc/timezone"

    # call tzdata and update things
    # debconf set configurations
    cat > "/tmp/debconf.$(basename $0)" << EOF
tzdata tzdata/Areas select ${_AREA}
tzdata tzdata/Zones/${_AREA} select ${_ZONE}
EOF
    debconf-set-selections < "/tmp/debconf.$(basename $0)"
    rm -f "/tmp/debconf.$(basename $0)"

    # elive conf file
    if [[ -n "$bios_mode" ]] ; then
        sed -i "/^bios mode:::/d" "$conf"
        echo "bios mode:::$bios_mode" >> "${conf}"
    fi

    # adjtime file
    if [[ -n "$bios_mode" ]] ; then
        ed -s /etc/adjtime << EOF
3d
a
$bios_mode
.
w
EOF
    fi

}

bios_mode_get(){
    # which mode of bios we have? utc or localtime?
    if [[ -z "$bios_mode" ]] ; then
        if ! ((is_force)) ; then
            bios_mode="$( awk -v FS=":::" '{if ($1 == "bios mode") print $2}' "${conf}" | tail -1 )"

            # first run always need to update conf
            if [[ -z "$bios_mode" ]] ; then
                needs_update_conf=1
            fi
        fi


        if [[ -z "$bios_mode" ]] ; then
            # if we have a windows, the time should be set to localtime for compatibility
            if has_windows ; then
                bios_mode="LOCAL"
                el_info "Clock will use 'LOCALTIME' mode, because you have a Windows system installed"
            else
                bios_mode="UTC"
                el_info "Clock will use 'UTC' mode, so you don't have a Windows system installed"
            fi
        else
            if grep -qs "bios mode" "$conf" ; then
                el_info "Hardware clock is configured as '${bios_mode}' in your Elive"
            fi
        fi
    fi
}


update_ntp_time_from_server(){
    bios_mode_get

    # 5-6 minutes max try to connect to internet before to set time
    for i in $(seq 10)
    do
        if el_verify_internet 2>/dev/null 1>/dev/null ; then
            break
        else
            sleep 10
        fi
    done

    # update the time from a server
    service ntp stop 2>/dev/null 1>&2

    #if ! ntpdate 0.pool.ntp.org 2>/dev/null 1>/dev/null ; then
        if ! ntpdate pool.ntp.org 2>/dev/null 1>/dev/null ; then
            if ! ntpdate europe.pool.ntp.org 2>/dev/null 1>/dev/null ; then
                if ! ntpdate north-america.pool.ntp.org 2>/dev/null 1>/dev/null ; then
                    if ! ntpdate 1.pool.ntp.org ; then
                        if ! ntpdate 2.pool.ntp.org ; then
                            if ! ntpdate 3.pool.ntp.org ; then
                                el_warning "can't set time from ntp servers: bios:${bios_mode} - timezone:${timezone} - wifi:${is_wifi} - live:${is_live} "
                            fi
                        fi
                    fi
                fi
            fi
        fi
    #fi

    # we don't need it at all, because we just managed to get the time, so don't waste resources
    #service ntp restart 2>/dev/null 1>&2

    # finally, save the time to hwclock if needed
    case "$bios_mode" in
        LOCAL)
            el_info "Saving time using LOCALTIME"

            hwclock -w --localtime
            ;;
        UTC|*)
            el_info "Saving time using UTC"

            hwclock -w --utc
            ;;
    esac


    el_explain 0 "Timezone is __${timezone}__, time is now __$(date)__"
    #log_progress_msg "Timezone is ${timezone}, time is now $(date)"
}


has_windows(){
    if ! ((has_os_prober_run)) ; then

        if [[ -n "$( partitions-list --show-all 2>/dev/null | awk -v FS="::" '{ if ($3 == "ntfs") print $1}' )" ]] ; then
            has_windows=1
            has_os_prober_run=1
        fi
    fi

    if ((has_windows)) ; then
        return 0
    else
        return 1
    fi
}

main(){
    # pre {{{

    # add a lock
    LOCKFILE="/tmp/.${USER}-$(basename $0).lock"
    # wait for process to finish first, if already running
    if [[ -r $LOCKFILE ]] ; then
        PROCESS=$(cat $LOCKFILE)

        while ps -p $PROCESS >/dev/null 2>&1
        do
            #echo "$(basename $0) process is already running"
            sleep 1
        done
    fi

    rm -f $LOCKFILE
    echo $$ > $LOCKFILE

    _CMDLINE="$(cat /proc/cmdline)"

    if LC_ALL=C echo "$_CMDLINE" | grep -qs "boot=live" ; then
        is_live=1
        is_force=1
    fi
    conf="/etc/elive-tools/geolocation/timezones.conf"


    if [[ -e "$conf" ]] ; then
        # fix any possible xml tag (bug) in the conf file
        if grep -qs '<.*>' "$conf" ; then
            sed -i -e 's/<[^>]*>//g' "$conf"
        fi

    else
        if [[ "${conf}" = */* ]] ; then
            mkdir -p "${conf%/*}"
        fi
        touch "$conf"
    fi

    el_dependencies_check "ip|arp|showmytimezone|ping"
    #el_check_variables "iface|state"


    # some values like no iface given should be directly exited
    if [[ -z "$1" ]] ; then
        exit
    fi

    case "$1" in
        connectivity-change|none)
            # whitelisted ignorings
            exit
            ;;
        -f|--force)
            is_force=1
            needs_update_conf=1
            # this is an ugly hack, iface is the first paramter but if we call the tool from cli it is "-f" instead
            #unset iface
            ;;
        -c|--clean)
            mode_clean=1
            unset iface
            ;;
        wlan*|ath*|ra*|w*)
            is_wifi=1
            ;;
        eth*|enp*|e*)
            is_lan=1
            ;;
        lo)
            # not needed to run on loopback
            exit
            ;;
        *)
            el_warning "unknown parameters (iface?) for $0: $@"
            ;;
    esac

    iface="$1"
    shift
    state="$1"
    shift

    read -r iface <<< "$iface"
    read -r state <<< "$state"

    # debug parameters:
    #echo "D: $@ ($iface - $state) "


    # checks
    # set some variables for compatibility specially if we run it from commandline
    if [[ -z "$state" ]] ; then
        #state="up"
        exit
    fi

    case "$state" in
        up)
            true
            ;;
        down)
            exit
            ;;
        *)
            # nothing useful to do when we disconnect
            #echo -e "Nothing to do..."
            el_warning "unknown state for $0: $state"
            exit
            ;;
    esac



    # pre hooks
    if ((mode_clean)) ; then
        rm -f "${conf}"
        el_info "Conf file cleaned"
        exit
    fi


    # }}}
    # wait for internet {{{
    # let's connect to internet first, and try to do at least one ping somewhere! or arp -a will not work
    el_verify_internet 2>/dev/null 1>/dev/null
    if ! timeout 10 ping -c 1 google.com 1>/dev/null 2>/dev/null ; then
        el_dependencies_check "dig"
        timeout 10 dig NS google.com 1>/dev/null 2>/dev/null
    fi
    sleep 1

    # make sure that we are connected to internet
    if ! el_verify_internet 2>/dev/null 1>/dev/null ; then
        sleep 5
        timeout 10 dig NS google.com 1>/dev/null 2>/dev/null
        if ! el_verify_internet 2>/dev/null 1>/dev/null ; then
            exit
        fi
    fi

    # }}}

    # get ID's {{{
    # get our connected MAC
    connected_gateway="$(ip route | grep default | awk '{ print $3 }' | tail -1 )"
    #connected_mac="$(arp -a | grep "(${connected_gateway}) at" | sed -e "s|^.*${connected_gateway} at||g" | tr ' ' '\n' | grep -E ":.*:.*:.*:" | tail -1 )"
    # note: arp -a is slow, use arp -n instead
    if [[ -n "$connected_gateway" ]] ; then
        connected_mac="$( arp -n | grep -E "(${connected_gateway})\s+" | sed -e "s|^.*${connected_gateway}||g" | tr ' ' '\n' | grep -E ":.*:.*:.*:" | tail -1 )"
    fi

    # get the bios mode
    bios_mode_get

    # get the ssid identifier
    if ((is_wifi)) ; then
        connected_ssid="$( iwconfig 2>&1 | grep "^${iface}[[:blank:]]*" | grep "ESSID:" | sed -e 's|^.*ESSID:"||g' | sed -e 's|"\s*$||g' | head -1 )"
    fi


    # }}}

    # get the location of our actual connection {{{
    timezone_last="$( awk -v FS=":::" '{if ($1 == "last") print $2}' "${conf}" | tail -1 )"

    if [[ -n "$connected_mac" ]] ; then

        if ((is_wifi)) && [[ -n "$connected_ssid" ]] ; then
            timezone_connected="$( grep -a "^${connected_mac}:::.*:::${connected_ssid}" "${conf}" | awk -v FS=":::" '{print $2}' | tail -1 )"
        else
            timezone_connected="$( grep -a "^${connected_mac}:::" "${conf}" | awk -v FS=":::" '{print $2}' | tail -1 )"
        fi
    else
        el_error "MAC '${connected_mac}' of where we are connected is not found"
        exit
    fi

    # always update the conf if we changed the place
    if [[ -n "$timezone_last" ]] ; then
        if [[ "${timezone_last}" != "$timezone_connected" ]] ; then
            needs_update_conf=1
        fi
        if [[ "${timezone_last}" != "$timezone" ]] ; then
            needs_update_conf=1
        fi
        if [[ "${timezone}" != "$(cat /etc/timezone)" ]] ; then
            needs_update_conf=1
        fi
    fi

    # }}}


    # get the actual timezone
    if [[ -n "$timezone_connected" ]] ; then
        timezone="${timezone_connected}"
    else
        timezone="$(showmytimezone)"

        if [[ "${timezone}" = "Etc/UTC" ]] || [[ "${timezone}" = "Etc/GMT"* ]] ; then
            if [[ -n "${timezone_last}" ]] ; then
                el_warning "we have not detected the timezone correctly, switching to last"
                timezone="${timezone_last}"
            else
                el_error "timezone not detected correctly"
                exit
            fi
        fi
    fi

    # check
    if [[ -z "$timezone" ]] ; then
        el_error "We have not found a timezone '${timezone}', exiting..."
        exit
    fi


    #
    # We changed our location
    #

    # always update it if we are in live
    if ((is_force)) ; then
        needs_update_conf=1
    fi


    # do it
    if ((needs_update_conf)) || ((is_force)) ; then
        update_conf_etc
    fi

    # by default we always need to update time
    update_ntp_time_from_server

    # update to our last location {{{
    # TODO: if the location is wrong, ask the user if the time is correct to confirm it
    if ((is_force)) ; then
        sed -i "/^${connected_mac}:::/d" "$conf"
    fi
    if ! grep -aq "^${connected_mac}:::" "${conf}" ; then
        # but remember it only if we have an interface
        if [[ -n "$iface" ]] ; then
            el_check_variables "connected_mac"
            if [[ -n "$connected_ssid" ]] ; then
                echo "${connected_mac}:::${timezone}:::${iface}:::${connected_ssid}" >> "${conf}"
            else
                if ! ((is_wifi)) ; then
                    # mobile connections without ID should be never saved, since they moves!
                    echo "${connected_mac}:::${timezone}:::${iface}" >> "${conf}"
                fi
            fi
        else
            el_warning "ignoring adding entry in conf, so we don't have enough ID data to include: iface '${iface},' ssid '${connected_ssid}' "
        fi
    fi


    if [[ -n "$timezone" ]] && ! [[ "${timezone}" = "${timezone_last}" ]] ; then
        el_explain 0 "Updating last timezone to __${timezone}__ because is different than the last one"
        sed -i '/^last:::.*$/d' "${conf}"
        echo "last:::${timezone}" >> "${conf}"
    fi

    # }}}
}

#
#  MAIN
#
#log_daemon_msg "Starting $(basename $0)"

main "$@"

#log_end_msg 0


# vim: set foldmethod=marker :

