#!/bin/bash
#
# Copyright (C) 2023 MOXA Inc. All rights reserved.
# This software is distributed under the terms of the MOXA SOFTWARE NOTICE.
# See the file LICENSE for details.
#
# Authors:
#       2023  Wilson YS Huang  <wilsonys.huang@moxa.com>

# Don't warn about unreachable commands in this file
# Don't info about to read lines rather than words, pipe/redirect to a 'while read' loop
# shellcheck disable=SC2317,SC2013

source "${INSTL_SCRIPT_DIR}/lib/util.sh"
source "${INSTL_SCRIPT_DIR}/lib/logger.sh"
source "${INSTL_SCRIPT_DIR}/lib/version.sh"
log::init "${INSTL_LOG_FILE}" "${INSTL_LOG_LEVEL}"

package_install=()

set -e

process_file_install() {
        local repo_name="$1"
        local repo_tag="$2"
        local repo_ver
        local src_ver
        local cmp_ver

        if util::is_exists "${INSTL_TOP_DIR}/src/${repo_name}-${repo_tag}/version"; then
                repo_ver="$(cat "${INSTL_TOP_DIR}"/src/"${repo_name}"-"${repo_tag}"/version)"
        else
                repo_ver="unknown"
        fi

        if [[ $INSTL_FORCE_INSTALL = true ]]; then
                if util::confirm_prompt "Do you want to install ${repo_name} (${repo_ver})?" "${INSTL_PROMPT_AUTO_YES}"; then
                        source "${INSTL_SCRIPT_DIR}/install.d/${repo_name}.install.sh" "${repo_tag}" "${repo_ver}"

                        if grep -q "${repo_name}" "$INSTL_SRC_VERSION_FILE"; then
                                sed -i "/^$repo_name/s/:\([^:]*\)$/:$repo_ver/" "${INSTL_SRC_VERSION_FILE}"
                        else
                                echo "${repo_name}:${repo_ver}" >>"$INSTL_SRC_VERSION_FILE"
                        fi

                        return 0
                else
                        log::info "Skip install ${repo_name}"
                        return 1
                fi
        else
                if util::is_exists "${INSTL_SRC_VERSION_FILE}" && grep -wq "${repo_name}" "${INSTL_SRC_VERSION_FILE}"; then
                        src_ver=$(grep -w "${repo_name}" "${INSTL_SRC_VERSION_FILE}" | awk -F ':' '{print $2}')

                        cmp_ver=$(ver::compare "$repo_ver" "$src_ver")

                        if [[ $cmp_ver -eq 0 ]]; then
                                log::info "$repo_name is already the latest version ($repo_ver)"
                                return 1
                        elif [[ $cmp_ver -lt 0 ]]; then
                                log::info "$repo_name is already the newest version ($src_ver)"
                                log::info " An OLD version of $repo_name is found ($repo_ver)"
                                log::info " If you want to install, please use the --force option"
                                return 1
                        elif [[ $cmp_ver -gt 0 ]]; then
                                log::info "A NEW version of $repo_name is available ($src_ver -> $repo_ver)"
                                if util::confirm_prompt "Do you want to install?" "${INSTL_PROMPT_AUTO_YES}"; then
                                        source "${INSTL_SCRIPT_DIR}/install.d/${repo_name}.install.sh" "${repo_tag}" "${repo_ver}"
                                        sed -i "/^$repo_name/s/:\([^:]*\)$/:$repo_ver/" "${INSTL_SRC_VERSION_FILE}"

                                        return 0
                                else
                                        log::info "Skip install newer ${repo_name}"

                                        return 1
                                fi
                        fi
                else
                        if util::confirm_prompt "Do you want to install ${repo_name} (${repo_ver})?" "${INSTL_PROMPT_AUTO_YES}"; then
                                source "${INSTL_SCRIPT_DIR}/install.d/${repo_name}.install.sh" "${repo_tag}" "${repo_ver}"
                                echo "${repo_name}:${repo_ver}" >>"$INSTL_SRC_VERSION_FILE"

                                return 0
                        else
                                log::info "Skip install ${repo_name}"

                                return 1
                        fi
                fi
        fi

        return 1
}

process_config_install() {
        local src_name="$1"
        local src_path="$2"
        local dst_path="$3"
        local ret_val=0
        local install_path

        if util::is_dir "${dst_path}"; then
                install_path="${dst_path}${src_name}"
        else
                install_path="${dst_path}"
        fi

        if [[ $INSTL_FORCE_INSTALL = true ]]; then
                if util::confirm_prompt "Do you want to install ${src_path} to ${install_path}?" "${INSTL_PROMPT_AUTO_YES}"; then
                        install -D -m "$(stat -c '%a' "${src_path}")" "${src_path}" "${install_path}"
                        return 0
                else
                        log::info "Skip install ${src_name}"
                        return 1
                fi
        else
                if util::is_file "${install_path}"; then

                        diff "${src_path}" "${install_path}" >/dev/null
                        ret_val=${?}

                        if [[ $ret_val -eq 0 ]]; then
                                log::info "${src_name} in ${install_path} is installed"
                                log::info " If you want to install, please use the --force option"
                                return 1
                        elif [[ $ret_val -gt 0 ]]; then
                                log::info "A NEW version of $src_name is available"
                                if util::confirm_prompt "Do you want to install?" "${INSTL_PROMPT_AUTO_YES}"; then
                                        log::info "Install newer $src_name"
                                        install -Dm644 "${src_path}" "${install_path}"
                                        return 0
                                else
                                        log::info "Skip install newer ${src_name}"
                                        return 1
                                fi
                        fi
                else
                        if util::confirm_prompt "Do you want to install ${src_name} to ${install_path}?" "${INSTL_PROMPT_AUTO_YES}"; then
                                log::info "Install $src_name into $install_path"
                                install -D -m "$(stat -c '%a' "${src_path}")" "${src_path}" "${install_path}"
                                return 0
                        else
                                log::info "Skip install ${src_name}"
                                return 1
                        fi
                fi
        fi

        return 1
}

