#!/bin/sh
source /usr/bin/flexa-config-lib

loga() 
{
    msg="$1 $2 $3"
    logger "flexa-agent: $msg"
    date=`date +'%T'`
    echo "$date flexa-agent: $msg"
}

FLEXABASEDIR=/mnt/data

device=$( qiba-spi-get-production-info.sh -c )
echo $device
if [ "${device}" == "Undefined" ] ; then
  echo "setting regid paths for Barionet"

  # device is a barionet  
  CONFDIR=/mnt/data/config
  REGIDJSON=/mnt/config/config.json
  device="barionet"
else
  echo "Setting regid paths for IPAM"
  # device is an ipam400 
  CONFDIR=${FLEXABASEDIR}/config
  REGIDPATH=${FLEXABASEDIR}/regId
  REGIDJSON=/mnt/shadow/config.json
  device="ipam400"
fi


TMPDIR=${FLEXABASEDIR}/tmp
NEWPACKAGE=${FLEXABASEDIR}/new_package
PACKAGENAME=package
PACKAGEZIP=${PACKAGENAME}.zip
PACKAGEPATH=${FLEXABASEDIR}/${PACKAGENAME}
ZIPPATH=${FLEXABASEDIR}/package.zip
SERVICEINFO=${CONFDIR}/service.json
APPINFO=${CONFDIR}/app.json
CONFIGFILE="config.json"
CONFIGPATH=${PACKAGEPATH}/${CONFIGFILE}
STATE=${CONFDIR}/state.json
EXIT_CODE=0

if [ "${device}" == "barionet" ] ; then 
  echo "setting paths for Barionet"
  tpl_path=/etc/config/flexa_app_tpl
  uci_config_path=/etc/config/flexa_app
else 
  echo "Setting paths for IPAM"
  tpl_path=/barix/local/config/flexa_app_tpl
  uci_config_path=/barix/local/config/flexa_app
fi

mkdir -p ${FLEXABASEDIR}
mkdir -p ${NEWPACKAGE}
mkdir -p ${CONFDIR}

do_reboot=false
do_restart_app=false
do_reset_uci=true
max_timeout=5  # timeout for flexa-calls
n_reconnects=0
update_rate=0
max_reconnects=3
version=$( uci get flexa_agent.service.package_version )   
registry_url=$( uci get flexa_agent.registry.registry_url )


usage() {
  echo " "
  echo "-------------------------------------------------------------------------------------"
  echo "no argument:                 checks status and takes required actions"
  echo "full                         contact service or flexa registry"
  echo "usb [mountdir]               checks [mountdir] for new package"
  echo "reset                        resets uci configuration"
  echo "clean                        resets uci configuration and removes installed packages"
  echo "install <package> [version]  installs a package located under <package> with [version]"
  echo "config <file>                installs an application configuration <file> (JSON format)"
  echo "-------------------------------------------------------------------------------------"
}


