#!/bin/bash

# Copyright (C) 2013-2025 Marcin Krol <hawk@tld-linux.org>
# All Rights Reserved

. /lib/cri/vars

# read configuration
. /lib/cri/system.config

dialog_title="System image installation"

mirror_selection () {
  # create options file for dialog
  local idx
  idx=0
  cat >/tmp/dialog.opts <<EOF
    --backtitle "${dialog_backtitle}"
    --title "${dialog_title}"
    --colors
    --cancel-label "Back"
    --extra-button
    --extra-label "Custom"
    --help-button
    --help-label "Quit"
    --menu "\nSelect image repository to install from:\n "
      19 74 10
    $(
      grep -E "^[0-9]+\s+(ftp|http|https)://" /lib/cri/mirrors 2>/dev/null | while read id url desc; do
        # check if params are not empty
        if [ "${id}" = "" ] || [ "${url}" = "" ] || [ "${desc}" = "" ]; then
          continue
        else
          echo "${url}" >/tmp/mirror.cri.${id}
          echo "\"${id}\" \"${url} (${desc})\""
        fi
      done
    )
EOF
  # show mirror seletion menu
  dialog --file /tmp/dialog.opts \
    2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
  return $?
}

custom_mirror () {
  dialog \
    --backtitle "${dialog_backtitle}" \
    --title "${dialog_title}" \
    --colors \
    --cancel-label "Quit" \
    --extra-button \
    --extra-label "Back" \
    --inputbox "\nEnter full URL at which image repository is available. Examples:\n\n\Z5https://pirx.dev/linux/\nhttps://dist.tld-linux.org/CRI/images/\n\Zn" \
    14 60 \
    "" \
    2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
  return $?
}

show_menu () {
  # cleanup temporary data
  rm -f /tmp/cri.index.* 2>/dev/null
  # create options file for dialog
  cat >/tmp/dialog.opts <<EOF
    --backtitle "${dialog_backtitle}" \
    --title "${dialog_title}" \
    --cancel-label "Quit" \
    --colors \
    --cr-wrap \
    $(if ! [ -z "${1}" ]; then echo "--extra-button --extra-label \"Back\""; fi)
    --menu "\nPlease select system image that you want to install:\n " \
    19 74 10 \
  $(
    if [ -z "${1}" ]; then
      regex="^[0-9]+\s+"
    else
      regex="^"${1}"-[0-9]+\s+"
    fi
    grep -E "${regex}" "${lds_index}" | while read cr_id cr_distro cr_tar cr_desc; do
      # check entry parameters if not empty
      if [ -z "${cr_id}" ] || [ -z "${cr_distro}" ] || [ -z "${cr_tar}" ] || [ -z "${cr_desc}" ]; then
        continue
      else
        echo "cr_id=\"${cr_id}\"" >/tmp/cri.index.${cr_id}
        echo "cr_distro=\"${cr_distro}\"" >>/tmp/cri.index.${cr_id}
        echo "cr_tar=\"${cr_tar}\"" >>/tmp/cri.index.${cr_id}
        echo "cr_desc=\"${cr_desc}\"" >>/tmp/cri.index.${cr_id}
        echo "\"${cr_id#[0-9]*-}\" \"${cr_desc}\""
      fi
    done
  )
EOF
  dialog --file /tmp/dialog.opts \
    2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
  return $?
}

# if no args specified show usage info
if [ "${1}" = "" ]; then
  echo "Usage: $(basename "${0}" 2>/dev/null) <destination path>"
fi

# allow only absolute destination paths
if ! echo "${1}" | grep -E -q "^/"; then
  echo "[1;31mError:[0m please use absolute path as destination"
  exit 1
fi

# check if destination path exist and bail out if not
if ! [ -d "${1}" ]; then
  echo "[1;31mError:[0m bad destination path specified"
  exit 1
fi

# destination path seems to be correct, get rid of trailing backslashes
destination_path=$(echo "${1}" | sed -e 's/[\/]*$//g' 2>/dev/null)

cat >/lib/cri/crinit.opts <<EOF
crinit_hostname=1
crinit_timezone=1
crinit_network=1
crinit_netifnames=1
crinit_netrules=1
crinit_fstab=1
crinit_crypttab=1
crinit_mdadm=1
crinit_sshkeys=1
crinit_rootpw=1
crinit_user=1
crinit_initrd=1
crinit_grubconfig=1
crinit_grubinstall=1
EOF

/lib/cri/install.pre
result=$?
if [ "${result}" -ne 0 ]; then
  clear
  exit 1