process_package_compose() {
        local pkg_name="$1"
        local pkg_ver="$2"

        for pkg_file in "${INSTL_TOP_DIR}"/pkg/"${pkg_name}"/"${pkg_ver}"/*.deb; do
                package_install+=("$pkg_file")
        done
}

process_package_install() {
        if util::confirm_prompt "Do you want to install packages? these packages will be install ${package_install[*]}" "${INSTL_PROMPT_AUTO_YES}"; then
                apt -y install "${package_install[@]}"
                return 0
        else
                log::info "Skip install packages"
                return 1
        fi

        return 1
}

main() {
        local drivers_list
        local tools_list
        local driver_available
        local tool_available
        local file_available
        local pkg_available

        driver_available=true
        tool_available=true
        file_available=true
        pkg_available=true

        if util::is_exists "${INSTL_PRODUCT_DIR}/${BOARD_ID}/preinst.sh"; then
                log::info "=== Run pre-install"
                source "${INSTL_PRODUCT_DIR}/${BOARD_ID}/preinst.sh"
        fi

        if ! util::is_exists "${INSTL_CONF_DIR}"; then
                mkdir "${INSTL_CONF_DIR}"
        fi

        if ! util::is_exists "${INSTL_SRC_VERSION_FILE}"; then
                touch "${INSTL_SRC_VERSION_FILE}"
        fi

        if [[ -z "${IS_CUSTOM_CONFIG_FILE}" ]]; then
                log::info "=== Install driver"
                drivers_list="${INSTL_PRODUCT_DIR}/${BOARD_ID}/drivers"
                if ! util::parse_product_file "${drivers_list}" "${LINUX_KERNEL_MAJOR_VER}" "${LINUX_KERNEL_MINOR_VER}" process_file_install; then
                        driver_available=false
                fi

                log::info "=== Install tool"
                tools_list="${INSTL_PRODUCT_DIR}/${BOARD_ID}/tools"
                if ! util::parse_product_file "${tools_list}" "${LINUX_KERNEL_MAJOR_VER}" "${LINUX_KERNEL_MINOR_VER}" process_file_install; then
                        tool_available=false
                fi
        else
                log::info "=== Install the components of custom config list"
                # parse custom config list
                for line in $(cat "${INSTL_CUSTOM_CONFIG_FILE}"); do
                        repo_name="${line%%(*}"
                        repo_tag="${line#*\(}"
                        repo_tag="${repo_tag%\)}"
                        if ! process_file_install "${repo_name}" "${repo_tag}"; then
                                tool_available=false
                        fi
                done
        fi

        if [ -n "${LINUX_DISTRO_VERSION_CODENAME}" ]; then
                codename="${LINUX_DISTRO_VERSION_CODENAME}"
        elif [ "${LINUX_DISTRO_ID}" = "rhel" ] || [ "${LINUX_DISTRO_ID}" = "rocky" ]; then
                codename="${LINUX_DISTRO_ID}_$(echo "${LINUX_DISTRO_VERSION}" | sed -n 's/.*(\(.*\)).*/\1/p')"
        else
                codename="${LINUX_DISTRO_ID}_${LINUX_DISTRO_VERSION_ID}"
        fi

        files_list="${INSTL_PRODUCT_DIR}/${BOARD_ID}/files"
        if util::is_exists "${files_list}"; then
                log::info "=== Install file"
                if ! util::parse_product_file_from_codename "${files_list}" "${codename}" process_config_install; then
                        file_available=false
                fi
        fi

        pkg_list="${INSTL_PRODUCT_DIR}/${BOARD_ID}/packages"
        if util::is_exists "${pkg_list}"; then
                log::info "=== Install 3rd-party packages"
                if ! util::parse_product_file_from_codename "${pkg_list}" "${codename}" process_package_compose; then
                        pkg_available=false
                fi
                process_package_install
        fi

        if [[ $driver_available = false ]] && [[ $tool_available = false ]] && [[ $file_available = false ]] && [[ $pkg_available = false ]]; then
                exit 3
        else
                if util::is_exists "${INSTL_PRODUCT_DIR}/${BOARD_ID}/postinst.sh"; then
                        log::info "=== Run post-install"
                        source "${INSTL_PRODUCT_DIR}/${BOARD_ID}/postinst.sh"
                fi

                exit 0
        fi
}

main
