#!/bin/bash
#
# Rekor Scout / OpenALPR installer.
#
# Unified installer that auto-detects the OS package family and dispatches:
#   - Debian / Ubuntu (and Nvidia Jetson)   -> apt / .deb engine
#   - Rocky / RHEL / AlmaLinux / Fedora      -> dnf / .rpm engine
#
#   bash <(curl -s https://deb.openalpr.com/install)     # Debian/Ubuntu
#   bash <(curl -s https://rpm.openalpr.com/install)     # Rocky/RHEL
#
# Non-interactive usage (task names differ slightly per family):
#   ./install -i install_agent -y
#   ./install -i install_sdk
#   ./install -i install_nvidia
#

#==============================================================================
# Shared globals
#==============================================================================
ARCH=$(uname -m)
OS_NAME=""
EXTRA_PACKAGES=""
CONTAINER_INSTALL=0
ALL_YES=0
INSTALL_TYPE=""
PKG_FAMILY=""
cuda_version=""
cuda_driver_support_version=""

# --- deb-family globals ---
REPO_POSTFIX="/"
REPO_PREFIX=""
CUDAVER=0
DEFAULTCUDA_FOCAL=("11.4.0")
DEFAULTCUDA_JAMMY=("12.6.0" "12.9.0" "13.0.0")
DEFAULTCUDA_NOBLE=("12.9.0" "13.0.0")
DEFAULTCUDA_RACCOON=("13.3.0")

# --- rpm-family globals (repository configuration) ---
# Layout served by the repo (see rpm_package.py / .drone.yml in alprmodules):
#   <RPM_BASE_URL>/<RPM_REPO>/<REPO_CHANNEL>/<arch>/   -- all RPMs (incl. noarch)
RPM_BASE_URL="${RPM_BASE_URL:-https://rpm.openalpr.com}"
RPM_REPO="${RPM_REPO:-rocky10}"
# dnf channel directory (rocky10/<channel>/<arch>). GA is the default; upload.sh
# rewrites this line to produce the install-beta / install-latest variants, the
# same way it rewrites REPO_POSTFIX for the apt channels.
REPO_CHANNEL="ga"
REPO_FILE="/etc/yum.repos.d/openalpr.repo"
# Recognition model data (Recommends of libopenalpr2 on Debian). dnf does not
# pull these in automatically here, so install them explicitly with the agent/SDK.
MODEL_PACKAGES="libopenalpr-data libalprocr-data libalpredge-data libvehicleclassifier-data libvehiclesignature-data"
AGENT_PACKAGES="openalpr openalpr-daemon openalpr-link libalprlc-utils $MODEL_PACKAGES"
SDK_PACKAGES="openalpr libopenalpr-devel libalprstream-devel python3-openalpr python3-alprstream openalpr-alprvideo libalpropencvgpu-python3 $MODEL_PACKAGES"
GPU_PACKAGE="openalprgpu"
# The GPU packages depend on cuda-libraries-13 / libcudnn9-cuda-13, served by
# NVIDIA's official CUDA repo (not the OpenALPR repo).
CUDA_REPO_RELEASE="${CUDA_REPO_RELEASE:-rhel10}"

#==============================================================================
# Package-family detection
#==============================================================================
detect_pkg_family() {
    local id="" like=""
    if [ -r /etc/os-release ]; then
        id=$(. /etc/os-release 2>/dev/null; echo "$ID")
        like=$(. /etc/os-release 2>/dev/null; echo "$ID_LIKE")
    fi
    case " $id $like " in
        *rhel*|*fedora*|*centos*|*rocky*|*almalinux*) PKG_FAMILY="rpm"; return ;;
        *debian*|*ubuntu*)                            PKG_FAMILY="deb"; return ;;
    esac
    # Fallback: infer from the available package manager.
    if command -v dnf &>/dev/null || command -v yum &>/dev/null; then
        PKG_FAMILY="rpm"
    elif command -v apt-get &>/dev/null; then
        PKG_FAMILY="deb"
    else
        echo "Unable to determine package manager family (no apt-get/dnf/yum found)."
        exit 1
    fi
}

#==============================================================================
# Shared CUDA / GPU detection
#==============================================================================
getCudaVersion() {
    # Check if Nvidia GPU is present
    if command -v lspci &>/dev/null; then
        if ! lspci | grep -i nvidia &>/dev/null; then
            echo "NVIDIA GPU not found."
            return
        fi
    fi

    # See what the highest CUDA version the driver supports
    if command -v nvidia-smi &>/dev/null; then
        cuda_driver_support_version=$(nvidia-smi | grep CUDA | grep -oP 'CUDA Version: \K[^ ]+')
    fi

    cuda_version_file="/usr/local/cuda/version.json"
    nvcc_cmd="/usr/local/cuda/bin/nvcc"

    if [ ! -x "$nvcc_cmd" ]; then
        nvcc_cmd=$(which nvcc 2>/dev/null)
    fi

    if [ -n "$nvcc_cmd" ] && [ -x "$nvcc_cmd" ]; then
        if $nvcc_cmd --version &>/dev/null; then
            cuda_version=$($nvcc_cmd --version | sed -n 's/^.*release \([0-9]\+\.[0-9]\+\).*$/\1/p')
        fi
    elif [ -f "$cuda_version_file" ]; then
        cuda_version=$(grep -A 2 '"cuda"' $cuda_version_file | grep '"version"' | sed 's/[^0-9]*\([0-9.]*\).*/\1/')
    fi
}

compareCudaVersions() {
    local array_name="$1"
    local distro_name="$2"

    # default to unsupported CUDA version
    CUDAVER=0

    if [[ -n "${cuda_version}" ]]; then
        local shortver
        shortver=$(echo "${cuda_version}" | cut -d. -f1-2)

        local supported=0

        # Dereference array name
        local -n DEFAULTCUDA="$array_name"

        for version in "${DEFAULTCUDA[@]}"; do
            local defver
            defver=$(echo "${version}" | cut -d. -f1-2)
            if [[ "${shortver}" == "${defver}" ]]; then
                CUDAVER="${cuda_version}"
                supported=1
                break
            fi
        done

        if [[ $supported -eq 0 ]]; then
            local valid_versions
            valid_versions=$(printf " or %s" "${DEFAULTCUDA[@]}")
            valid_versions=${valid_versions:4} # Remove the leading ' or '
            echo "ERROR: Cuda version ${cuda_version} is not supported on ${distro_name}. Use ${valid_versions}"
            exit 1
        fi

        # See if driver supports this version of cuda
        if [[ -n "${cuda_driver_support_version}" ]]; then
            local driverver
            driverver=$(echo "${cuda_driver_support_version}" | cut -d. -f1-2)

            if (( $(echo "${driverver} < ${shortver}" | bc -l) )); then
                echo "ERROR: Cuda driver ${cuda_driver_support_version} is too old. Update driver to support ${cuda_version}"
                exit 1
            fi
        fi
    fi
}

dumpNvidiaGPUInfo() {
    if command -v lspci &>/dev/null; then
        if ! lspci | grep -i nvidia &>/dev/null; then
            echo "NVIDIA GPU not found."
            return 1
        fi
    fi

    if ! command -v nvidia-smi &>/dev/null; then
        echo "nvidia-smi not found — NVIDIA drivers may not be installed."
        return 1
    fi

    if ! nvidia-smi --query-gpu=count --format=csv,noheader &>/dev/null; then
        echo "nvidia-smi found but no GPU detected."
        return 1
    fi

    # compute_cap was added to nvidia-smi around driver 510; older versions reject it.
    if nvidia-smi --help-query-gpu 2>/dev/null | grep -qw compute_cap; then
        nvidia-smi --query-gpu=index,name,compute_cap --format=csv,noheader | while IFS=, read idx name cc; do
            idx=$(echo "$idx" | xargs)
            name=$(echo "$name" | xargs)
            cc=$(echo "$cc" | xargs)
            ver=$(echo "$cc" | tr -d '.')
            if [[ "$ver" =~ ^[0-9]+$ ]]; then
                [ "$ver" -lt 75 ] && status="BELOW 7.5 ⚠️" || status="7.5 or above ✅"
            else
                status="compute capability unknown"
            fi
            echo "GPU $idx ($name) — cc $cc — $status"
        done
    else
        nvidia-smi --query-gpu=index,name --format=csv,noheader | while IFS=, read idx name; do
            idx=$(echo "$idx" | xargs)
            name=$(echo "$name" | xargs)
            echo "GPU $idx ($name) — compute capability not reported (nvidia-smi too old for compute_cap query)"
        done
    fi
}

# Returns 0 if an NVIDIA GPU is present (so GPU packages should be installed).
hasNvidiaGpu() {
    if command -v nvidia-smi &>/dev/null && nvidia-smi -L &>/dev/null; then
        return 0
    fi
    if command -v lspci &>/dev/null && lspci | grep -i nvidia &>/dev/null; then
        return 0
    fi
    return 1
}

