#!/bin/bash

# Globals
download=false
update=false
register=false
this_dir=`pwd`

log_file=${this_dir}/get-gateway.log
log_history_file=${this_dir}/get-gateway.history.log

sha256_file="gatewaydigest.txt"
#executable name
appname="tehama-gateway"
#program executable full path
program="${this_dir}/${appname}"

zip_file="gateway.zip"

version_file_old="gatewayagent-version.json"
version_file="gateway-version.json"

script_file="get-gateway.sh"
script_path="${this_dir}/${script_file}"

#sub-directory to store the tehama-gateway of a specific version
version_dir=

#Update proxy urls loaded from the secret.sck
proxy_url1=
proxy_url2=
proxy_url3=

#content of a file downloaded to memory
download_result=

#latest version available from the server
version=

#clear rotating log file
rm -f "${log_file}"
function log() {
    #print to console, append to rotating log file and history log file
    echo $* | tee -a "${log_file}" "${log_history_file}"
}

function logFromFile() {
    #print contents of the file to the console, append to rotating log file and history log file
    if [ ! -f "${1}" ]; then
        log "${1} does not exist"
    else
        cat "${1}" | tee -a "${log_file}" "${log_history_file}"
    fi
}

log "Started: `date`"
#will capture the exit time
trap 'log "Finished with exit code $? on `date` "' EXIT

log "Command: $0 $*"

function usage() {
    echo
    echo "Usage: ${0} [-u] [-r] [-h]"
    echo "    No params:"
    echo "        Install the latest tehama-gateway if not installed"
    echo "        Prompt for secret.sck if missing"
    echo "        Then start the gateway"
    echo
    echo "    -u: Update the tehama-gateway to the latest version"
    echo "        Then start the gateway"
    echo "        secret.sck must exist in the current directory"
    echo
    echo "    -r: Register tehama-gateway auto start using rc.local"
    echo "        Must be run as a root or with sudo"
    echo
    echo "    -h: Print this help text and exit"
    echo
    exit 2
}

#Check for program dependencies (wget, curl, unzip)
function verify_dependencies() {
    if [ ! -f "${program}" ]; then
        log "tehama-gateway executable not found in '${this_dir}'"
        log "Will download the latest version."
        download=true
    fi

    unzipcmd=`which unzip`
    unzipexists=$?
    if [ ${unzipexists} != 0 ]; then
        log "Required tool: unzip does not exist. Install and retry."
        exit 3
    fi

    pgrepcmd=`which pgrep`
    pgrepexists=$?
    if [ ${pgrepexists} != 0 ]; then
        log "Required tool: pgrep does not exist. Install and retry."
        exit 3
    fi

    wgetcmd=`which wget 2>/dev/null`
    wgetexists=$?
    curlcmd=`which curl 2>/dev/null`
    curlexists=$?
    if [ ${wgetexists} != 0 ] && [ ${curlexists} != 0 ];then
        log "Required tools: wget OR curl. Install one and retry."
        exit 3
    fi

    sshcmd=`which ssh`
    sshexists=$?
    if [ ${sshexists} != 0 ];then
        log "ssh is not installed. Gateway network performance will be degraded."
    fi

    sshkeygencmd=`which ssh-keygen`
    sshkeygenexists=$?
    if [ ${sshkeygenexists} != 0 ];then
        log "ssh-keygen is not installed. Gateway network performance will be degraded."
    fi

    sshdcmd=`which sshd`
    sshdexists=$?
    if [ ${sshdexists} != 0 ];then
        log "sshd is not installed. Gateway network performance will be degraded."
    fi

}

function download_versioninfo() {
    log "Downloading the version info"
    rm -f ${version_file_old}
    rm -f ${version_file}
    download_to_memory ${version_file}

    if [ $? -ne 0 ]; then
        log "Failed to download version info"
        exit 4
    fi
    version_json=${download_result}
    log "Version JSON: ${version_json}"

    version=`echo -n "${version_json}" | grep -Po '"version"\s*:\s*"\K([^"]*)'`
    #Validate version format: #.#.#
    if [[ ! ${version} =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]] ; then
        log "INVALID version detected! Exiting."
        exit 4
    fi

    log "Latest available version is ${version}"
    version_dir=${version}
}

function download_digest() {
    log "Downloading SHA256 digest"
    download_to_memory ${sha256_file}
    sha256=${download_result}
    if [ $? -ne 0 ]; then
        log "Failed to download SHA256 Digest"
        exit 5
    fi
    #Validate the sha256 digest format
    if [[ ! ${sha256} =~ ^[a-f0-9]{64}$ ]] ; then
        log "INVALID SHA256 digest detected: '${sha256}'! Exiting."
        exit 5
    fi
    log "SHA256 Digest: ${sha256}"
}

