#!/bin/bash
set -e
set -u

PATH=/bin:/usr/bin:/sbin:/usr/sbin
ISU_PKGS_PATH=/opt/isu

readonly PKG_FILE_NOT_EXIST=100
readonly PKG_INSTALL_ERROR=101
readonly INVALID_ISU_CFG_PKG_NAME=102
readonly CHECKUM_ERROR=103
readonly PKG_ALERADY_INSTALLED=104

function print_remove_help()
{
    if [ -z "${1:-}" ]; then
        echo ""
        echo "Usage:"
        echo -n "  $0"
    fi

    echo " remove <pkg_name>           - remove ISU package"
}

function print_install_help()
{
    if [ -z "${1:-}" ]; then
        echo ""
        echo "Usage:"
        echo -n "  $0"
    fi

    echo " install [-f|-r] <pkg_file>  - install ISU package"
    echo "         -f                  - Install even when the package is already installed"
    echo "         -r                  - Restart systemd service after package installation"
    echo "                               (for development purposes only)"
}

function print_help()
{
    echo ""
    echo "ISU Package Manager"
    echo
    echo "Usage:"
    echo "  $0 <command>"
    echo
    echo "commands:"
    echo " list                        - list installed packages"
    print_install_help x
    print_remove_help x
}

function list_pkgs()
{
    echo "Installed ISU packages:"
    for pkg_path in "$ISU_PKGS_PATH"/*; do
        if [ ! -d "$pkg_path" ]; then
            continue
        fi
        local version=$(grep -e '^version' "$pkg_path/isu.cfg" 2>/dev/null | awk -F '=' '{gsub(/[ ]+/,""); print $2}')
        local pkg_name=$(basename "$pkg_path")
        echo "$pkg_name ($version)"
    done
}

function verify_checksum()
{
    local pkg_path="$1"
    pushd "$pkg_path" > /dev/null
    sha256sum -c "checksum.sha256" > /dev/null
    local res=$?
    popd > /dev/null
    return $res
}

function fixup_permissions()
{
    local pkg_path="$1"
    find "$pkg_path" \
          \( -type f \( -exec chmod 644 '{}' \; -and -exec chsmack -a _ '{}' \; \) \) -o \
          \( -type d \( -exec chmod 755 '{}' \; -and -exec chsmack -a _ '{}' \; \) \)
    chmod 0400 "$pkg_path"/rootfs.img
    return 0
}

function install_pkg()
{
    local pkg_file="$1"
    local force=$2
    local restart_after_install=$3

    if [ ! -f "$pkg_file" ]; then
        echo "File $pkg_file not exist"
        return $PKG_FILE_NOT_EXIST
    fi

    local temp_path=$(mktemp -d)
    if ! unzip "$pkg_file" -d "$temp_path" > /dev/null; then
        echo "Unable to extract ISU package"
        return $PKG_INSTALL_ERROR
    fi

    if ! fixup_permissions "$temp_path"; then
        echo "Unable to santize ISU package files permissions"
        return $PKG_INSTALL_ERROR
    fi

    local pkg_name=$(grep -e '^name' "$temp_path/isu.cfg" | head -n 1 | awk -F '=' '{gsub(/[ ]+/,""); print $2}')
    if [ -z "$pkg_name" ]; then
        echo "Invalid package name in isu.cfg"
        return $INVALID_ISU_CFG_PKG_NAME
    fi

    if ! verify_checksum "$temp_path"; then
        echo "Checksum verification error"
        return $CHECKUM_ERROR
    fi

    local new_pkg_path="$ISU_PKGS_PATH/$pkg_name"

    if [ "$force" -eq 0 ] && [ -e "$new_pkg_path" ]; then
        echo "Package $pkg_name already installed. Uninstall the old version before installing the new one."
        return $PKG_ALERADY_INSTALLED
    fi

    if [ "$force" -eq 1 ]; then
        rm -rf "$new_pkg_path"
    fi

    mv "$temp_path" "$new_pkg_path"

    if [ "$restart_after_install" -eq 1 ]; then
        systemctl daemon-reload
        for service in "$ISU_PKGS_PATH/$pkg_name"/system-services/*.service; do
            systemctl restart $(basename "$service")
        done
    fi
    echo "Package $pkg_name has been installed"
}

function remove_pkg()
{
    local pkg_name="$1"
    local pkg_path="$ISU_PKGS_PATH/$pkg_name"
    if [ -d "$pkg_path" ]; then
        rm -rf "$pkg_path"
    else
        echo "Package $pkg_name is not installed"
    fi
}

script_name=$0
if [ $# -lt 1 ]; then
    print_help "$script_name"
    exit
fi

case $1 in
    list)
        list_pkgs
        ;;
    install)
        force=0
        restart_after_install=0
        shift 1

        while getopts "frh" arg; do
            case $arg in
                f)
                    force=1
                    ;;
                r)
                    restart_after_install=1
                    ;;
                *)
                    print_install_help
                    exit
                    ;;
            esac
        done

        shift $((OPTIND-1))

        if [ $# -lt 1 ]; then
            print_install_help
            exit
        fi
        install_pkg "$1" $force $restart_after_install
        ;;
    remove)
        shift 1
        while getopts "h" arg; do
            case $arg in
                *)
                    print_remove_help
                    exit
                    ;;
            esac
        done
        if [ $# -lt 1 ]; then
            print_remove_help
            exit
        fi
        remove_pkg "$1"
        ;;
    *)
        print_help "$script_name"
        ;;
esac