fi

# reread configuration
. /lib/cri/system.config

# installation source selection
while : ; do
  # create options file for dialog
 cat >/tmp/dialog.opts <<EOF
    --backtitle "${dialog_backtitle}"
    --title "${dialog_title}"
    --colors
    --cancel-label "Quit"
    --menu "\nSelect source media for installation:\n "
      12 50 3
      "1" "FTP/HTTP/HTTPS server"
      "2" "CD/DVD or USB disk"
      "3" "Local storage"
EOF
  # show architecture seletion menu
  dialog --file /tmp/dialog.opts \
    2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
  result=$?
  if [ "${result}" -eq 1 ]; then
    clear
    exit 1
  fi
  selection=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
  case "${selection}" in
    1)
      while : ; do
        mirror_selection
        result=$?
        selection=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
        if [ "${result}" -eq 0 ]; then
          cri_repository=$(cat /tmp/mirror.cri."${selection}" 2>/dev/null)
          break 2
        elif [ "${result}" -eq 1 ]; then
          break
        elif [ "${result}" -eq 2 ]; then
          clear
          exit 1
        elif [ "${result}" -eq 3 ]; then
          while : ; do
            custom_mirror
            result=$?
            if [ "${result}" -eq 1 ]; then
              clear
              exit 1
            elif [ "${result}" -eq 0 ]; then
              cri_repository=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
              if echo "${cri_repository}" | grep -q -E "^(http|ftp)://.+\..+"; then
                break 3
              else
                dialog \
                  --backtitle "${dialog_backtitle}" \
                  --title "${dialog_title}" \
                  --colors \
                  --msgbox "\n\Z1Error!\Zn\n\nInvalid mirror URL specified. Only FTP and HTTP protocols are supported." 10 60
              fi
            elif [ "${result}" -eq 3 ]; then
              unset "${cri_repository}"
              break
            fi
          done
        fi
      done
      ;;
    2)
      clear
      /lib/cri/crimedia
      if [ -s "/lib/cri/media" ]; then
        cat >/tmp/dialog.opts <<EOF
          --backtitle "${dialog_backtitle}" \
          --title "${dialog_title}" \
          --colors \
          --extra-button \
          --extra-label "Back" \
          --cancel-label "Quit" \
          --menu "\nChoose one of detected CRI devices from which you wish to install:" \
          19 70 11 \
          $(
            for cridev in $(cat /lib/cri/media); do
              echo "\"${cridev}\" \"\""
            done
          )
EOF
        dialog --file /tmp/dialog.opts \
          2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
        result=$?
        if [ "${result}" -eq 1 ]; then
          clear
          exit 1
        elif [ "${result}" -eq 0 ]; then
          cri_device=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
          mountpoint -q "/media/cri" 1>/dev/null 2>/dev/null
          result=$?
          if [ "${result}" -eq 0 ]; then
            umount /media/cri 1>/dev/null 2>/dev/null
          fi
          mount "${cri_device}" /media/cri 1>/dev/null 2>/dev/null
          result=$?
          if [ "${result}" -eq 0 ]; then
            cri_repository=$(dirname $(find /media/cri -type f -name lds.index 2>/dev/null | head -n 1) 2>/dev/null)
            if [ -z "${cri_repository}" ]; then
              dialog \
                --backtitle "${dialog_backtitle}" \
                --title "${dialog_title}" \
                --colors \
                --msgbox "\n\Z1Error!\Zn\n\nNo system images found on selected device. Choose other device or different image repository." \
                10 60
            else
              break
            fi
          else
            dialog \
              --backtitle "${dialog_backtitle}" \
              --title "${dialog_title}" \
              --colors \
              --msgbox "\n\Z1Error!\Zn\n\nMounting ${cri_device} has failed. Choose other device or different image repository." \
              10 60
          fi
        fi
      fi
      ;;
    3)
      while : ; do
        dialog \
          --backtitle "${dialog_backtitle}" \
          --title "${dialog_title}" \
          --colors \
          --cancel-label "Quit" \
          --extra-button \
          --extra-label "Back" \
          --inputbox "\nEnter path to image repository. Examples:\n\n\Zn\Z5/media/cri/\n\Z5/home/user/cri/images\n\Zn" \
          13 60 \
          2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
        result=$?
        if [ "${result}" -eq 1 ]; then
          clear
          exit 1
        elif [ "${result}" -eq 3 ]; then
          break
        fi
        cri_repository=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
        if echo "${cri_repository}" | grep -E -q "^/.+"; then
          if ! [ -d "${cri_repository}" ]; then
            dialog \
              --backtitle "${dialog_backtitle}" \
              --title "${dialog_title}" \
              --colors \
              --msgbox "\n\Z1Error!\Zn\n\nSpecified path does not exists." \
              9 60
          else
            break 2
          fi
        else
          dialog \
            --backtitle "${dialog_backtitle}" \
            --title "${dialog_title}" \
            --colors \
            --msgbox "\n\Z1Error!\Zn\n\nInvalid path. Only full absolute paths are supported." \
            9 60
        fi
      done
      ;;
  esac