# download the get-gateway.sh if missing.
# this can happen if the script is invoked from another direcoty or from the web directly.
function download_script() {
    if [ ! -f "${script_path}" ]; then
        log "${script_file} not found in '${this_dir}'"
        log "Will download latest version"
        download_to_file ${script_file}
        if [ $? -ne 0 ]; then
            log "Failed to download ${script_file}"
            log "Please download the file manually"
        fi
        chmod +x "${script_path}"
        log "${script_file} is downloaded"
    fi
}

function download_gateway() {
    log "Downloading the ${zip_file} file to `pwd`"
    download_to_file ${zip_file}

    if [ $? -ne 0 ]; then
        log "Failed to download ${zip_file} to `pwd`"
        exit 6
    fi
}

# download_to_memory <filename>
function download_to_memory() {
    download_result=
    download_using_proxies "${1}" "MEMORY"
    return $?
}

# download_to_file <filename>
function download_to_file() {
    download_using_proxies "${1}" "FILE"
    return $?
}

# download_using_proxies <filename> <MEMORY|FILE>
function download_using_proxies() {
    #Primary download URL 1
    log "Attempting to download ${proxy_url1}/$1"
    download_from_url ${proxy_url1} $1 $2
    if [[ $? -eq 0 ]]; then
        log "Downloaded $1 from ${proxy_url1}/$1"
        return 0
    fi

    #Proxy download URL 2
    log "Attempting to download ${proxy_url2}/$1 (${proxy_ip2})"
    download_from_url ${proxy_url2} $1 $2 ${proxy_resolve2}
    if [[ $? -eq 0 ]]; then
        log "Downloaded ${proxy_url2}/$1"
        return 0
    fi

    #Proxy download URL 3
    log "Attempting to download ${proxy_url3}/$1 (${proxy_ip3})"
    download_from_url ${proxy_url3} $1 $2 ${proxy_resolve3}
    if [[ $? -eq 0 ]]; then
        log "Downloaded ${proxy_url3}/$1"
        return 0
    fi

    return 1
}

# download_from_url <url> <filename> <MEMORY|FILE> [resolved_ip_address]
function download_from_url() {
    if [ "${3}" = "MEMORY" ]; then
        wgetcmd="wget -q -O - "
        curlcmd="curl -# "
    else
        wgetcmd="wget "
        curlcmd="curl -# -o ${2}"
    fi

    if [ -n "${4}" ]; then
        curlcmd="${curlcmd} --resolve ${4} --connect-timeout 5"
    fi

    #Primary download URL 1
    if [ ${curlexists} -eq 0 ]; then
        log "${curlcmd} ${1}/${2}"
        download_result=`${curlcmd} "${1}/${2}"`
    else
        log "${wgetcmd} ${1}/${2}"
        download_result=`${wgetcmd} "${1}/${2}"`
    fi
    code=$?
    log "Download error code: ${code}"
    return ${code}
}


function verify_checksum() {
    which sha256sum
    sha256exists=$?
    if [ ${sha256exists} != 0 ];then
        log "WARNING: Required tool 'sha256sum' does not exist. Can not verify sha256 digest for ${version}/${zip_file}"
        return 0
    fi

    download_digest
    log "Verifying SHA256 checksum for ${version}/${zip_file}"
    echo "${sha256}  ${zip_file}" | sha256sum -c
    if [ $? != 0 ]; then
        log "Validation Failed: SHA256 does not match! The zip file might be corrupted."
        rm ${zip_file}
        exit 7
    fi
}

