#!/bin/bash

# The provisioning (dependency manifest)
MANIFEST="./provisioning/p_manifest.json"

COMPONENT_NAME="NODE_RED_INSTALL"

function notify_info() {
    notify_system "$COMPONENT_NAME" "INFO" "$@" >/dev/null 2>&1 &
}

function notify_warn() {
    notify_system "$COMPONENT_NAME" "WARNING" "$@" >/dev/null 2>&1 &
}

function notify_error() {
    notify_system "$COMPONENT_NAME" "ERROR" "$@" >/dev/null 2>&1 &
}

function log_info() {
    echo "$1"
    logger -p info -t $COMPONENT_NAME "$1" 1>&2
}

function log_warn() {
    echo "$1"
    logger -p warning -t $COMPONENT_NAME "$1" 1>&2
}

function log_error() {
    echo "$1"
    logger -p error -t $COMPONENT_NAME "$1" 1>&2
}

function install_package() {
    local PACKAGE="$1"
    local OUTPUT
    local RET

    OUTPUT=$(opkg install "$PACKAGE" 2>&1)
    RET=$?

    if [[ "$RET" -eq 0 ]]; then
        return 0
    fi

    # Install failed. Try to analyze why.
    if [[ "$OUTPUT" == *"as it matches the installed version"* ]]; then
        log_warn "Dependency [$PACKAGE] version matches the installed version, skipped"
        return 0
    fi

    # Install failed, dependency is not installed
    log_error "Failed to install dependency: [$OUTPUT]"
    return $RET
}

function remove_package() {
    local PACKAGE="$1"
    local OUTPUT
    local RET

    OUTPUT=$(opkg remove "$PACKAGE" 2>&1)
    RET=$?

    if [[ "$RET" -eq 0 ]]; then
        return 0
    fi

    # Remove failed, dependency is not removed
    log_error "Failed to remove dependency: [$OUTPUT]"
    return $RET
}

function install_packages {
    local JSONTXT
    local PKGCNT
    local RET
    local PKG
    local PKGFILE
    local PKGTYPE
    local PKGNAME
    local MESSAGE
    local DISPLAY_INDEX

    if [ ! -f "$MANIFEST" ]; then
        log_info "p_manifest.json file is not present, skipped dependency installation"
        return 0
    fi

    JSONTXT=$(<./provisioning/p_manifest.json)
    PKGCNT=$(echo "$JSONTXT" | jsparser --count -p /pkgs)
    
    RET=$?
    if [ $RET -ne 0 ]; then
        log_error "Failed to parse p_manifest.json as json"
        return $RET
    fi

    notify_warn "Node-RED installation can take up to 10 minutes and reboot will be required. Please wait."

    for ((i=0; i < PKGCNT; i++))
    do
        DISPLAY_INDEX=$(( $i + 1 ))
        PKG=$(echo "$JSONTXT" | jsparser --jsobj -p /pkgs/$i)
        PKGFILE=$(echo "$PKG" | jsparser -p /FileName)
        PKGTYPE=$(echo "$PKG" | jsparser -p /type)
        PKGNAME=$(echo "$PKG" | jsparser -p /PkgName)

        if [ "$PKGTYPE" == "ipk" ]; then
            log_info "Installing dependency [$PKGNAME][$DISPLAY_INDEX/$PKGCNT]..."
            install_package "./provisioning/$PKGFILE"
            RET=$?
            if [[ $RET -ne 0 ]]; then
                log_error "Dependency [$PKGNAME] installation failed with status $RET"
                return $RET
            fi
        fi
        MESSAGE="Installed dependency [$PKGNAME][$DISPLAY_INDEX/$PKGCNT]"
        log_info "$MESSAGE"
        notify_info "$MESSAGE"
    done

    return 0
}

function post_install {
    local MESSAGE

    # The new mechanism
    post-upgrade-request-reboot "node-red custom app"

    # The new mechanism failed, manual reboot is required
    if [[ $? -ne 0 ]]; then
        MESSAGE="Please reboot the device manually to finish Node-RED installation"
        log_warn "$MESSAGE"
        notify_warn "$MESSAGE"
    fi

    return 0
}

