#!/bin/bash

RELEASE_NAME=$(cat /etc/lsb-release | grep DISTRIB_CODENAME | sed 's/DISTRIB_CODENAME\s*=\s*//g')
REPO_POSTFIX="/"
REPO_PREFIX=""
OS_NAME=""
EXTRA_PACKAGES=""
# default 0 for not a container install
# only used for agent install
CONTAINER_INSTALL=0
CUDAVER=0
DEFAULTCUDA_FOCAL=("11.4.0" )
DEFAULTCUDA_JAMMY=("12.6.0" "12.9.0")
DEFAULTCUDA_NOBLE=("12.9.0" "13.0.0")
ARCH=$(uname -m)
cuda_version=""
cuda_driver_support_version=""

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 driver we support
    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)
    fi

    if [ -x "$nvcc_cmd" ]; then
        if $nvcc_cmd --version &>/dev/null; then
            # Determine CUDA version using default nvcc binary
            cuda_version=$($nvcc_cmd --version | sed -n 's/^.*release \([0-9]\+\.[0-9]\+\).*$/\1/p')
        fi
    elif [ -f "$cuda_version_file" ]; then
        # Determine CUDA version using /usr/local/cuda/version.json file
        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
}


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

# try and find the cuda version - We can ignore CUDA with the env variable
if [ ! -n "$REKOR_IGNORE_CUDA" ]; then
    echo "determining CUDA version"
    getCudaVersion
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
        # We are running JetPack 3.1
        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
        # We are running JetPack 3.2
        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
        # We are running JetPack 4.0.x
        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
        # We are running JetPack 4.2.x
        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
        # We are running JetPack 4.3.x
        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
        # We are running JetPack 4.4.x
        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
        # We are running JetPack 4.6.x
        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
        # We are running JetPack 5.1.x
        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
        # We are running JetPack 6.1
        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"

    if [[ $CUDAVER == 12.6 || $CUDAVER == 12.6.* ]]; then
        OS_NAME="Ubuntu Jammy"
        EXTRA_PACKAGES="libcudnn9-cuda-12"
        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda126${REPO_POSTFIX} jammycuda126 main"
#    elif [[ $CUDAVER == 13 || $CUDAVER == 13.* || $CUDAVER == 13.*.* ]]; then
#        OS_NAME="Ubuntu Jammy"
#        EXTRA_PACKAGES="libcudnn9-cuda-13"
#        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda130${REPO_POSTFIX} jammycuda130 main"
#    elif [[ $CUDAVER == 12.9 || $CUDAVER == 12.9.* ]]; then
#        OS_NAME="Ubuntu Jammy"
#        EXTRA_PACKAGES="libcudnn9-cuda-12"
#        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}jammycuda129${REPO_POSTFIX} jammycuda129 main"
    else
        OS_NAME="Ubuntu Jammy"
        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"

#    if [[ $CUDAVER == 13 || $CUDAVER == 13.* || $CUDAVER == 13.*.* ]]; then
#        OS_NAME="Ubuntu Noble"
#        EXTRA_PACKAGES="libcudnn9-cuda-13"
#        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noblecuda130${REPO_POSTFIX} noblecuda130 main"
#    elif [[ $CUDAVER == 12.9 || $CUDAVER == 12.9.* ]]; then
#        OS_NAME="Ubuntu Noble"
#        EXTRA_PACKAGES="libcudnn9-cuda-12"
#        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noblecuda129${REPO_POSTFIX} noblecuda129 main"
#    else
        OS_NAME="Ubuntu Noble"
        DEB_REPO_PATH="deb https://deb.openalpr.com/${REPO_PREFIX}noble${REPO_POSTFIX} noble main"
#    fi

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

if [[ $EUID -eq 0 ]]; then
    # Running as root
    SUDO_COMMAND=""
else
    # Not running as root
    SUDO_COMMAND="sudo"

    # Check if sudo is available
    which sudo >/dev/null 2>&1
    if [ "$?" == "1" ]; then
        echo "sudo command not found.  You must have this installed in order to continue."
        echo "You can install sudo with the command:"
        echo "  apt-get install sudo."
        exit 1
    fi
fi

## Are we in a container???
if [ -f /.dockerenv ]; then
    EXTRA_PACKAGES+=" supervisor"
    CONTAINER_INSTALL=1
fi

INFO_QUALIFIER="Latest Testing"