# Add the tehama-gateway line to rclocal if not already present to auto-start
# Only executed if running the script as root (sudo)
function register_autostart() {
    if [ `id -u` != 0 ]; then
        log "Not running as root (sudo). Can not register tehama-gateway to auto start."
        exit 8
    fi

    rclocal=
    if [ -f /etc/rc.d/rc.local ]; then
        rclocal=/etc/rc.d/rc.local
    elif [ -f /etc/rc.local ]; then
        rclocal=/etc/rc.local
    else
        rclocal='/etc/rc.local'
        log "The file ${rclocal} not found. Creating new file to enable auto start"
        echo '#! /bin/bash' > ${rclocal}
        echo 'exit 0' >> ${rclocal}
        if [ $? -ne 0 ]; then
            log "Can not create ${rclocal} to enable auto start."
            exit 8
        fi
        log "${rclocal} created. Please make sure the systemd rc-local.service is enabled."
    fi

    rclocalbak=${rclocal}.`date +'%s'`.bak
    log "Backing up ${rclocal} to ${rclocalbak}"
    cp -f "${rclocal}" "${rclocalbak}"

    if [ ! -x "${rclocal}" ]; then
        log "Making ${rclocal} executable"

        chmod +x "${rclocal}"
        if [ $? -ne 0 ]; then
            log "Failed to set permissions for ${rclocal}"
            exit 8
        fi
    fi

    cmd="nohup bash -c \"cd `dirname ${program}` && ${program} 2>&1 &\""

    grep "${cmd}" "${rclocal}"
    if [ $? -ne 0 ]; then
        # Remove any exit that might exist in rc.local
        sed -i 's/^exit.*//' "${rclocal}"

        log "Adding the command '${cmd}' to the file ${rclocal}"
        echo "${cmd}" >> "${rclocal}"
        echo "exit 0" >> "${rclocal}"
    fi
}

function load_secret_sck() {
    #Key file to connect to the room
    secret_file="secret.sck"
    if [ -f "${secret_file}" ]; then
        log "The file '${secret_file}' found"
    elif [ "${update}" = "true" ]; then
        log "The file '${secret_file}' NOT found in ${this_dir}! The update can not continue."
        exit 10
    else
        #if not in update mode, will ask the user to type in the missing SCK file
        log "The file '${secret_file}' is not found in ${this_dir}."
        while true
        do
            read -p $'\e[01;33mPlease paste your Tehama Room key here and press enter:  \e[0m' key
            read -p $'\e[01;33mAre you sure this secret is correct? (y/n)  \e[0m' answer
            if [ "${answer}" == "y" ] || [ "${answer}" == "yes" ];
            then
                echo ${key} > "${secret_file}"
                break
            fi
        done
    fi

    #parse the SCK file to load the proxy URLs
    sck_version=`cut -f 1 -d ';' "secret.sck"`
    if [ "${sck_version}" -ne "2" ]; then
        log "Wrong version or format of the secret.sck file. Supported version '2'"
        exit 10
    fi
    proxy_urls=`cut -f 5 -d ';' "secret.sck"`
    # Normally https://app.tehama.io
    proxy_url1=`echo "${proxy_urls}" | cut -f 1 -d '|'`

    # Normally https://gwa-proxy1.app.tehama.io
    proxy_url2=${proxy_url1/app./gwa-proxy1.app.}
    # Fixed IP
    proxy_ip2=`echo "${proxy_urls}" | cut -f 2 -d '|' | cut -f 3 -d '/'`
    # host:port:ip for curl --resolve
    proxy_resolve2=`echo "${proxy_url2}" | cut -f 3 -d '/'`:443:${proxy_ip2}

    # Normally https://gwa-proxy2.app.tehama.io
    proxy_url3=${proxy_url1/app./gwa-proxy2.app.}
    # Fixed IP
    proxy_ip3=`echo "${proxy_urls}" | cut -f 3 -d '|' | cut -f 3 -d '/'`
    # host:port:ip for curl --resolve
    proxy_resolve3=`echo "${proxy_url3}" | cut -f 3 -d '/'`:443:${proxy_ip3}

    log "Update URLs: ${proxy_url1}, ${proxy_url2} (${proxy_ip2}), ${proxy_url3} (${proxy_ip3})"
}

function verify_gateway_name() {
    #Each gateway must have a name which is stored in the gateway.name file
    name_file="gateway.name"
    if [ -f "${name_file}" ]; then
        log "The file '${name_file}' found"
    elif [ "${update}" = "true" ]; then
        log "The file '${name_file}' not found in '${this_dir}'! The Gateway will use a default name '`hostname`'."
    else
        #if not in the 'update' mode, will ask the user to type in the name
        log "The file '${name_file}' is not found in ${this_dir}"
        #default value for hateway name is hostname
        gatewayname=`hostname`
        while true
        do
            read -e -r -p $'\e[01;33mThe Name is used to identify this instance of the Gateway\nPlease enter the Name and press enter:\e[0m ' -i "${gatewayname}" gatewayname
            read -p $'\e[01;33mAre you sure this name is correct? (y/n)  \e[0m' answer
            if [ "${answer}" == "y" ] || [ "${answer}" == "yes" ];
            then
                log "Saving '${gatewayname}' to '${name_file}'"
                echo "${gatewayname}" > "${name_file}"
                break
            fi
        done
    fi
}