clean() {
  echo "removing old package and config..."
  if [ -d ${PACKAGEPATH} ]; then 
    rm -rf ${PACKAGEPATH}
  fi
  if [ -d ${NEWPACKAGE} ]; then
    rm -rf ${NEWPACKAGE}
  fi
  if [ -f ${ZIPPATH} ]; then 
    rm -rf ${ZIPPATH}
  fi
  if [ -d ${CONFDIR} ]; then 
    rm ${CONFDIR}/*
  fi
  echo "removing old package and config... Done!"
}

decompress_package() {
    zipFile=$1
    destPath=$2
    unzip -o "${zipFile}" -d "${destPath}" || tar -xvf "${zipFile}" -C "${destPath}" || \
        tar -xzvf "${zipFile}" -C "${destPath}" || tar -xjvf "${zipFile}" -C "${destPath}"
}


install_config() {
    config_src=$1
    config_tmp="/tmp/${CONFIGFILE}"

    loga "installing configuration file ${config_src}..."

    if [ ! -f "${config_src}" ]; then
        loga "installing configuration file ${config_src}... no file found!"
        return 1
    fi

    if [ ! -f "${ZIPPATH}" ]; then
        loga "installing configuration file ${config_src}... no package actual installed!"
        return 1
    fi

    # parse config file to check its format
    json_content=$(jq . "${config_src}" 2>/dev/null)
    if [ $? -ne 0 ] || [ -z "${json_content}" ]; then
        loga "installing configuration file ${config_src}... parse error!"
        return 2
    fi

    echo -e "{\n\"AppParam\": $(cat "${config_src}")\n}" > ${config_tmp}
    MD5SUMNEW=$( md5sum "${config_tmp}" | awk '{ print $1 }' )
    if [ -f "${CONFIGPATH}" ]; then
        MD5SUMOLD=$( md5sum "${CONFIGPATH}" | awk '{ print $1 }' )
    else
        MD5SUMOLD=0
    fi
    if [ ${MD5SUMNEW} != ${MD5SUMOLD} ]; then
        cp -f "${config_tmp}" /root/flexa/config
        mv -f "${config_tmp}" "${CONFIGPATH}"
        # app_param_to_uci always expects to have an AppParam object inside the file
        app_param_to_uci ${CONFIGPATH}
        loga "installing configuration file ${config_src}... done!"
        do_restart_app=true
        sync
    else
        rm -f "${config_tmp}"
        loga "installing configuration file ${config_src}... no new configuration found!"
        return 3
    fi
}


install_package() {
    package_src=$1
    force=$2
    config_backup="/tmp/config.json"

    loga "installing new application package ${package_src}..."
    if [ ! -f "${package_src}" ]; then
        loga "installing new application package ${package_src}... package not found!"
        return 1
    fi

    if [ -f "${ZIPPATH}" ];then
        MD5SUMOLD=$( md5sum ${ZIPPATH} | awk '{ print $1 }' )
    else
        MD5SUMOLD=0
    fi
    MD5SUMNEW=$( md5sum "${package_src}" | awk '{ print $1 }' )
    loga ${MD5SUMNEW} " " ${MD5SUMOLD}
    if [ ${MD5SUMNEW} != ${MD5SUMOLD} ] || [ -n "$force" ]; then
        reset_flexa_agent_config
        loga "installing new application package ${package_src}... new package found, installing..."
        decompress_package "${package_src}" "${NEWPACKAGE}"
        if [ $? -ne 0 ]; then
            loga "installing new application package ${package_src}... error decompressing the package!!"
            return 2
        fi
        cp -f "${package_src}" "${ZIPPATH}"
        # backup the configuration file
        [ -f "${CONFIGPATH}" ] && cp -f "${CONFIGPATH}" "${config_backup}"
        rm -rf ${PACKAGEPATH}
        mkdir -p ${PACKAGEPATH}
        /usr/bin/flexa-install --install ${NEWPACKAGE}
        if [ $? -ne 0 ]; then
            loga "error installing package"
            rm -rf ${NEWPACKAGE}
            rm -f ${config_backup}
            return 3
        fi

        [ -f "${config_backup}" ] && cp -f "${config_backup}" "${CONFIGPATH}"
        loga "installing new application package ${package_src}... done!"
    else
        loga "installing new application package ${config_src}... no new application found!"
        return 4
    fi
}


get_registration_id() {
  # flexa prototypes have the regid written to /mnt/data/regid
  # produced devices have the regid inside the config.json in 
  # /mnt/shadow/config.json
  # if the device has no regid at all, flexa will not work! 
  if [ -f "${REGIDJSON}" ]; then
    regid=$( jq -r '.registrationId' ${REGIDJSON} )
    uci set flexa_agent.registry.regid=${regid}
    uci commit flexa_agent
    # also writes the regId into /root/flexa/regId for compatibility porpuses
    readValue=$(cat /root/flexa/regId)
    if [ "${readValue}" != "${regid}" ]; then
        logger "Store regid under /root/flexa/regId"
        echo -ne "${regid}" > /root/flexa/regId
    fi
  elif [ -f "${REGIDPATH}" ]; then
    regid=$(cat ${REGIDPATH} )
    uci set flexa_agent.registry.regid=${regid}
    uci commit flexa_agent
  else
    logger "ERROR: Device has no registration ID assigned!"
    echo "ERROR: Device has no registration ID assigned!"
  fi 
}

# request the app configuration from the portal and store them
# in the device
request_config() {
    TMP_CONFIGPATH=$(mktemp)
    loga "Request configuration..."
    get_config ${TMP_CONFIGPATH} ${regid} ${config_url}
    if [ $? -eq 0 ]; then
        loga "Request configuration... Done!"
        if [ -f "${CONFIGPATH}" ]; then
            CONFIG_MD5_OLD=$( md5sum ${CONFIGPATH} | awk '{ print $1 }' )
        else
            CONFIG_MD5_OLD=0
        fi
        CONFIG_MD5_NEW=$( md5sum ${TMP_CONFIGPATH} | awk '{ print $1 }' )
        if [ ${CONFIG_MD5_OLD} != ${CONFIG_MD5_NEW} ]; then
            # this /root/flexa/config is used by some flexa apps
            jq -M .AppParam ${TMP_CONFIGPATH} > /root/flexa/config
            cp -f ${TMP_CONFIGPATH} ${CONFIGPATH}
            do_restart_app=true
            sync
        else
            # check if /root/flexa/config is consistent
            TMP_ROOTCONF=$(mktemp)
            jq -M .AppParam ${TMP_CONFIGPATH} > ${TMP_ROOTCONF}
            CONFIG_MD5_NEW=$(md5sum ${TMP_ROOTCONF} | awk '{ print $1 }')
            if [ -f /root/flexa/config ]; then
                CONFIG_MD5_OLD=$(md5sum /root/flexa/config | awk '{ print $1 }')
            else
                CONFIG_MD5_OLD=0
            fi
            if [ ${CONFIG_MD5_OLD} != ${CONFIG_MD5_NEW} ]; then
                mv -f ${TMP_ROOTCONF} /root/flexa/config
                sync
            else
                rm -f ${TMP_ROOTCONF}
            fi
        fi
    else
        loga "Request configuration... ERROR!"
    fi
    rm -f ${TMP_CONFIGPATH}
}

contact_registry() {
    loga "Contacting registry..."
    registry_response=$( request_registry_info ${SERVICEINFO} ${regid} ${registry_url} )
    echo "Registry response: "${registry_response}
    if [ "${registry_response}" = "200" ]; then
        echo -n $(uci -q get flexa_agent.service.service_url) > /root/flexa/url
    else 
        loga "Contacting registry failed, exit agent!"
        return 1
    fi
    loga "Contacting registry... Done!"
    return 0
}


check_appl_status() {
    loga "Check state..."

    service_url=$( uci get flexa_agent.service.service_url )
    if [ "${service_url}" != "changeme" ] ; then
        # fix old versions that were not creating this file
        if [ ! -f /root/flexa/url ]; then
            echo -n $(uci -q get flexa_agent.service.service_url) > /root/flexa/url
        fi

        echo "request status: "${STATE} ${regid} ${service_url} 
        request_status_info ${STATE} ${regid} ${service_url}
        ret=$?
        if [ $ret -eq 0 ]; then

            state=$( jq -r '.config' ${STATE} ) 
            if [ ${state} = "sync" ]; then
                logger "application in sync with service configuration. Stopping flexa-client."
                echo "application in sync... exit agent!"
                update_rate_to_uci ${CONFIGPATH}
            else
                echo "application not in sync... contact service!"
                return 1
            fi
        elif [ $ret -eq 2 ]; then
            return 2
        else
            update_rate_to_uci ${CONFIGPATH}
        fi
    else
        echo "status url not known -> contact service "
        return 2
    fi

    return 0
}


contact_service() {
    loga "Contacting service..."
    service_url=$( uci get flexa_agent.service.service_url )
    if [ "${service_url}" = "changeme" ]; then
        loga "Service URL not kown -> contact registry"
        contact_registry
        if [ $? -ne 0 ]; then
            return 1
        fi
        service_url=$( uci get flexa_agent.service.service_url )
    fi

    request_service_info ${APPINFO} ${regid} ${service_url}
    ret=$?
    if [ $ret -eq 2 ]; then
        loga "Contacting service... device not found!"
        loga "Retrying the registry..."
        contact_registry
        if [ $? -ne 0 ]; then
            schedule_agent
            return 1
        fi
        service_url=$( uci get flexa_agent.service.service_url )
        request_service_info ${APPINFO} ${regid} ${service_url}
        ret=$?
    fi

    if [ $ret -eq 0 ]; then
        getConfigUrl=$( jq -r '.getConfigUrl' ${APPINFO} | awk '{ print $2 }' )
        config_url=$( uci get flexa_agent.service.config_url )
        package_url=$( uci get flexa_agent.service.package_url )
        new_version=$( get_app_version ${APPINFO} )
        loga "Contacting service: downloading package..."
        get_package ${new_version} "${package_url}" ${ZIPPATH}
        ret_download=$?
        if [ $ret_download -eq 0 ]; then
            loga "Contacting service: downloading package... Done!"
            loga "Contacting service: installing package..."
            # dealing with change in extension.	    
            decompress_package "${ZIPPATH}" "${NEWPACKAGE}"
            if [ $? -eq 0 ]; then
                rm -rf ${PACKAGEPATH}
                mkdir -p ${PACKAGEPATH}
                flexa-install --install ${NEWPACKAGE}
                if [ $? -eq 0 ]; then
                    do_reboot=true
                    set_package_version "${new_version}"
                    loga "Contacting service: installing package... Done!"
                else
                    ret_download=1
                    loga "Contacting service: failed to install the package!"
                fi
                # NEWPACKAGE is remove inside flexa-install only if everything succeeds
                rm -rf ${NEWPACKAGE}
            else
                loga "Contacting: failed to install the package!"
                rm -rf ${PACKAGEPATH}
                ret_download=1
            fi
        fi

        if [ $ret_download -eq 1 ]; then
            # Failed to download the package.. lets retry
            schedule_agent
            return 1
        fi
    else
        loga "Contacting service... request error!"
        return 2
    fi

    loga "Contacting service... Done!"
    return 0
}


# checks if the inserted usb-drive has a different application
# package than the one installed at /mnt/data
# 
# parameters:
#   $1: mount-dir

get_app_usb() {
    TMP_ZIPPATH="/tmp/package.zip"

    usb_update=$(uci get flexa_agent.service.enable_usb_update)
    if [ "${usb_update}" = "false" ]; then
        loga "USB Application Package update is disabled"
        exit 1
    fi

    loga "Check usb drive ${1} for application package..."

    PACKAGE_USB="${1}/${PACKAGEZIP}"
    for package in package.zip package.tar package.tar.gz package.tar.bz2; do
        if [ -f "${1}/${package}" ]; then
            PACKAGE_USB="${1}/${package}"
            break
        fi
    done

    install_package "${PACKAGE_USB}"
    if [ $? -eq 0 ]; then
        do_reboot=true
    fi

    # Install also the configuration file
    loga "check usb drive ${1} for configuration file..."
    TMP_CONFIG="/tmp/${CONFIGFILE}"
    REGID=$(uci -q get flexa_agent.registry.regid)
    if [ -f "${1}/${CONFIGFILE}" ]; then
        CONFIG_USB="${1}/${CONFIGFILE}"
    elif [ -f "${1}/${REGID}.json" ]; then
        CONFIG_USB="${1}/${REGID}.json"
    fi
    if [ -n "${CONFIG_USB}" ] && [ -f "${CONFIG_USB}" ]; then
        loga "check usb drive ${1} for configuration file... file ${CONFIG_USB} found"
        install_config "${CONFIG_USB}"
    else
        loga "check usb drive ${1} for configuration file... file not found"
    fi
}


if [ $# -eq 0 ]; then
  enabled=$(uci -q get flexa_agent.service.enabled)
  if [ "$enabled" == "false" ] || [ "$enabled" == "0" ]; then
    loga "Flexa agent not enabled"
    exit 0
  fi

  get_registration_id

  check_flexa_directories "${SERVICEINFO}" "${APPINFO}"
  dir_ok=$?

  # first time to run we need to contact the service
  if [ ! -f /tmp/flexa-firstboot ] || [ ${dir_ok} -ne 0 ]; then
    contact_service
    if [ $? -eq 0 ]; then
      check_appl_status
      request_config
      touch /tmp/flexa-firstboot
    fi
  elif [ ${dir_ok} -eq 0 ]; then
    check_appl_status
    ret=$?
    if [ $ret -eq 1 ]; then
      contact_service && request_config
    elif [ $ret -eq 2 ]; then
      contact_service && request_config
      if [ $? -eq 1 ]; then
        loga "device not found in the service portal. Trying the registry..."
        reset_flexa_agent_config
        contact_service
        if [ $? -eq 0 ]; then
          check_appl_status
          request_config
        fi
      fi
    fi
  fi

elif [ $1 = "clean" ]; then
  clean
  reset_flexa_agent_config
  reset_flexa_app_config ${tpl_path} ${uci_config_path}

elif [ $1 = "reset" ]; then

  reset_flexa_agent_config
  reset_flexa_app_config ${tpl_path} ${uci_config_path}

elif [ $1 = "install" ]; then
  package_src=$2
  new_version=$3
  install_package "${package_src}" "force"
  if [ $? -eq 0 ]; then
      [ -n "${new_version}" ] && set_package_version "${new_version}"
      do_reboot=true
  fi

elif [ $1 = "usb" ]; then
  get_registration_id
  if [ -d "$2" ]; then
    get_app_usb $2
  else
    usage
  fi

elif [ $1 = "config" ]; then
  confFile=$2
  install_config "${confFile}"
  EXIT_CODE=$?

elif [ $1 = "help" ]; then

  usage
fi


if ${do_reboot}; then
    reboot
elif ${do_restart_app}; then
    if [ -f /barix/hooks/application/sdf ]; then
        /barix/hooks/application/sdf restart
    fi
    /etc/init.d/run-flexa restart
fi

exit $EXIT_CODE