# True when systemd is the running init (so systemctl can manage services).
# Containers / WSL / chroots often lack this.
systemd_available() {
    [ -d /run/systemd/system ]
}

#==============================================================================
# Shared UI helpers
#==============================================================================
prompt_confirm() {
    if [ "$ALL_YES" -eq 1 ]; then
        return 0
    fi

    while true; do
        read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
        case $REPLY in
            [yY]) echo; return 0 ;;
            [nN]) echo; return 1 ;;
            *) printf " \033[31m %s \n\033[0m" "invalid input" ;;
        esac
    done
}

run_commands_with_confirm() {
    echo "Detected Operating System: ${OS_NAME}"
    echo "Rekor Scout Installer will execute the following commands to install the software"
    echo ""
    echo "--------------------------------------------------------------------"
    for cmd in "${COMMANDS[@]}"; do
        echo "    $cmd"
    done
    echo ""
    echo "--------------------------------------------------------------------"
    echo ""
    prompt_confirm

    if [ $? -ne 0 ]; then
        echo "Installation canceled."
        exit 1
    fi

    for cmd in "${COMMANDS[@]}"; do
        eval "$cmd"
        if [ $? -ne 0 ]; then
            echo "Installation failed."
            exit 1
        fi
    done
}

createAlprConfFile() {
    if [ ! -f "/etc/openalpr/openalpr.conf" ]; then
        $SUDO_COMMAND mkdir -p /etc/openalpr
        $SUDO_COMMAND touch /etc/openalpr/openalpr.conf
        echo "Creating empty conf file"
    fi
}

#==============================================================================
# Family dispatchers (route to the active family's implementation)
#==============================================================================
append_repo_setup() {
    if [ "$PKG_FAMILY" = "rpm" ]; then append_repo_setup_rpm; else append_repo_setup_deb; fi
}

dumpInformation() {
    if [ "$PKG_FAMILY" = "rpm" ]; then dumpInformation_rpm; else dumpInformation_deb; fi
}

do_task() {
    if [ "$PKG_FAMILY" = "rpm" ]; then do_task_rpm "$1"; else do_task_deb "$1"; fi
}

#//////////////////////////////////////////////////////////////////////////////
#
#  DEBIAN / UBUNTU (apt) ENGINE
#
#//////////////////////////////////////////////////////////////////////////////