# Parse script options
while getopts "urh" opt; do
    case ${opt} in
        u)
            download=true
            update=true
            ;;
        r)
            register=true
            ;;
        h)
            usage
            ;;
        \?)
            usage
            ;;
    esac
done

load_secret_sck

verify_dependencies
verify_gateway_name
download_script

if [ "${register}" == "true" ]; then
    register_autostart
    exit 0
fi

# Download the tehama-gateway unzip and install
if [ "${download}" == "true" ]; then
    #fetch version from the server
    download_versioninfo
    log "Create sub-directory ${version_dir} for the version"
    mkdir -p ${version_dir}
    if [ $? -ne 0 ]; then
        log "Failed to create directory ${version_dir}"
        exit 9
    fi

    #cd into version dir to start download
    pushd ${version_dir}
    download_gateway

    verify_checksum

    log "Unzipping the downloaded zip"
    unzip -o "${zip_file}"
    if [ $? -ne 0 ]; then
        log "Failed to unzip ${zip_file}"
        popd
        exit 9
    fi

    log "Making '${appname}' executable"
    chmod +x "${appname}"
    if [ $? -ne 0 ]; then
        log "Failed to make the '${appname}' executable"
        popd
        exit 9
    fi

    #remove ZIP after unzipping
    log "Removing ZIP file"
    rm -f "${zip_file}"
    
    popd

    #save version to file to indicate the currently running version of tehama-gateway
    log "Updating version file ${this_dir}/${version_file}"
    echo -n "${version_json}" > ${version_file}

    #create hard link; override existing tehama-gateway
    log "Creating link ${program} to ${version_dir}/${appname}"
    ln -f "${version_dir}/${appname}" "${program}"
    if [ $? -ne 0 ]; then
        log "Failed create a link to ${version_dir}/${appname}"
        exit 9
    fi

    #if no .env file existing, copy default
    if [ ! -f ".env" ]; then
        log "Copying default ${version}/.env file to ${this_dir}"
        cp "${version}/.env" .
    fi

    #if no ssh_config file existing, copy default
    if [ ! -f "ssh_config" ]; then
        log "Copying default ${version}/ssh_config file to ${this_dir}"
        cp "${version}/ssh_config" .
    fi

    #if no sshd_config file existing, copy default
    if [ ! -f "sshd_config" ]; then
        log "Copying default ${version}/sshd_config file to ${this_dir}"
        cp "${version}/sshd_config" .
        echo >> sshd_config
        if [ $(id -u) -ne 0 ]; then
           echo "UsePAM no" >> sshd_config
        else
           echo "UsePAM yes" >> sshd_config
        fi
    fi

    log "Copying ${version}/stop-gateway.sh file to ${this_dir}"
    cp "${version}/stop-gateway.sh" .
    chmod 700 stop-gateway.sh

    log "Tehama Gateway version ${version} successfully downloaded and installed!"
    log "Use ${program} when starting the Tehama Gateway manually!"

    log "Checking Tehama Gateway connectivity requirements"
    diagnostic="${version}/gateway-diagnostic.sh"
    diagnostic_log="${version}/gateway-diagnostic.log"
    if [ -f "${diagnostic}" ]; then
        chmod +x ${diagnostic}
        $diagnostic > ${diagnostic_log}
        if [ $? -ne 0 ]; then
            log "Connectivity requirements have not been satisfied. Review the ${diagnostic_log} file. Also printed below:"
            logFromFile ${diagnostic_log}
            exit 1
        fi
        log "Basic connectivity requirements are satisfied."
    else
        log "Failed to find connectivity diagnostic at ${diagnostic}"
    fi

fi

#check if tehama-gateway process already running in the same directory
function isGatewayRunning() {
    if [ "${update}" = "false" ]; then
        if [ "$(ps -ef | grep "${program}" | grep -v grep | wc -l)" -gt 0 ]; then
            log "Tehama gateway is already running at ${program}."
            log "Please stop other instance of tehama-gateway running from this directory."
            log "You may use the script ./stop-gateway.sh to stop ALL gateway instances on this host running from any directory."
            log "Exiting..."
            exit 1
        fi
    fi
}
isGatewayRunning

log "Starting the tehama-gateway in background with command 'nohup ${program} 2>&1 &'"
log "Consider registering the tehama-gateway as auto-start in rc.local using 'get-gateway.sh -r'"
nohup "${program}" 2>&1 &
