#!/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:
#       2024  Wilson YS Huang  <wilsonys.huang@moxa.com>

util::is_root_user() {
        [[ "$(id -u)" -eq 0 ]]
}

util::is_dir() {
        [[ -d "$1" ]]
}

util::is_empty_str() {
        [[ -z "$1" ]]
}

util::is_exists() {
        [[ -e "$1" ]]
}

util::is_file() {
        [[ -f "$1" ]]
}

util::parse_product_file() {
        local file_path
        local kernel_major_ver
        local kernel_minor_ver
        local process_fn
        local repo_name
        local repo_tag
        local ret

        file_path="$1"
        kernel_major_ver="$2"
        kernel_minor_ver="$3"
        process_fn="$4"
        ret=1

        if util::is_exists "${file_path}"; then
                # Read from fd=3 instead of the stdin
                while read -u 3 -r line; do
                        # \[         Match an opening square bracket '['
                        # ([0-9]+)   Match and capture one or more digits (major version)
                        # (?:        Start of a non-capturing group (for optional minor version)
                        #   \.       Match a dot '.' (denoting a decimal point)
                        #   ([0-9]+) Match and capture one or more digits (minor version)
                        # )?         End of the non-capturing group, make it optional (minor version)
                        # \]         Match a closing square bracket ']'
                        if [[ $line =~ \[([0-9]+)(\.([0-9]+))?\] ]]; then
                                major_ver="${BASH_REMATCH[1]}"
                                minor_ver="${BASH_REMATCH[3]}"
                        elif ! util::is_empty_str "$line" && [[ "${kernel_major_ver}" == "${major_ver}" ]]; then
                                IFS=', ' read -r -a fields <<<"$line"

                                if [ ${#fields[@]} -ne 2 ]; then
                                        log::error "Invalid config format in line: $line"
                                        exit 1
                                fi

                                repo_name=${fields[0]}
                                repo_tag=${fields[1]}

                                log::debug "repo_name=${repo_name}"
                                log::debug "repo_tag=${repo_tag}"

                                if util::is_empty_str "${minor_ver}" || [[ "${kernel_minor_ver}" == "${minor_ver}" ]]; then
                                        $process_fn "${repo_name}" "${repo_tag}"
                                        ((ret *= $?))
                                fi
                        fi
                done 3<"${file_path}"
        fi

        return $ret
}

util::parse_product_file_from_codename() {
        local file_path
        local product_codename
        local kernel_minor_ver
        local process_fn
        local src_name
        local dst_path
        local ret

        file_path="$1"
        product_codename="$2"
        process_fn="$3"
        ret=1
        file_type=""
        if [[ "${file_path}" == *files ]]; then
                file_type="file"
        elif [[ "${file_path}" == *packages ]]; then
                file_type="package"
        fi

        if util::is_exists "${file_path}"; then
                # Read from fd=3 instead of the stdin
                while read -u 3 -r line; do
                        if [[ $line =~ ^\[(.*)\] ]]; then
                                parse_codename="${BASH_REMATCH[1]}"
                        elif ! util::is_empty_str "$line" && [[ "${product_codename}" == "${parse_codename}" ]]; then
                                IFS=', ' read -r -a fields <<<"$line"
                                if [[ "${file_type}" == "package" ]]; then
                                        if [ ${#fields[@]} -ne 2 ]; then
                                                log::error "Invalid config format in line: $line"
                                                exit 1
                                        fi

                                        pkg_name=${fields[0]}
                                        pkg_ver=${fields[1]}

                                        log::debug "pkg_name=${pkg_name}"
                                        log::debug "pkg_ver=${pkg_ver}"

                                        $process_fn "${pkg_name}" "${pkg_ver}"
                                        ((ret *= $?))
                                fi
                        else
                                IFS=', ' read -r -a fields <<<"$line"
                                if [[ "${file_type}" == "file" ]]; then
                                        if [ ${#fields[@]} -ne 2 ]; then
                                                log::error "Invalid config format in line: $line"
                                                exit 1
                                        fi

                                        src_name=${fields[0]}
                                        src_path=${INSTL_PRODUCT_DIR}/${BOARD_ID}/data/${src_name}
                                        dst_path=${fields[1]}

                                        log::debug "src_name=${src_name}"
                                        log::debug "src_path=${src_path}"
                                        log::debug "dst_path=${dst_path}"

                                        $process_fn "${src_name}" "${src_path}" "${dst_path}"
                                        ((ret *= $?))
                                fi
                        fi
                done 3<"${file_path}"
        fi

        return $ret
}

util::confirm_prompt() {
        local prompt_msg
        local auto_yes
        prompt_msg="$1"
        auto_yes="$2"

        if [[ $auto_yes = false ]]; then
                read -r -p "${prompt_msg} [Y/n]" response
                if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
                        return 0
                else
                        return 1
                fi
        else
                return 0
        fi
}

util::get_kernel_config_value() {
        local cfg_key
        local line
        local cfg_value

        cfg_key="$1"

        if [[ ! -f "/boot/config-$(uname -r)" ]]; then
                log::error "Cannot find kernel config"
                return 1
        fi

        line=$(grep "$cfg_key" "/boot/config-$(uname -r)")
        cfg_value="${line#*=}"

        echo "$cfg_value"
}

util::extract_compress_file() {
        local src=$1
        local dest="${2}"

        if ! util::is_file "${src}"; then
                log::info "${src} not exist"
                return 1
        fi

        if ! util::is_dir "${dest}"; then
                mkdir -p "$dest" || {
                        log::info "cannot creat folder ${dest}"
                        return 1
                }
        fi

        local mime
        mime=$(file -b --mime-type "$src")

        case "$mime" in
        application/zip) unzip -o "$src" -d "$dest" ;;
        application/gzip) gunzip -c "$src" >"$dest/$(basename "${src%.gz}")" ;;
        application/x-bzip2) bunzip2 -c "$src" >"$dest/$(basename "${src%.bz2}")" ;;
        application/x-xz) unxz -c "$src" >"$dest/$(basename "${src%.xz}")" ;;
        application/x-tar) tar -xvf "$src" -C "$dest" ;;
        application/x-gzip* | application/gzip*) tar -xzvf "$src" -C "$dest" ;;
        application/x-bzip2* | application/bzip2*) tar -xjvf "$src" -C "$dest" ;;
        application/x-xz*) tar -xJvf "$src" -C "$dest" ;;
        application/vnd.debian.binary-package) log::info "${src} is debian package format" ;;
        *)
                log::info "${src} unknown compress format"
                return 1
                ;;
        esac
}

util::get_board_index_from_eeprom() {
        local address=$1
        local offset=$2

        if [ "$(lsmod | grep -c i2c_dev)" = "0" ]; then
                # If the driver has not been loaded, load it
                modprobe i2c_dev
        fi

        local i2c_num
        i2c_num=$(/usr/sbin/i2cdetect -l | grep smbus | awk -F ' ' '{print $1}' | awk -F '-' '{print $2}')

        /usr/sbin/i2cget -f -y "$i2c_num" "$address" "$offset" 2>/dev/null || echo "I2C read failed"
}