detect_os_deb() {
    RELEASE_NAME=$(cat /etc/lsb-release 2>/dev/null | grep DISTRIB_CODENAME | sed 's/DISTRIB_CODENAME\s*=\s*//g')

    if [ -n "$REKOR_VERSION" ]; then
        REPO_POSTFIX="-${REKOR_VERSION}/"
        REPO_PREFIX="snapshot/"
    fi

    if [ -e "/etc/nv_tegra_release" ]; then

        # Check JetPack version and setup the correct repo
        if cat /etc/nv_tegra_release | head -n 1 | grep "R28.*REVISION:\s*1.0"; then
            OS_NAME="Nvidia Jetson JetPack 3.1"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson-xenial-commercial${REPO_POSTFIX} jetson-xenial main"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R28.*REVISION:\s*2."; then
            OS_NAME="Nvidia Jetson JetPack 3.2"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson32${REPO_POSTFIX} jetson32 main"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R31.*"; then
            OS_NAME="Nvidia Jetson JetPack 4.0"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson40${REPO_POSTFIX} jetson40 main"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R32.*REVISION:\s*[12].*"; then
            OS_NAME="Nvidia Jetson JetPack 4.2"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson40${REPO_POSTFIX} jetson40 main"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R32.*REVISION:\s*3.*"; then
            OS_NAME="Nvidia Jetson JetPack 4.3"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson43${REPO_POSTFIX} jetson43 main"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R32.*REVISION:\s*[45].*"; then
            OS_NAME="Nvidia Jetson JetPack 4.4"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson44${REPO_POSTFIX} jetson44 main"
            EXTRA_PACKAGES="cuda-nvrtc-10-2"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R32.*REVISION:\s*[67].*"; then
            OS_NAME="Nvidia Jetson JetPack 4.6"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson46${REPO_POSTFIX} jetson46 main"
            EXTRA_PACKAGES="libopencv"

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R35.*REVISION:\s*[23456].*"; then
            OS_NAME="Nvidia Jetson JetPack 5.1"
            if [[ $RELEASE_NAME == "focal" ]]; then
                DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson51${REPO_POSTFIX} jetson51 main"
            else
                echo "Unsupported OS"
                exit 1
            fi

        elif cat /etc/nv_tegra_release | head -n 1 | grep "R36.*REVISION:\s*[345].*"; then
            OS_NAME="Nvidia Jetson JetPack 6.1"
            if [[ $RELEASE_NAME == "jammy" ]]; then
                EXTRA_PACKAGES="libcudnn9-cuda-12"
                DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson60${REPO_POSTFIX} jetson60 main"
            else
                echo "Unsupported OS"
                exit 1
            fi

        else
            echo "Unsupported JetPack"
            cat /etc/nv_tegra_release
            exit
        fi
    elif [ -e "/etc/nvpmodel.conf" ]; then
        # In some cases, on Jetson, the nv_tegra_release file is missing.  Handle this by checking the packages installed

        L4T_VERSION=$(dpkg -l | grep nvidia-l4t-core | awk '{print $3;}' | sed 's/-.*//g')
        if [[ "$L4T_VERSION" = "32.2.1" || "$L4T_VERSION" = "32.2.3" ]]; then
            OS_NAME="Nvidia Jetson JetPack 4.2"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson40${REPO_POSTFIX} jetson40 main"

        elif [ "$L4T_VERSION" = "32.3.1" ]; then
            OS_NAME="Nvidia Jetson JetPack 4.3"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson43${REPO_POSTFIX} jetson43 main"

        elif [ "$L4T_VERSION" = "35.3.1" ]; then
            OS_NAME="Nvidia Jetson JetPack 5.1"
            if [[ $RELEASE_NAME == "focal" ]]; then
                DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jetson51${REPO_POSTFIX} jetson51 main"
            else
                echo "Unsupported OS"
                exit 1
            fi
        else
            echo "Unable to determine Jetpack version.  /etc/nv_tegra_release file is missing"
            exit 1
        fi

    elif [ "$RELEASE_NAME" = "trusty" ]; then
        OS_NAME="Ubuntu Trusty"
        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}commercial${REPO_POSTFIX} trusty main"
    elif [ "$RELEASE_NAME" = "xenial" ]; then
        OS_NAME="Ubuntu Xenial"
        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}xenial-commercial${REPO_POSTFIX} xenial main"
    elif [ "$RELEASE_NAME" = "bionic" ]; then
        OS_NAME="Ubuntu Bionic"
        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}bionic${REPO_POSTFIX} bionic main"
    elif [ "$RELEASE_NAME" = "focal" ]; then

        compareCudaVersions DEFAULTCUDA_FOCAL "focal"

        if [ $CUDAVER == "11.8" ]; then
            OS_NAME="Ubuntu Focal"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}focalcuda118${REPO_POSTFIX} focalcuda118 main"
        elif [ $CUDAVER == "11.4" ]; then
            OS_NAME="Ubuntu Focal"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}focalcuda11${REPO_POSTFIX} focalcuda11 main"
        else
            OS_NAME="Ubuntu Focal"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}focal${REPO_POSTFIX} focal main"
        fi

    elif [ "$RELEASE_NAME" = "jammy" ]; then

        compareCudaVersions DEFAULTCUDA_JAMMY "jammy"
        OS_NAME="Ubuntu Jammy"

        if [[ $CUDAVER == 12.6 || $CUDAVER == 12.6.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-12"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda126${REPO_POSTFIX} jammycuda126 main"
        elif [[ $CUDAVER == 12.9 || $CUDAVER == 12.9.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-12"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda129${REPO_POSTFIX} jammycuda129 main"
        elif [[ $CUDAVER == 13.0 || $CUDAVER == 13.0.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-13"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda130${REPO_POSTFIX} jammycuda130 main"
        else
            # CPU-only (no supported CUDA detected)
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammy${REPO_POSTFIX} jammy main"
        fi
    elif [ "$RELEASE_NAME" = "noble" ]; then

        compareCudaVersions DEFAULTCUDA_NOBLE "noble"
        OS_NAME="Ubuntu Noble"

        if [[ $CUDAVER == 12.9 || $CUDAVER == 12.9.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-12"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noblecuda129${REPO_POSTFIX} noblecuda129 main"
        elif [[ $CUDAVER == 13.0 || $CUDAVER == 13.0.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-13"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noblecuda130${REPO_POSTFIX} noblecuda130 main"
        else
            # CPU-only (no supported CUDA detected)
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noble${REPO_POSTFIX} noble main"
        fi

    # Ubuntu 26.04 "Raccoon". The DISTRIB_CODENAME may be raccoon or resolute;
    # match both. Same repos serve x86_64 and arm64 (apt selects the arch).
    elif [ "$RELEASE_NAME" = "raccoon" ] || [ "$RELEASE_NAME" = "resolute" ]; then

        compareCudaVersions DEFAULTCUDA_RACCOON "raccoon"
        OS_NAME="Ubuntu Raccoon (26.04)"

        if [[ $CUDAVER == 13.3 || $CUDAVER == 13.3.* ]]; then
            EXTRA_PACKAGES="libcudnn9-cuda-13"
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}raccooncuda133${REPO_POSTFIX} raccooncuda133 main"
        else
            # CPU-only (no supported CUDA detected)
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}raccoon${REPO_POSTFIX} raccoon main"
        fi

    else
        echo "Unable to determine Ubuntu release version.  Rekor Scout supports installation on Ubuntu 18.04, 20.04, 22.04, 24.04, and 26.04"
        exit 1
    fi
}

create_docker_configs() {

    # create supervisord.conf file
    cat >/etc/supervisor/conf.d/supervisord.conf <<EOF
[supervisord]
nodaemon=false

[program:beanstalkd]
command=/usr/bin/beanstalkd

[program:openalpr-daemon]
command=/usr/bin/alprd -f
stdout_logfile=/var/log/alpr.log
stdout_logfile_maxbytes=10000000
redirect_stderr=true
autorestart=true
startsecs=2
startretries=1000000000

[program:openalpr-link]
command=/usr/bin/alprlink -f
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
autorestart=true
startsecs=2
startretries=1000000000

EOF

    # override systemctl in the container. This redirects to supervisorctl
    cat >/bin/systemctl <<EOT
#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "You must enter exactly 2 command line arguments"
    exit 1
fi

if [ "$2" == "openalpr-link" ]; then
    # Say nothing
    exit 0
fi

if [ "$2" != "openalpr-daemon" ]; then
    echo "This override is only valid for openalpr-daemon service"
    exit 1
fi


# They are trying to restart openalpr-daemon with the service command.  Redirect this to supervisorctl
supervisorctl $1 alprd

EOT

}

#-------------------------------
# Service management (deb)
#-------------------------------
services_stop() {
    if [[ ${#SERVICES[@]} -gt 0 ]]; then
        for unit in "${SERVICES[@]}"; do
            $SUDO_COMMAND systemctl stop -- "$unit"
        done
    fi
}

# Wait until APT/DPKG operations fully complete (avoid races with triggers)
wait_for_apt() {
    while \
        sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \
        sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1 || \
        pgrep -x apt >/dev/null || \
        pgrep -x apt-get >/dev/null || \
        pgrep -x dpkg >/dev/null
    do
        sleep 1
    done
}

services_restart() {
    if [[ ${#SERVICES[@]} -eq 0 ]]; then
        return 0
    fi

    wait_for_apt

    $SUDO_COMMAND systemctl daemon-reload || true

    $SUDO_COMMAND systemctl is-active --quiet network-online.target || \
        $SUDO_COMMAND systemctl start network-online.target || true

    local unit attempt
    for unit in "${SERVICES[@]}"; do
        $SUDO_COMMAND systemctl reset-failed -- "$unit" || true

        $SUDO_COMMAND systemctl stop -- "$unit" || true

        for attempt in 1 2 3; do
            if $SUDO_COMMAND systemctl start -- "$unit"; then
                break
            fi
            sleep 2
            $SUDO_COMMAND systemctl daemon-reload || true
        done

        if $SUDO_COMMAND systemctl is-active --quiet "$unit"; then
            echo "$unit is active"
        else
            echo "$unit FAILED to start; recent logs:" >&2
            $SUDO_COMMAND journalctl -u "$unit" -n 100 --no-pager || true
        fi
    done
}

append_repo_setup_deb() {
    # Modern keyring-based repo setup (avoid deprecated apt-key)
    COMMANDS+=("$SUDO_COMMAND install -d -m 0755 /etc/apt/keyrings")
    COMMANDS+=("curl -fsSL https://deb.openalpr.com/openalpr.gpg.key | $SUDO_COMMAND gpg --dearmor --batch --yes -o /etc/apt/keyrings/openalpr.gpg")
    # Add signed-by to the deb line derived from DEB_REPO_PATH
    COMMANDS+=("echo '$DEB_REPO_PATH' | sed 's/^deb /deb [signed-by=\\/etc\\/apt\\/keyrings\\/openalpr.gpg] /' | $SUDO_COMMAND tee /etc/apt/sources.list.d/openalpr.list")
}

dumpInformation_deb() {
    if [[ "$REPO_POSTFIX" == *-latest* ]]; then
        echo " "
        echo "**************************** WARNING ***************************************"
        echo "This is a developer installation. It pulls the latest code from active development"
        echo "and may be unstable or untested. Please proceed only if instructed to do so"
        echo "by Rekor Support or Engineering."
        echo " "
    fi

    echo "Arch: $ARCH"
    echo "CUDA_VERSION: $cuda_version"
    echo "CUDA_DRIVER_VERSION: $cuda_driver_support_version"
    dumpNvidiaGPUInfo
    if [[ $CONTAINER_INSTALL == "1" ]]; then
        echo "Docker install"
    fi
}

# Show a dialog menu of major.minor version prefixes available across the
# given packages and echo the chosen one to stdout.
select_model_version_prefix() {
    local pkgs="$1"
    local p family families latest menu_args installed_versions installed_v

    installed_versions=$(for p in $pkgs; do
        installed_v=$(dpkg-query -W -f='${Version}' "$p" 2>/dev/null)
        [ -n "$installed_v" ] && echo "$installed_v" | cut -d. -f1-3
    done | sort -u)

    families=$({
        for p in $pkgs; do
            apt-cache madison "$p" 2>/dev/null | awk '{print $3}' | cut -d. -f1-2
        done
    } | grep -v '^$' | sort -uV -r)

    if [ -z "$families" ]; then
        echo "No versions found for model packages" >&2
        return 1
    fi

    menu_args=""
    while IFS= read -r family; do
        latest=$(for p in $pkgs; do
            apt-cache madison "$p" 2>/dev/null | awk '{print $3}'
        done | grep -E "^${family}\." | cut -d. -f1-3 | sort -uV -r | head -n 1)
        if [ -n "$latest" ] && ! echo "$installed_versions" | grep -qxF "$latest"; then
            menu_args="$menu_args '$latest' ''"
        fi
    done <<< "$families"

    if [ -z "$menu_args" ]; then
        echo "No downgrade versions available" >&2
        return 1
    fi

    eval "dialog --stdout --backtitle 'Rekor Alpr Installer' --title 'Rekor Alpr Installer' --menu 'Select version to install:' 20 60 10 $menu_args"
}

# Install the given packages at the newest revision matching the
# specified major.minor.patch prefix.
downgrade_models_to_prefix() {
    local pkgs="$1"
    local prefix="$2"
    local downgrade_list="" p v
    for p in $pkgs; do
        v=$(apt-cache madison "$p" | awk '{print $3}' | grep -E "^${prefix}(\.|-|$)" | head -n 1)
        [ -n "$v" ] && downgrade_list="$downgrade_list $p=$v"
    done
    if [ -n "$downgrade_list" ]; then
        echo "Installing:$downgrade_list"
        $SUDO_COMMAND apt-get install -y --allow-downgrades $downgrade_list
    else
        echo "No matching versions found for prefix $prefix"
        return 1
    fi
}

do_task_deb() {
    task=$1

    echo ""
    echo "-------------------------------"
    echo "Executing task: $task"
    echo "-------------------------------"

    COMMANDS=()

    if [ "$task" == "install_agent" ]; then

        echo "Installing Rekor Scout Agent"
        dumpInformation
        createAlprConfFile

        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr openalpr-daemon openalpr-link ${EXTRA_PACKAGES}")
        COMMANDS+=("$SUDO_COMMAND apt-get dist-upgrade -y -o Dir::Etc::sourcelist=\"sources.list.d/openalpr.list\"     -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"-upgrade")
        if [[ $OS_NAME == Nvidia* || $cuda_version != "" ]]; then
            COMMANDS+=("$SUDO_COMMAND apt-get -y install openalprgpu")
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^hardware_acceleration/!p' -e '\$ahardware_acceleration = 1' /etc/openalpr/alprd.conf")
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^gpu_batch_size/!p' -e '\$agpu_batch_size = 5' /etc/openalpr/alprd.conf")
        fi

        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm

        if [[ $CONTAINER_INSTALL == "1" ]]; then
            create_docker_configs
            update-rc.d supervisor defaults
            service supervisor start
        fi

        DESKTOP_DIR=$(eval echo "~$USER/Desktop")
        DESKTOP_SCRIPT="rekor-scout-agent.desktop"
        if [ -d "$DESKTOP_DIR" ]; then
            curl "https://deb.openalpr.com/installer_files/${DESKTOP_SCRIPT}" -o "$DESKTOP_DIR/${DESKTOP_SCRIPT}" \
                && chmod +x "$DESKTOP_DIR/${DESKTOP_SCRIPT}"
        fi

    fi

    if [ "$task" == "install_sdk" ]; then
        echo "Installing Rekor Scout Agent SDK"
        dumpInformation
        createAlprConfFile

        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr libopenalpr-dev libalprstream-dev python3-openalpr python3-alprstream openalpr-video ${EXTRA_PACKAGES}")
        COMMANDS+=("$SUDO_COMMAND apt-get dist-upgrade -y -o Dir::Etc::sourcelist=\"sources.list.d/openalpr.list\"     -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"-upgrade")
        if [[ $OS_NAME == Nvidia* || $cuda_version != "" ]]; then
            COMMANDS+=("$SUDO_COMMAND apt-get -y install openalprgpu")
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^hardware_acceleration/!p' -e '\$ahardware_acceleration = 1' /etc/openalpr/openalpr.conf")
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^gpu_batch_size/!p' -e '\$agpu_batch_size = 5' /etc/openalpr/openalpr.conf")
        fi
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm

    fi

    if [ "$task" == "system_info" ]; then
        dumpInformation
    fi

    if [ "$task" == "install_webserver" ]; then

        dumpInformation
        if [[ $ARCH != "x86_64" ]]; then
            echo "Webserver is only supported on x86_64 systems running Ubuntu Jammy, Focal or Bionic"
            exit 1
        fi

        tempOS="${OS_NAME,,}"
        if [[ $tempOS == "ubuntu focal" || $tempOS == "ubuntu bionic" || $tempOS == "ubuntu jammy" ]]; then

            WEB_SERVER_INSTALLED=0
            $SUDO_COMMAND dpkg --get-selections | grep -e "^openalpr-web\s*install" > /dev/null 2>&1
            if [ "$?" == "0" ]; then
                WEB_SERVER_INSTALLED=1
            fi

            if [ "$WEB_SERVER_INSTALLED" != "1" ]; then
                # Check if ports are open first
                $SUDO_COMMAND lsof -i -P -n | grep LISTEN | grep -e ":80\s" > /dev/null 2>&1
                HTTP_IN_USE=$?
                $SUDO_COMMAND lsof -i -P -n | grep LISTEN | grep -e ":443\s" > /dev/null 2>&1
                HTTPS_IN_USE=$?
                if [ "$HTTP_IN_USE" == "0" ] || [ "$HTTPS_IN_USE" == "0" ]; then
                    echo "--------------------------------------------------------------------------"
                    echo "                             Error"
                    echo "--------------------------------------------------------------------------"
                    echo "Detected port 80 or port 443 is already in use."
                    echo "Please uninstall software using these ports in order to install Rekor Scout Server"
                    echo "Install cannot continue..."
                    echo ""
                    exit 1
                fi
            fi

            echo "Installing Rekor Scout Web Server"
            # openalpr-web is only published to the plain distro repos, so
            # override any CUDA repo chosen during GPU detection.
            DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}${RELEASE_NAME}${REPO_POSTFIX} ${RELEASE_NAME} main"
            append_repo_setup
            if [[ $tempOS == "ubuntu jammy" ]]; then
                EXTRA_ALPR_WEB_PACKAGES="python3.8 python3.8-venv python3.8-dev python3.8-distutils \
                    build-essential pkg-config \
                    virtualenv \
                    libssl-dev libffi-dev zlib1g-dev \
                    default-libmysqlclient-dev \
                    libcurl4-openssl-dev \
                    libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 \
                    libjpeg-dev libopenjp2-7-dev libtiff5 libfreetype6-dev"

                COMMANDS+=("$SUDO_COMMAND apt-get install software-properties-common")
                COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND add-apt-repository -y ppa:deadsnakes/ppa; $SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr-web ${EXTRA_ALPR_WEB_PACKAGES}")
            else
                COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr-web")
            fi

            COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")

            # Only do the create-database script on fresh install
            if [ "$WEB_SERVER_INSTALLED" == "0" ]; then
                COMMANDS+=("$SUDO_COMMAND openalpr-web-createdb")
            fi

            COMMANDS+=("$SUDO_COMMAND /etc/init.d/openalpr-web restart && $SUDO_COMMAND /etc/init.d/openalpr-router restart")
            run_commands_with_confirm

            DESKTOP_DIR=$(eval echo "~$USER/Desktop")
            DESKTOP_SCRIPT="rekor-scout-web.desktop"
            if [ -d "$DESKTOP_DIR" ]; then
                curl "https://deb.openalpr.com/installer_files/${DESKTOP_SCRIPT}" -o "$DESKTOP_DIR/${DESKTOP_SCRIPT}" \
                    && chmod +x "$DESKTOP_DIR/${DESKTOP_SCRIPT}"
            fi
        else
            echo "Webserver is only supported on Ubuntu Jammy, Focal and Bionic"
        fi
    fi

    if [ "$task" == "upgrade_software" ]; then
        tempOS="${OS_NAME,,}"

        UPGRADE_COMMAND="$SUDO_COMMAND apt-get dist-upgrade -y -o Dir::Etc::sourcelist=\"sources.list.d/openalpr.list\"     -o Dir::Etc::sourceparts=\"-\" -o APT::Get::List-Cleanup=\"0\""

        NVIDIA_ACCEL_INSTALLED=0
        $SUDO_COMMAND dpkg --get-selections | grep -e "^openalprgpu\s*install" > /dev/null 2>&1
        if [ "$?" == "0" ]; then
            NVIDIA_ACCEL_INSTALLED=1
        fi

        DAEMON_INSTALLED=0
        $SUDO_COMMAND dpkg --get-selections | grep -e "^openalpr-daemon\s*install" > /dev/null 2>&1
        if [ "$?" == "0" ]; then
            DAEMON_INSTALLED=1
        fi

        has_web=$(dpkg -l | grep ^ii | grep openalpr-web)
        has_nvidia=$(dpkg -l | grep ^ii | grep openalprgpu)
        has_sdk=$(dpkg -l | grep ^ii | grep python3-openalpr)
        has_agent=$(dpkg -l | grep ^ii | grep openalpr-daemon)
        append_repo_setup

        # openalpr-web is only published to the plain distro repos; on a GPU
        # machine the detected repo is a CUDA one, so add the plain repo too.
        if [[ $has_web ]]; then
            PLAIN_DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}${RELEASE_NAME}${REPO_POSTFIX} ${RELEASE_NAME} main"
            if [[ "$PLAIN_DEB_REPO_PATH" != "$DEB_REPO_PATH" ]]; then
                COMMANDS+=("echo '$PLAIN_DEB_REPO_PATH' | sed 's/^deb /deb [signed-by=\\/etc\\/apt\\/keyrings\\/openalpr.gpg] /' | $SUDO_COMMAND tee -a /etc/apt/sources.list.d/openalpr.list")
            fi
        fi

        if [[ $tempOS == "ubuntu jammy" && $has_web ]]; then
            COMMANDS+=("$SUDO_COMMAND /etc/init.d/openalpr-websockets stop && $SUDO_COMMAND /etc/init.d/openalpr-web stop && $SUDO_COMMAND /etc/init.d/openalpr-router stop && $SUDO_COMMAND /etc/init.d/openalpr-systeminterface stop")

                EXTRA_ALPR_WEB_PACKAGES="python3.8 python3.8-venv python3.8-dev python3.8-distutils \
                    build-essential pkg-config \
                    virtualenv \
                    libssl-dev libffi-dev zlib1g-dev \
                    default-libmysqlclient-dev \
                    libcurl4-openssl-dev \
                    libcairo2 libpango-1.0-0 libpangocairo-1.0-0 libgdk-pixbuf2.0-0 \
                    libjpeg-dev libopenjp2-7-dev libtiff5 libfreetype6-dev"

                COMMANDS+=("$SUDO_COMMAND apt-get install software-properties-common")
                COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND add-apt-repository -y ppa:deadsnakes/ppa; $SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr-web ${EXTRA_ALPR_WEB_PACKAGES}")
        fi

        if [[ $has_agent ]]; then
            COMMANDS+=("$SUDO_COMMAND systemctl stop openalpr-link || true")
            COMMANDS+=("$SUDO_COMMAND systemctl stop openalpr-daemon || true")
            COMMANDS+=("$SUDO_COMMAND apt-get update")
            COMMANDS+=("$SUDO_COMMAND apt-get install -o apt::install-recommends=true -y openalpr openalpr-daemon openalpr-link openalpr-daemonconfig libopenalpr2 libalprstream3 libalprgpusupport2 libalprlc2 libalprlc-utils libalprlog2 libalprsupport2 librollingdb2")
            COMMANDS+=("$SUDO_COMMAND apt-get dist-upgrade -y -o Dir::Etc::sourcelist=\"sources.list.d/openalpr.list\"     -o Dir::Etc::sourceparts=\"-\" -o APT::Get::List-Cleanup=\"0\"")
            COMMANDS+=("$SUDO_COMMAND dpkg --configure -a || true")
            COMMANDS+=("$SUDO_COMMAND systemctl daemon-reload || true")
            # Restart link service as well (best-effort)
            COMMANDS+=("$SUDO_COMMAND service openalpr-link restart | true")
        fi

        if [[ $has_sdk ]]; then
            INSTALL_COMMAND+="$SUDO_COMMAND apt-get install -y libopenalpr-dev libalprstream-dev python3-openalpr python3-alprstream openalpr-video;"
        fi

        if [ "$NVIDIA_ACCEL_INSTALLED" == "1" ]; then
            INSTALL_COMMAND+="$SUDO_COMMAND apt-get install -y openalprgpu;"
        fi

        COMMANDS+=("$SUDO_COMMAND apt-get update; ${INSTALL_COMMAND} ${UPGRADE_COMMAND}")

        if [ "$DAEMON_INSTALLED" == "1" ]; then
            # Force restart the daemon if it's installed
            COMMANDS+=("$SUDO_COMMAND service openalpr-daemon restart | true")
        fi
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")

        if [[ $has_web ]]; then
            COMMANDS+=("$SUDO_COMMAND /etc/init.d/openalpr-systeminterface restart && $SUDO_COMMAND /etc/init.d/openalpr-router restart && $SUDO_COMMAND /etc/init.d/openalpr-websockets restart && $SUDO_COMMAND /etc/init.d/openalpr-web restart")
        fi

        run_commands_with_confirm

    fi

    if [ "$task" == "install_nvidia" ]; then
        dumpInformation
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get -y install openalpr openalprgpu")
        if [ -f "/etc/openalpr/alprd.conf" ]; then
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^hardware_acceleration/!p' -e '\$ahardware_acceleration = 1' /etc/openalpr/alprd.conf")
        fi
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm
    fi

    if [ "$task" == "update_models" ]; then
        echo "Updating Rekor Scout Model packages"
        dumpInformation
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get install -y libalpredge-data libalprocr-data libvehicleclassifier-data libvehiclesignature-data libopenalpr-data")
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm
    fi

    if [ "$task" == "downgrade_models" ]; then
        echo "Downgrading Rekor Scout Model packages"
        dumpInformation
        MODEL_PKGS="libalpredge-data libalprocr-data libvehicleclassifier-data libvehiclesignature-data libopenalpr-data"

        # Set up the repo and refresh package lists first so we can query
        # available versions before showing the selection dialog.
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update")
        for cmd in "${COMMANDS[@]}"; do
            eval $cmd
            if [ $? -ne 0 ]; then
                echo "Setup failed: $cmd"
                $SUDO_COMMAND rm -f /etc/apt/sources.list.d/openalpr.list
                exit 1
            fi
        done
        COMMANDS=()

        SELECTED_PREFIX=$(select_model_version_prefix "$MODEL_PKGS")
        clear
        if [ -z "$SELECTED_PREFIX" ]; then
            echo "No version selected. Aborting."
            $SUDO_COMMAND rm -f /etc/apt/sources.list.d/openalpr.list
            return
        fi
        echo "Selected version prefix: $SELECTED_PREFIX"

        COMMANDS+=("downgrade_models_to_prefix \"$MODEL_PKGS\" \"$SELECTED_PREFIX\"")
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm
    fi

    if [ "$task" == "install_test" ]; then
        dumpInformation
        # check if alpr sdk is installed
        if python3 -c "import alprstream" $ > /dev/null; then
            # install packages
            $SUDO_COMMAND apt install pip -y
            $SUDO_COMMAND pip install opencv-python

            # wget the tarball
            $SUDO_COMMAND rm -f rekor-test.tar
            wget deb.openalpr.com/rekor-test.tar

            $SUDO_COMMAND mkdir -p /opt/rekor/test
            # untar to /opt/rekor/test
            $SUDO_COMMAND tar xvf rekor-test.tar -C /opt/rekor/test

            echo ""
            echo "To Execute the test, make sure that the sdk is installed  "
            echo "and you have a valid SDK license."
            echo "To run it with the GPU, use the -g option"
            echo "Then cd /opt/rekor/test and execute ./smoke_test.sh [-g]"
        else
            echo ""
            echo "This test requires a SDK license"
            echo "And you will need to install the Rekor Scout Developer SDK first"
        fi
    fi

    if [ "$task" == "register_agent" ]; then

        WEB_SERVER_INSTALLED=0
        $SUDO_COMMAND dpkg -s openalpr-web > /dev/null 2>&1
        if [ "$?" == "0" ]; then
            WEB_SERVER_INSTALLED=1
        fi

        $SUDO_COMMAND dpkg -s openalpr-link > /dev/null 2>&1
        if [ "$?" == "0" ]; then

            # Check if GUI environment is configured
            if [[ ! -z "$GDMSESSION" ]]; then
                echo ""
                echo "Agent Configuration"
                prompt_confirm "Do you wish to launch the ALPR Configuration Utility? "
                ANSWER=$?

                if [[ $ANSWER == "0" ]]; then
                    $SUDO_COMMAND alprdconfig
                fi
            else
                # No GUI

                # Check for a valid license by seeing if the license files have any content
                HAS_LICENSE="0"
                if [[ -s /etc/openalpr/license.conf ]]; then
                    echo "Local license file exists"
                    # The file exists and is not empty
                    HAS_LICENSE="1"
                fi
                if [[ -s /etc/openalpr/onlinelicense.conf ]]; then
                    echo "Local license file exists"
                    # The file exists and is not empty
                    HAS_LICENSE="1"
                fi

                if [[ "$HAS_LICENSE" == "0" ]]; then
                    echo ""
                    echo "Agent Licensing"
                    prompt_confirm "Do you wish to activate your license with your account on https://cloud.openalpr.com/ ? "
                    ANSWER=$?

                    if [[ $ANSWER == "0" ]]; then
                        $SUDO_COMMAND openalpr-licenseregister
                    fi
                fi

                WEBSERVER_HOST="https://cloud.openalpr.com"
                if [ "$WEB_SERVER_INSTALLED" == "1" ]; then
                    WEBSERVER_HOST=https://localhost
                fi

                # Check if the alprd settings have already been set
                cat /etc/openalpr/alprd.conf | grep -E "company_id\s*=\s*[a-z0-9A-Z]+" > /dev/null 2>&1
                ALREADY_CONFIGURED=$?
                if [[ $ALREADY_CONFIGURED == "1" ]]; then
                    # This has NOT been already configured.  No company_id is setup in the alprd.conf

                    echo ""
                    echo "Agent Registration"
                    prompt_confirm "Do you wish to register the agent with $WEBSERVER_HOST? "
                    REGISTER_AGENT=$?
                    echo ""

                    if [[ $REGISTER_AGENT == "0" ]]; then
                        # loop until exit code is 0
                        until $SUDO_COMMAND alprlink-register -w "$WEBSERVER_HOST"; do
                            echo "Please try again..."
                        done
                    fi
                fi

            fi
        else
            # AlprLink is not installed

            $SUDO_COMMAND dpkg -s libopenalpr2 > /dev/null 2>&1
            if [ "$?" == "0" ]; then
                # Check for a valid license by seeing if the license files have any content
                HAS_LICENSE="0"
                if [[ -s /etc/openalpr/license.conf ]]; then
                    # The file exists and is not empty
                    HAS_LICENSE="1"
                fi

                if [[ "$HAS_LICENSE" == "0" ]]; then
                    echo ""
                    echo "Agent Licensing"
                    echo "The Rekor Scout SDK requires a valid license.  Go to https://license.openalpr.com/evalrequest/ to request a free 2-week evaluation key."
                    echo ""
                fi
            fi
        fi
    fi

    if [ "$task" == "download_packages" ]; then
        echo "Downloading Rekor Scout packages (without installing)"
        dumpInformation
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND apt-get update; $SUDO_COMMAND apt-get install --download-only -o apt::install-recommends=true -y openalpr openalpr-daemon openalpr-link libopenalpr-dev libalprstream-dev python3-openalpr python3-alprstream openalpr-video ${EXTRA_PACKAGES}")
        if [[ $OS_NAME == Nvidia* || $cuda_version != "" ]]; then
            COMMANDS+=("$SUDO_COMMAND apt-get install --download-only -y openalprgpu")
        fi
        COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        run_commands_with_confirm
        echo "Packages downloaded to /var/cache/apt/archives/"
    fi

    if [ "$task" == "uninstall_agent" ]; then
        echo "Removing Rekor Scout Agent"
        COMMANDS+=("$SUDO_COMMAND dpkg -l | grep alpr | grep ^i | awk '{print \$2;}' | grep -v web | grep -v libalprlc-utils | xargs $SUDO_COMMAND apt-get remove -y")
        if [ -e "/etc/apt/sources.list.d/openalpr.list" ]; then
            COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        fi
        run_commands_with_confirm
    fi

    if [ "$task" == "uninstall_webserver" ]; then
        echo "Removing Rekor Scout Web Server"
        COMMANDS+=("$SUDO_COMMAND openalpr-web-resetdb || true")
        COMMANDS+=("$SUDO_COMMAND apt-get purge -y openalpr-web")
        COMMANDS+=("$SUDO_COMMAND apt-get autoremove -y")
        if [ -e "/etc/apt/sources.list.d/openalpr.list" ]; then
            COMMANDS+=("$SUDO_COMMAND rm /etc/apt/sources.list.d/openalpr.list")
        fi
        run_commands_with_confirm
    fi
}

prereqs_deb() {
    PREREQS=""

    $SUDO_COMMAND dpkg -s dialog > /dev/null 2>&1
    [ "$?" == "1" ] && PREREQS=$PREREQS" dialog"

    $SUDO_COMMAND dpkg -s ca-certificates > /dev/null 2>&1
    [ "$?" == "1" ] && PREREQS=$PREREQS" ca-certificates"

    $SUDO_COMMAND dpkg -s apt-transport-https > /dev/null 2>&1
    [ "$?" == "1" ] && PREREQS=$PREREQS" apt-transport-https"

    $SUDO_COMMAND dpkg -s gnupg > /dev/null 2>&1
    [ "$?" == "1" ] && PREREQS=$PREREQS" gnupg"

    $SUDO_COMMAND dpkg -s lsof > /dev/null 2>&1
    [ "$?" == "1" ] && PREREQS=$PREREQS" lsof"

    if [ -z "$PREREQS" ]; then
        echo "Prerequisites satisfied"
    else
        echo "$PREREQS"
        $SUDO_COMMAND add-apt-repository -y universe > /dev/null 2> /dev/null
        $SUDO_COMMAND apt-get update
        $SUDO_COMMAND apt-get install -y $PREREQS < /dev/null
    fi
}

set_options_deb() {
    OPTIONS=(\
    install_webserver   "Install Rekor Scout $INFO_QUALIFIER Web Server" \
    install_agent       "Install Rekor Scout $INFO_QUALIFIER Agent" \
    install_sdk         "Install Rekor Scout $INFO_QUALIFIER Developer SDK" \
    install_nvidia      "Install Rekor Scout Nvidia Acceleration" \
    install_test        "Install Rekor Scout Test Software" \
    register_agent      "Register Agent" \
    update_models       "Update Rekor Scout Model packages" \
    downgrade_models    "Downgrade Rekor Scout Model packages to previous version" \
    upgrade_software    "Upgrade to the latest Rekor software" \
    download_packages   "Download Rekor Scout packages (without installing)" \
    uninstall_agent     "Uninstall Rekor Scout Agent" \
    uninstall_webserver "Uninstall Rekor Scout Web Server" \
    system_info         "Dump System Information" )
}

#//////////////////////////////////////////////////////////////////////////////
#
#  ROCKY / RHEL (dnf) ENGINE
#
#//////////////////////////////////////////////////////////////////////////////

detect_os_rpm() {
    if [ -r /etc/os-release ]; then
        OS_NAME=$(. /etc/os-release 2>/dev/null; echo "$PRETTY_NAME")
    fi
    if ! echo "$OS_NAME" | grep -qiE "rocky|rhel|red hat|almalinux|centos|fedora"; then
        echo "WARNING: This installer targets Rocky Linux 10 / RHEL-family systems."
        echo "Detected OS: ${OS_NAME:-unknown}"
    fi

    # Channel within the repo (mirrors REKOR_VERSION handling on the apt side).
    if [ -n "$REKOR_VERSION" ]; then
        REPO_CHANNEL="$REKOR_VERSION"
    fi

    # Prefer dnf, fall back to yum
    if command -v dnf &>/dev/null; then
        PKG_MGR="dnf"
    else
        PKG_MGR="yum"
    fi
}

# Write the OpenALPR yum repo definition. Unlike the apt side (which removes its
# sources file after installing), we leave the repo in place so `dnf update`
# keeps packages current — standard practice in the RPM world.
append_repo_setup_rpm() {
    COMMANDS+=("$SUDO_COMMAND tee $REPO_FILE > /dev/null <<'OPENALPR_REPO_EOF'
[openalpr]
name=OpenALPR for Rocky Linux ($RPM_REPO)
baseurl=$RPM_BASE_URL/$RPM_REPO/$REPO_CHANNEL/\$basearch/
enabled=1
gpgcheck=0
OPENALPR_REPO_EOF")
    COMMANDS+=("$SUDO_COMMAND $PKG_MGR makecache")
}

dumpInformation_rpm() {
    echo "OS: $OS_NAME"
    echo "Arch: $ARCH"
    echo "Package manager: $PKG_MGR"
    echo "Repo: $RPM_BASE_URL/$RPM_REPO/$REPO_CHANNEL/"
    echo "CUDA_VERSION: $cuda_version"
    echo "CUDA_DRIVER_VERSION: $cuda_driver_support_version"
    dumpNvidiaGPUInfo
    if systemd_available; then
        echo "systemd: available"
    else
        echo "systemd: NOT running (container/WSL) — service management skipped"
    fi
    if [[ $CONTAINER_INSTALL == "1" ]]; then
        echo "Docker install"
    fi
}

# Add NVIDIA's CUDA repo (provides cuda-libraries-13 / libcudnn9-cuda-13 that
# the openalprgpu packages depend on). Skipped if the repo is already present.
append_nvidia_cuda_repo() {
    local nvarch
    case "$ARCH" in
        x86_64)  nvarch="x86_64" ;;
        aarch64) nvarch="sbsa" ;;
        *)       nvarch="$ARCH" ;;
    esac
    local repo_url="https://developer.download.nvidia.com/compute/cuda/repos/${CUDA_REPO_RELEASE}/${nvarch}/cuda-${CUDA_REPO_RELEASE}.repo"
    if [ ! -f "/etc/yum.repos.d/cuda-${CUDA_REPO_RELEASE}.repo" ]; then
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR config-manager --add-repo $repo_url")
    fi
}

# NVIDIA's CUDA RPMs install their libs under /usr/local/cuda-*/targets/*/lib,
# which is not on the dynamic linker path. Without registering it, onnxruntime's
# CUDA provider cannot load libcudart.so.13 / libcublas.so.13 / etc. and GPU
# inference fails at runtime ("CUDA provider failed ... DefaultLogger"). cuDNN
# lives in /usr/lib64 and is already found. Register the dir(s) and refresh.
append_cuda_ldconfig() {
    COMMANDS+=("$SUDO_COMMAND sh -c 'ls -d /usr/local/cuda-*/targets/*/lib 2>/dev/null > /etc/ld.so.conf.d/openalpr-cuda.conf; ldconfig'")
}

# Append the GPU package + config edits when an NVIDIA GPU is present.
# $1 is the conf file whose hardware_acceleration / gpu_batch_size to set.
append_gpu_if_present() {
    local conf_file="$1"
    if hasNvidiaGpu; then
        echo "NVIDIA GPU detected — including GPU acceleration package"
        # The CUDA repo + ldconfig are set up unconditionally by the caller (the
        # OpenCV build needs CUDA even without a GPU), so just add the GPU package.
        # --allowerasing lets dnf swap the CPU stub (libalprgpusupport2) for the
        # CUDA variant (libalprgpusupportcuda2); they Conflict on the same soname.
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y --allowerasing $GPU_PACKAGE")
        COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^hardware_acceleration/!p' -e '\$ahardware_acceleration = 1' $conf_file")
        COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^gpu_batch_size/!p' -e '\$agpu_batch_size = 5' $conf_file")
    fi
}

# Dialog menu of major.minor.patch versions available across the model packages
# (dnf counterpart of the apt select_model_version_prefix). Echoes the choice.
select_model_version_prefix_rpm() {
    local pkgs="$1"
    local p family families latest menu_args installed_versions installed_v
    installed_versions=$(for p in $pkgs; do
        installed_v=$(rpm -q "$p" >/dev/null 2>&1 && rpm -q --qf '%{version}\n' "$p")
        [ -n "$installed_v" ] && echo "$installed_v" | cut -d. -f1-3
    done | sort -u)

    families=$(for p in $pkgs; do
        $PKG_MGR -q repoquery --qf '%{version}\n' "$p" 2>/dev/null | cut -d. -f1-2
    done | grep -v '^$' | sort -uV -r)

    if [ -z "$families" ]; then
        echo "No versions found for model packages" >&2
        return 1
    fi

    menu_args=""
    while IFS= read -r family; do
        latest=$(for p in $pkgs; do
            $PKG_MGR -q repoquery --qf '%{version}\n' "$p" 2>/dev/null
        done | grep -E "^${family}\." | cut -d. -f1-3 | sort -uV -r | head -n 1)
        if [ -n "$latest" ] && ! echo "$installed_versions" | grep -qxF "$latest"; then
            menu_args="$menu_args '$latest' ''"
        fi
    done <<< "$families"

    if [ -z "$menu_args" ]; then
        echo "No downgrade versions available" >&2
        return 1
    fi

    eval "dialog --stdout --backtitle 'Rekor Alpr Installer' --title 'Rekor Alpr Installer' --menu 'Select version to install:' 20 60 10 $menu_args"
}

# Install the given model packages at the newest build matching the chosen
# major.minor.patch prefix (dnf counterpart of downgrade_models_to_prefix).
downgrade_models_to_prefix_rpm() {
    local pkgs="$1"
    local prefix="$2"
    local list="" p v
    for p in $pkgs; do
        v=$($PKG_MGR -q repoquery --qf '%{version}-%{release}\n' "$p" 2>/dev/null | grep -E "^${prefix}(\.|-|$)" | sort -V | tail -n 1)
        [ -n "$v" ] && list="$list ${p}-${v}"
    done
    if [ -n "$list" ]; then
        echo "Installing:$list"
        $SUDO_COMMAND $PKG_MGR downgrade -y $list || $SUDO_COMMAND $PKG_MGR install -y $list
    else
        echo "No matching versions found for prefix $prefix"
        return 1
    fi
}

do_task_rpm() {
    task=$1

    echo ""
    echo "-------------------------------"
    echo "Executing task: $task"
    echo "-------------------------------"

    COMMANDS=()

    if [ "$task" == "install_agent" ]; then
        echo "Installing Rekor Scout Agent"
        dumpInformation
        createAlprConfFile

        append_repo_setup
        # The OpenCV build (libalpropencvgpu4) links CUDA (cuBLAS/cuFFT/NPP), so
        # the NVIDIA CUDA repo + linker path are required for every install, GPU
        # or not.
        append_nvidia_cuda_repo
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y $AGENT_PACKAGES")
        append_gpu_if_present "/etc/openalpr/alprd.conf"
        append_cuda_ldconfig
        if systemd_available; then
            COMMANDS+=("$SUDO_COMMAND systemctl daemon-reload || true")
            # beanstalkd is alprd's job queue; bring it up before the daemon.
            COMMANDS+=("$SUDO_COMMAND systemctl enable --now beanstalkd.service || true")
            COMMANDS+=("$SUDO_COMMAND systemctl enable openalpr-daemon.service || true")
            COMMANDS+=("$SUDO_COMMAND systemctl enable openalpr-link.service || true")
        fi
        run_commands_with_confirm

        echo ""
        echo "NOTE: Add your license key to /etc/openalpr/license.conf, then:"
        if systemd_available; then
            echo "  $SUDO_COMMAND systemctl start openalpr-daemon openalpr-link"
        else
            echo "systemd not detected (container/WSL) — services were not enabled."
            echo "Start the daemon manually, e.g.:  alprd -f"
        fi
    fi

    if [ "$task" == "install_sdk" ]; then
        echo "Installing Rekor Scout Developer SDK"
        dumpInformation
        createAlprConfFile

        append_repo_setup
        # OpenCV (libalpropencvgpu4) links CUDA, so the CUDA repo + linker path are
        # required for every install, GPU or not.
        append_nvidia_cuda_repo
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y $SDK_PACKAGES")
        append_gpu_if_present "/etc/openalpr/openalpr.conf"
        append_cuda_ldconfig
        run_commands_with_confirm

        echo ""
        echo "The Rekor Scout SDK requires a valid license."
        echo "Go to https://license.openalpr.com/evalrequest/ for a free 2-week evaluation key."
    fi

    if [ "$task" == "install_nvidia" ]; then
        echo "Installing Rekor Scout Nvidia Acceleration"
        dumpInformation
        if ! hasNvidiaGpu; then
            echo "WARNING: No NVIDIA GPU detected. Continuing anyway at your request."
        fi
        append_repo_setup
        append_nvidia_cuda_repo
        # --allowerasing lets dnf swap the CPU stub for the CUDA GPU support lib.
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y --allowerasing openalpr $GPU_PACKAGE")
        append_cuda_ldconfig
        if [ -f "/etc/openalpr/alprd.conf" ]; then
            COMMANDS+=("$SUDO_COMMAND sed -i -n -e '/^hardware_acceleration/!p' -e '\$ahardware_acceleration = 1' /etc/openalpr/alprd.conf")
        fi
        run_commands_with_confirm
    fi

    if [ "$task" == "uninstall_agent" ]; then
        echo "Removing Rekor Scout Agent"
        if systemd_available; then
            COMMANDS+=("$SUDO_COMMAND systemctl stop openalpr-link.service || true")
            COMMANDS+=("$SUDO_COMMAND systemctl stop openalpr-daemon.service || true")
        fi
        # Remove all installed openalpr/alpr packages (the web server is not
        # supported on Rocky, so there is nothing web-related to preserve).
        COMMANDS+=("PKGS=\$(rpm -qa 'openalpr*' 'libopenalpr*' 'libalpr*' 'librollingdb*' 'python3-openalpr' 'python3-alprstream' 'openalprgpu' 2>/dev/null); if [ -n \"\$PKGS\" ]; then $SUDO_COMMAND $PKG_MGR remove -y \$PKGS; else echo 'No OpenALPR packages installed'; fi")
        if [ -e "$REPO_FILE" ]; then
            COMMANDS+=("$SUDO_COMMAND rm -f $REPO_FILE")
        fi
        run_commands_with_confirm
    fi

    if [ "$task" == "update_models" ]; then
        echo "Updating Rekor Scout Model packages"
        dumpInformation
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y $MODEL_PACKAGES")
        run_commands_with_confirm
    fi

    if [ "$task" == "downgrade_models" ]; then
        echo "Downgrading Rekor Scout Model packages"
        dumpInformation
        MODEL_PKGS="libalpredge-data libalprocr-data libvehicleclassifier-data libvehiclesignature-data libopenalpr-data"

        # Set up the repo and refresh metadata first so we can query available
        # versions before showing the selection dialog.
        append_repo_setup
        for cmd in "${COMMANDS[@]}"; do
            eval "$cmd"
            if [ $? -ne 0 ]; then
                echo "Setup failed: $cmd"
                exit 1
            fi
        done
        COMMANDS=()

        SELECTED_PREFIX=$(select_model_version_prefix_rpm "$MODEL_PKGS")
        clear
        if [ -z "$SELECTED_PREFIX" ]; then
            echo "No version selected. Aborting."
            return
        fi
        echo "Selected version prefix: $SELECTED_PREFIX"

        COMMANDS+=("downgrade_models_to_prefix_rpm \"$MODEL_PKGS\" \"$SELECTED_PREFIX\"")
        run_commands_with_confirm
    fi

    if [ "$task" == "upgrade_software" ]; then
        echo "Upgrading Rekor Scout software"
        dumpInformation
        append_repo_setup
        COMMANDS+=("PKGS=\$(rpm -qa 'openalpr*' 'libopenalpr*' 'libalpr*' 'librollingdb*' 'python3-openalpr' 'python3-alprstream' 'openalprgpu' 2>/dev/null); if [ -n \"\$PKGS\" ]; then $SUDO_COMMAND $PKG_MGR upgrade -y \$PKGS; else echo 'No OpenALPR packages installed'; fi")
        if systemd_available; then
            # try-restart only bounces services that are currently running.
            COMMANDS+=("$SUDO_COMMAND systemctl try-restart openalpr-daemon.service openalpr-link.service || true")
        fi
        run_commands_with_confirm
    fi

    if [ "$task" == "download_packages" ]; then
        echo "Downloading Rekor Scout packages (without installing)"
        dumpInformation
        DEST="$PWD/openalpr-packages"
        append_repo_setup
        COMMANDS+=("$SUDO_COMMAND mkdir -p $DEST")
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR download --resolve --alldeps --destdir $DEST $AGENT_PACKAGES $SDK_PACKAGES")
        if hasNvidiaGpu; then
            COMMANDS+=("$SUDO_COMMAND $PKG_MGR download --resolve --alldeps --destdir $DEST $GPU_PACKAGE")
        fi
        run_commands_with_confirm
        echo "Packages downloaded to $DEST"
    fi

    if [ "$task" == "install_test" ]; then
        dumpInformation
        # check if alpr sdk is installed
        if python3 -c "import alprstream" >/dev/null 2>&1; then
            # cv2 is provided by libalpropencvgpu-python3 (installed with the SDK).
            $SUDO_COMMAND rm -f /tmp/rekor-test.tar
            # rekor-test.tar is hosted only on deb.openalpr.com (not the rpm repo).
            # Use curl (a prerequisite) since wget isn't installed by default on Rocky.
            curl -fSL -o /tmp/rekor-test.tar https://deb.openalpr.com/rekor-test.tar

            $SUDO_COMMAND mkdir -p /opt/rekor/test
            $SUDO_COMMAND tar xvf /tmp/rekor-test.tar -C /opt/rekor/test

            echo ""
            echo "To Execute the test, make sure that the sdk is installed  "
            echo "and you have a valid SDK license."
            echo "To run it with the GPU, use the -g option"
            echo "Then cd /opt/rekor/test and execute ./smoke_test.sh [-g]"
        else
            echo ""
            echo "This test requires a SDK license"
            echo "And you will need to install the Rekor Scout Developer SDK first"
        fi
    fi

    if [ "$task" == "register_agent" ]; then

        WEB_SERVER_INSTALLED=0
        rpm -q openalpr-web > /dev/null 2>&1 && WEB_SERVER_INSTALLED=1

        if rpm -q openalpr-link > /dev/null 2>&1; then

            # Check if GUI environment is configured
            if [[ ! -z "$GDMSESSION" ]]; then
                echo ""
                echo "Agent Configuration"
                prompt_confirm "Do you wish to launch the ALPR Configuration Utility? "
                if [[ $? == "0" ]]; then
                    $SUDO_COMMAND alprdconfig
                fi
            else
                # No GUI

                # Check for a valid license by seeing if the license files have any content
                HAS_LICENSE="0"
                if [[ -s /etc/openalpr/license.conf ]]; then
                    echo "Local license file exists"
                    HAS_LICENSE="1"
                fi
                if [[ -s /etc/openalpr/onlinelicense.conf ]]; then
                    echo "Local license file exists"
                    HAS_LICENSE="1"
                fi

                if [[ "$HAS_LICENSE" == "0" ]]; then
                    echo ""
                    echo "Agent Licensing"
                    prompt_confirm "Do you wish to activate your license with your account on https://cloud.openalpr.com/ ? "
                    if [[ $? == "0" ]]; then
                        $SUDO_COMMAND openalpr-licenseregister
                    fi
                fi

                WEBSERVER_HOST="https://cloud.openalpr.com"
                if [ "$WEB_SERVER_INSTALLED" == "1" ]; then
                    WEBSERVER_HOST=https://localhost
                fi

                # Check if the alprd settings have already been set
                cat /etc/openalpr/alprd.conf | grep -E "company_id\s*=\s*[a-z0-9A-Z]+" > /dev/null 2>&1
                ALREADY_CONFIGURED=$?
                if [[ $ALREADY_CONFIGURED == "1" ]]; then
                    # Not configured yet — no company_id in alprd.conf
                    echo ""
                    echo "Agent Registration"
                    prompt_confirm "Do you wish to register the agent with $WEBSERVER_HOST? "
                    REGISTER_AGENT=$?
                    echo ""

                    if [[ $REGISTER_AGENT == "0" ]]; then
                        until $SUDO_COMMAND alprlink-register -w "$WEBSERVER_HOST"; do
                            echo "Please try again..."
                        done
                    fi
                fi
            fi
        else
            # AlprLink is not installed
            if rpm -q libopenalpr2 > /dev/null 2>&1; then
                HAS_LICENSE="0"
                if [[ -s /etc/openalpr/license.conf ]]; then
                    HAS_LICENSE="1"
                fi

                if [[ "$HAS_LICENSE" == "0" ]]; then
                    echo ""
                    echo "Agent Licensing"
                    echo "The Rekor Scout SDK requires a valid license.  Go to https://license.openalpr.com/evalrequest/ to request a free 2-week evaluation key."
                    echo ""
                fi
            fi
        fi
    fi

    # Hidden task (intentionally not in the menu): install the openalpr-tests
    # package. Run with:  ./install -i install_openalpr_tests
    if [ "$task" == "install_openalpr_tests" ]; then
        echo "Installing openalpr-tests package"
        dumpInformation
        append_repo_setup
        append_nvidia_cuda_repo
        COMMANDS+=("$SUDO_COMMAND $PKG_MGR install -y openalpr-tests")
        append_cuda_ldconfig
        run_commands_with_confirm
    fi

    if [ "$task" == "system_info" ]; then
        dumpInformation
    fi
}

prereqs_rpm() {
    PREREQS=""
    for pkg in dialog ca-certificates pciutils curl "dnf-plugins-core"; do
        if ! rpm -q "$pkg" >/dev/null 2>&1; then
            PREREQS="$PREREQS $pkg"
        fi
    done

    if [ -z "$PREREQS" ]; then
        echo "Prerequisites satisfied"
    else
        echo "Installing prerequisites:$PREREQS"
        # EPEL + CRB provide some prerequisites and OpenALPR build/runtime deps.
        $SUDO_COMMAND $PKG_MGR install -y epel-release >/dev/null 2>&1 || true
        $SUDO_COMMAND $PKG_MGR config-manager --set-enabled crb >/dev/null 2>&1 || true
        $SUDO_COMMAND $PKG_MGR install -y $PREREQS < /dev/null
    fi
}

set_options_rpm() {
    OPTIONS=(\
    install_agent       "Install Rekor Scout $INFO_QUALIFIER Agent" \
    install_sdk         "Install Rekor Scout $INFO_QUALIFIER Developer SDK" \
    install_nvidia      "Install Rekor Scout Nvidia Acceleration" \
    install_test        "Install Rekor Scout Test Software" \
    register_agent      "Register Agent" \
    update_models       "Update Rekor Scout Model packages" \
    downgrade_models    "Downgrade Rekor Scout Model packages to previous version" \
    upgrade_software    "Upgrade to the latest Rekor software" \
    download_packages   "Download Rekor Scout packages (without installing)" \
    uninstall_agent     "Uninstall Rekor Scout Agent" \
    system_info         "Dump System Information" )
}

#//////////////////////////////////////////////////////////////////////////////
#
#  MAIN
#
#//////////////////////////////////////////////////////////////////////////////
trap ctrl_c INT
function ctrl_c() {
    exit 1
}

detect_pkg_family

# Privilege / sudo handling
if [[ $EUID -eq 0 ]]; then
    SUDO_COMMAND=""
else
    SUDO_COMMAND="sudo"
    if ! which sudo >/dev/null 2>&1; then
        echo "sudo command not found.  You must have this installed in order to continue."
        if [ "$PKG_FAMILY" = "rpm" ]; then
            echo "You can install sudo with the command:  dnf install sudo"
        else
            echo "You can install sudo with the command:  apt-get install sudo"
        fi
        exit 1
    fi
fi

# Determine CUDA version (can be skipped with REKOR_IGNORE_CUDA)
if [ -z "$REKOR_IGNORE_CUDA" ]; then
    echo "Determining CUDA version"
    getCudaVersion
fi

# Container detection
if [ -f /.dockerenv ]; then
    CONTAINER_INSTALL=1
    [ "$PKG_FAMILY" = "deb" ] && EXTRA_PACKAGES+=" supervisor"
fi

INFO_QUALIFIER="GA"

# OS detection + menu options, per family
if [ "$PKG_FAMILY" = "rpm" ]; then
    detect_os_rpm
    set_options_rpm
else
    detect_os_deb
    set_options_deb
fi

# Argument parsing
while getopts "yi:" flag; do
    case "${flag}" in
    i) INSTALL_TYPE=${OPTARG} ;;
    y) ALL_YES=1 ;;
    esac
done

# Prerequisites
if [ "$PKG_FAMILY" = "rpm" ]; then
    prereqs_rpm
else
    prereqs_deb
fi

if [ -z "$INSTALL_TYPE" ]; then

    NUM_ITEMS=$((${#OPTIONS[@]} / 2))
    LIST_HEIGHT=$NUM_ITEMS
    DIALOG_HEIGHT=$((NUM_ITEMS + 7))
    DIALOG_ARGS="--backtitle \"Rekor Alpr Installer\" --title \"Rekor Alpr Installer\" --checklist \"Choose Install Tasks (Press SPACE to select):\" $DIALOG_HEIGHT 72 $LIST_HEIGHT"

    end_array=$((${#OPTIONS[@]} - 1))
    for i in $(seq 0 2 $end_array); do
        DIALOG_ARGS="$DIALOG_ARGS '${OPTIONS[$i]}' '${OPTIONS[$i + 1]}' off"
    done

    TEMP_CHOICE_RESULTS_FILE=$(mktemp)

    get_install_selection() {
        eval "dialog $DIALOG_ARGS" 2> "$TEMP_CHOICE_RESULTS_FILE"
    }

    while [ true ]; do

        get_install_selection
        if [ $? -ne 0 ]; then
            echo "Installation canceled."
            break
        fi

        clear
        choices=$(cat "$TEMP_CHOICE_RESULTS_FILE")
        echo "" > "$TEMP_CHOICE_RESULTS_FILE"

        for choice in $choices; do
            # remove prefix/suffix quote (") characters
            choice="${choice%\"}"
            choice="${choice#\"}"

            echo "Your choice: $choice"
            do_task "$choice"
        done

        echo "Installation Complete"
        break

    done

    rm -f "$TEMP_CHOICE_RESULTS_FILE"
else
    echo "Installing $INSTALL_TYPE"
    do_task "$INSTALL_TYPE"
    echo "Installation Complete - need to register and add license"
fi