declare -a 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" \
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" )

DEBUG=0

ALL_YES=0
INSTALL_TYPE=""

if [ "$1" == "-y" ]; then
    ALL_YES=1
fi

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

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
#-------------------------------
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() {
    # Wait for dpkg/apt locks or processes to clear
    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

    # Ensure no package triggers are still running
    wait_for_apt

    # Ensure systemd sees any changed unit files from upgrades
    $SUDO_COMMAND systemctl daemon-reload || true

    # Optionally ensure network-online if required by these services
    $SUDO_COMMAND systemctl is-active --quiet network-online.target || \
        $SUDO_COMMAND systemctl start network-online.target || true

    # Restart each service individually with retries and post-checks
    local unit attempt
    for unit in "${SERVICES[@]}"; do
        # Clear any latched failed state
        $SUDO_COMMAND systemctl reset-failed -- "$unit" || true

        # Stop ignoring errors, then start with up to 3 attempts
        $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
}

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
}

append_repo_setup() {
    # 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")
}

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
}

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

  nvidia-smi --query-gpu=index,name,compute_cap --format=csv,noheader | while IFS=, read idx name cc; do
    ver=$(echo $cc | tr -d '. ')
    [ "$ver" -lt 75 ] && status="BELOW 7.5 ⚠️" || status="7.5 or above ✅"
    echo "GPU $idx ($name) — cc$cc — $status"
  done
} 


dumpInformation() {
    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
}

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

do_task() {
    task=$1

    if [ "$DEBUG" -eq 1 ]; then
        echo "Bypassing task $task due to debug enabled"
        return 0
    else
        echo ""
        echo "-------------------------------"
        echo "Executing task: $task"
        echo "-------------------------------"
    fi

    task=$1

    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"
            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 

        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 
#        if [[ $tempOS == "ubuntu jammy" && $has_web ]]; then
#
#            SERVICES=("openalpr-systeminterface.service"
#                "openalpr-websockets.service"
#                "openalpr-router.service"
#                "openalpr-web.service")
#
#            echo "Restarting services" "${SERVICES[@]}"
#            services_stop
#            sleep 1
#            services_restart
#        fi

    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" == "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
}

# Trap CTRL-C (Cancel the entire script if CTRL-C)
trap ctrl_c INT

function ctrl_c() {
    exit 1
}

PREREQS=""

# Check if dialog is already installed
$SUDO_COMMAND dpkg -s dialog > /dev/null 2>&1
if [ "$?" == "1" ]; then
    PREREQS=$PREREQS" dialog"
fi

# Check if ca-certificates is already installed
$SUDO_COMMAND dpkg -s ca-certificates > /dev/null 2>&1
if [ "$?" == "1" ]; then
    PREREQS=$PREREQS" ca-certificates"
fi

# Check if apt-transport-https is installed
$SUDO_COMMAND dpkg -s apt-transport-https > /dev/null 2>&1
if [ "$?" == "1" ]; then
    PREREQS=$PREREQS" apt-transport-https"
fi

# Check if apt-transport-https is installed
$SUDO_COMMAND dpkg -s gnupg > /dev/null 2>&1
if [ "$?" == "1" ]; then
    PREREQS=$PREREQS" gnupg"
fi

# Check if prereq is installed
$SUDO_COMMAND dpkg -s lsof > /dev/null 2>&1
if [ "$?" == "1" ]; then
    PREREQS=$PREREQS" lsof"
fi

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

if [ -z "$INSTALL_TYPE" ]; then

    DIALOG_ARGS='--checklist "Choose Install Tasks (Press SPACE to select):" 18 72 10 '

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

    done

    TEMP_CHOICE_RESULTS_FILE=/tmp/choice_results
    $SUDO_COMMAND rm $TEMP_CHOICE_RESULTS_FILE
    touch $TEMP_CHOICE_RESULTS_FILE

    get_install_selection() {
        echo dialog ${DIALOG_ARGS} | bash 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/suffice quote (") characters
            choice="${choice%\"}"
            choice="${choice#\"}"

            # Do it
            echo "Your choice: $choice"
            do_task $choice
        done

        ### disable, since we added it to the menu
        # If they chose at least one thing
        #        if [ ${#choice[@]} -gt 0 ]; then
        #            do_task register_agent
        #        else
        #            continue
        #        fi

        echo "Installation Complete"
        break

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