function remove_packages {
    local JSONTXT
    local PKGCNT
    local RET
    local PKG
    local PKG_INDEX
    local PKGFILE
    local PKGTYPE
    local PKGNAME
    local MESSAGE
    local DISPLAY_INDEX

    if [ ! -f "$MANIFEST" ]; then
        log_info "p_manifest.json file is not present, skipped dependency removal"
        return 0
    fi

    JSONTXT=$(<./provisioning/p_manifest.json)
    PKGCNT=$(echo "$JSONTXT" | jsparser --count -p /pkgs)
    
    RET=$?
    if [ $RET -ne 0 ]; then
        log_error "Failed to parse p_manifest.json as json"
        return $RET
    fi

    notify_warn "Node-RED removal can take up to 5 minutes. Please wait."

    for ((i=0; i < PKGCNT; i++))
    do
        # remove in reverse
        DISPLAY_INDEX=$(( $i + 1 ))
        PKG_INDEX=$(($PKGCNT - 1 - $i))
        PKG=$(echo "$JSONTXT" | jsparser --jsobj -p /pkgs/$PKG_INDEX)
        PKGTYPE=$(echo $PKG | jsparser -p /type)
        PKGNAME=$(echo $PKG | jsparser -p /PkgName)

        if [ "$PKGTYPE" == "ipk" ]; then
            notify_info "Removing dependency: [$PKGNAME][$DISPLAY_INDEX/$PKGCNT]..."
            remove_package "$PKGNAME"
            RET=$?
            if [[ $RET -ne 0 ]]; then
                log_error "Dependency [$PKGNAME] removal failed with status $RET"
                return $RET
            fi
        fi
        MESSAGE="Removed dependency [$PKGNAME][$DISPLAY_INDEX/$PKGCNT]"
        log_info "$MESSAGE"
        notify_info "$MESSAGE"
    done

    return 0
}

function check_device_model() {
    local RET
    local HW_VERSION
    local SUPPORTED_DEVICES

    HW_VERSION=$(cat /sys/devices/platform/mts-io/hw-version)
    SUPPORTED_DEVICES="mtcdt|mtcdtip|mtcdtiphp|mtcap"

    shopt -s nocasematch
    if [[ "$HW_VERSION" =~ ^${SUPPORTED_DEVICES}- ]]; then
        RET=0
    else
        RET=1
    fi
    shopt -u nocasematch

    return $RET
}

function check_persistent() {
    # /var/persistent was added to Atmel-based devices in mPower 5.3.3 and can be used as an indicator.
    if [[ -d /var/persistent ]]; then
        return 0
    fi

    return 1
}

function check_python_version() {
    local RET
    local OUTPUT
    local PY_VERSION

    OUTPUT=$(python2 --version 2>&1)
    RET=$?

    if [[ $RET -ne 0 ]]; then
        log_error "Failed to detect the Python version: [$RET][$OUTPUT]"
        return 2
    fi

    PY_VERSION="${OUTPUT##* }"
    log_info "Detected the Python version: [$PY_VERSION]"

    if [[ "$PY_VERSION" != "2.7.15" ]]; then
        # We don't have the correct dependency packages for this version of Python.
        return 1
    fi

    return 0
}

function check_compatibility() {
    if ! check_device_model; then
        log_error "This application is compatible only with MTCDT, MTCDTIP, MTCDTIPHP and MTCAP devices"
        return 1
    fi

    if ! check_persistent; then
        log_error "This application requires mPower 5.3.3 or newer for successful installation"
        return 1
    fi

    if ! check_python_version; then
        log_error "This application is not compatible with the current version of Python. Please update the application to a newer version"
        return 1
    fi

    return 0
}


case "$1" in
    install)
        if ! check_compatibility; then
            exit 2
        fi

        install_packages
        exit $?
        ;;
    postinstall)
        post_install
        exit $?
        ;;
    remove)
        remove_packages
        exit $?
        ;;
  *)
      echo "Usage: $0 {install|postinstall|remove}" >&2
      exit 1
      ;;
esac

exit 0