done

clear

# LDS index temporary file
lds_index="/lib/cri/lds.index"

# little cleanup
rm -f "${lds_index}"

# get rid of trailing backslashes in source path/url
cri_repository=$(echo "${cri_repository}" | sed -e 's/[\/]*$//g' 2>/dev/null)

# try to get list of available system images
if echo "${cri_repository}" | grep -E -q "^(ftp|http|https)://.+\..+"; then
  # our source is FTP/HTTP/HTTPS URL, try to download index
  echo "Fetching list of available system images"
  wget --quiet --timeout=30 --tries=5 --prefer-family=IPv4 --continue --no-cookies --no-check-certificate "${cri_repository}/lds.index" -O "${lds_index}"
  result=$?
  if [ "${result}" -ne 0 ]; then
    echo "[1;31mError:[0m unable to download image index from ${cri_repository}"
    rm -f "${lds_index}"
    exit 1
  fi
elif echo "${cri_repository}" | grep -E -q "^/"; then
  # our source is system path, check if it contains index
  if ! [ -s "${cri_repository}/lds.index" ]; then
    echo "[1;31mError:[0m image index not found or empty"
    exit 1
  else
    cp -f "${cri_repository}/lds.index" "${lds_index}" 1>/dev/null 2>/dev/null
  fi
else
  # unknown source type
  echo "[1;31mError:[0m bad image repository, must be either system path or URL"
  exit 1
fi

# if we are here we should have valid list of system images
# launch menu to allow user select what he wants to install

sleep 1
menu_id=""
while : ; do
  show_menu "${menu_id}"
  result=$?
  if [ "${result}" -eq 1 ]; then
    clear
    exit 1
  elif [ "${result}" -eq 3 ]; then
    menu_id=""
    continue
  else
    selection=$(cat /tmp/$(basename "${0}.dialog" 2>/dev/null) 2>/dev/null)
    if ! [ -z "${menu_id}" ]; then
      selection="${menu_id}-${selection}"
    fi
    # system image was selected, read its data
    . /tmp/cri.index."${selection}"
    # check for submenu
    if [ "${cr_distro}" = "-" ]; then
      menu_id="${cr_id}"
      continue
    else
      # confirm installation
      dialog \
        --backtitle "${dialog_backtitle}" \
        --title "${dialog_title}" \
        --colors \
        --extra-button \
        --extra-label "No" \
        --no-label "Quit" \
        --yesno "\nYou are about to install following system image:\n\n\Z5${cr_desc}\Zn\n\nDestination path : ${destination_path}\n\nProceed with installation?" \
        13 76 \
      2>/tmp/$(basename "${0}.dialog" 2>/dev/null)
      result=$?
      # if user wants to proceed, exit menu loop and proceed
      if [ "${result}" -eq 0 ]; then
        clear
        break
      # if quit was chosen, exit
      elif [ "${result}" -eq 1 ]; then
        clear
        exit 1
      fi
    fi
  fi
done

# if we are here we should have all data needed to install system image
clear

# if installing from network, download and uncompress on the fly to destination path
echo "Installing ${cr_desc}"
if echo "${cri_repository}" | grep -E -q "^(ftp|http|https)://.+\..+"; then
  wget --quiet --timeout=30 --tries=5 --prefer-family=IPv4 --continue --no-cookies --no-check-certificate --show-progress --progress=bar:force "${cri_repository}/${cr_tar}" -O- | tar Jxf - -C "${destination_path}"
  result=$?
  if [ "${result}" -ne 0 ]; then
    echo "[1;31mError:[0m unable to download system image from ${cri_repository}"
    exit 1
  fi
# if installing from local repository, uncompress to destination path
elif echo "${cri_repository}" | grep -E -q "^/"; then
  pv "${cri_repository}/${cr_tar}" | tar Jxf - -C "${destination_path}"
fi

/lib/cri/install.post "${destination_path}"

exit 0
