#!/bin/bash

# shellcheck disable=SC1091,SC2016,SC2086,SC2181

# @license   http://www.gnu.org/licenses/gpl.html GPL Version 3
# @author    OpenMediaVault Plugin Developers <plugins@omv-extras.org>
# @copyright Copyright (c) 2013-2026 openmediavault plugin developers
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

. /etc/default/openmediavault

arch="$(dpkg --print-architecture)"
if [ ! "${arch}" = "amd64" ]; then
  echo "Unsupported architecture."
  exit 1
fi

OMV_SOURCEFORGE_URL=${OMV_SOURCEFORGE_URL:-"https://sourceforge.net/projects"}
GRUB_PATH="/etc/grub.d"

subdir="${OMV_KERNEL_BOOT_ISO_SUBDIR#/}"
ISO_PATH="/boot${subdir:+/${subdir%/}}"

declare -A VERSIONS=(
  ["clonezilla"]="3.3.3-15"
  ["finnix"]="251"
  ["gpartedlive"]="1.8.1-3"
  ["sysresccd"]="13.02"
)

declare -A GRUB_FILES=(
  ["clonezilla"]="${GRUB_PATH}/42_clonezilla"
  ["finnix"]="${GRUB_PATH}/42_finnix"
  ["gpartedlive"]="${GRUB_PATH}/42_gpartedlive"
  ["sysresccd"]="${GRUB_PATH}/42_sysresccd"
)

declare -A GRUB_NAMES=(
  ["clonezilla"]="Clonezilla Live ${VERSIONS[clonezilla]}"
  ["finnix"]="Finnix ${VERSIONS[finnix]}"
  ["gpartedlive"]="GParted Live ${VERSIONS[gpartedlive]}"
  ["sysresccd"]="SystemRescue ${VERSIONS[sysresccd]}"
)

declare -A URLS=(
  ["clonezilla"]="${OMV_SOURCEFORGE_URL}/clonezilla/files/clonezilla_live_stable/${VERSIONS[clonezilla]}/clonezilla-live-${VERSIONS[clonezilla]}-amd64.iso/download"
  ["finnix"]="https://www.finnix.org/releases/${VERSIONS[finnix]}/finnix-${VERSIONS[finnix]}.iso"
  ["gpartedlive"]="${OMV_SOURCEFORGE_URL}/gparted/files/gparted-live-stable/${VERSIONS[gpartedlive]}/gparted-live-${VERSIONS[gpartedlive]}-amd64.iso/download"
  ["sysresccd"]="${OMV_SOURCEFORGE_URL}/systemrescuecd/files/sysresccd-x86/${VERSIONS[sysresccd]}/systemrescue-${VERSIONS[sysresccd]}-amd64.iso/download"
)

declare -A CHECKSUMS=(
  ["clonezilla"]="482518ea32af3b82ed15d09e2e7714806775deb62aeed81491e534f6cc6bbc47"
  ["finnix"]="a635a75a155d8640956c5640fc49268b4a89ce7013fdc7d19f1dfdc8529e9a9e"
  ["gpartedlive"]="3f66b2e10b8bb2c573ed6cdd3a9b54fd0a8e7690634ab6b15c3c8f517992d1a1"
  ["sysresccd"]="ad4d670b72859d887c7960142a9a9d36a3e50446694a035e254442f65d6e7572"
)

declare -A FILES=(
  ["clonezilla"]="clonezilla-live-${VERSIONS[clonezilla]}-amd64.iso"
  ["finnix"]="finnix-${VERSIONS[finnix]}.iso"
  ["gpartedlive"]="gparted-live-${VERSIONS[gpartedlive]}-amd64.iso"
  ["sysresccd"]="systemrescue-${VERSIONS[sysresccd]}-amd64.iso"
)

declare -A RM=(
  ["clonezilla"]="clonezilla-live*.iso"
  ["finnix"]="finnix*.iso"
  ["gpartedlive"]="gparted-live*.iso"
  ["sysresccd"]="systemrescue*.iso"
)

GRUB="/etc/default/grub"

checkDNS() {
  host="/usr/bin/host"
  hostDomain="$(echo "${OMV_SOURCEFORGE_URL}" | sed -e 's/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/')"
  echo "Checking DNS with '${hostDomain}' ..."
  if [ -f "${host}" ]; then
    if ! ${host} ${hostDomain} > /dev/null; then
      echo "DNS error.  Exiting ..."
      exit 1
    else
      echo "DNS OK."
    fi
  fi
}

install_iso() {
  local iso=$1
  local url=${URLS[$iso]}
  local iso_file="${ISO_PATH}/${FILES[$iso]}"
  local iso_pattern="${RM[$iso]}"
  local checksum=${CHECKSUMS[$iso]}
  local grub_file=${GRUB_FILES[$iso]}
  local grub_name=${GRUB_NAMES[$iso]}
  local grub_isofile="${iso_file}"

  checkDNS

  echo "Installing ${iso}..."
  if [ ! -f "${iso_file}" ]; then
    find /boot -type f -name "${iso_pattern}" -ls -delete
    wget "${url}" -O "${iso_file}" 2>&1
    if [ $? -gt 0 ]; then
      echo "Download failed. Deleting ${iso} file and exiting..."
      rm -f "${iso_file}"
      exit 2
    fi
    echo "Checking sha256sum..."
    echo "${checksum} ${iso_file}" | sha256sum --check
    if [ $? -gt 0 ]; then
      echo "Checksum failed. Deleting ${iso} file and exiting..."
      rm -f "${iso_file}"
      exit 10
    fi
  else
    echo "${iso_file} already exists. Skipping download."
  fi

  echo "Creating GRUB entry..."
  cat <<EOF > ${grub_file}
#!/bin/sh
exec tail -n +3 \$0
menuentry '${grub_name}' {
EOF

  # extra systemrescue lines
  if [ "${iso}" = "sysresccd" ]; then
    echo '  probe -u $root --set=rootuuid' >> ${grub_file}
    echo '  set imgdevpath="/dev/disk/by-uuid/$rootuuid"' >> ${grub_file}
  fi

  # isofile and loopback lines
  grub_isofile="$(grub-mkrelpath "${iso_file}")"
  echo "  set isofile='${grub_isofile}'" >> ${grub_file}
  echo '  loopback loop "$isofile"' >> ${grub_file}

  # linux line
  # Get keyboard layout (default to "us" if not set)
  kmap=$(awk -F '=' '$1 == "XKBLAYOUT" { gsub(/"/, "", $2); print $2 }' /etc/default/keyboard)
  kmap=${kmap:-us}

  # Get system locale (default to "en_US.UTF-8" if not set)
  loc=$(locale | awk -F= '$1 == "LANG" { print $2 }')
  loc=${loc:-en_US.UTF-8}

  case "${iso}" in
    clonezilla)
      linux="linux (loop)/live/vmlinuz boot=live live-config noswap edd=on nomodeset ocs_prerun=\"dhclient\" ocs_live_run=\"ocs-live-general\" ocs_live_extra_param=\"\" keyboard-layouts=${kmap} ocs_live_batch=\"no\" locales=\"${loc}\" ocs_daemonon=\"ssh\" gfxpayload=text nosplash toram=filesystem.squashfs findiso=\"\$isofile\""
      ;;
    finnix)
      linux="linux (loop)/live/vmlinuz linux boot=live toram sshd passwd=openmediavault locales=${loc} keyboard-layouts=${kmap} findiso=\"\$isofile\""
      ;;
    gpartedlive)
      linux="linux (loop)/live/vmlinuz boot=\"live\" union=\"overlay\" username=\"user\" config components noswap noeject toram=\"filesystem.squashfs\" ip=\"\" nosplash keyboard-layouts=${kmap} locales=${loc} findiso=\"\$isofile\""
      ;;
    sysresccd)
      linux="linux (loop)/sysresccd/boot/x86_64/vmlinuz rootpass=openmediavault nofirewall archisobasedir=sysresccd copytoram dovnc vncpass=openmediavault setkmap=${kmap} lang=${loc} img_dev=\"\$imgdevpath\" img_loop=\"\$isofile\" earlymodules=loop"
      ;;
  esac
  echo "  ${linux}" >> ${grub_file}

  # initrd line
  if [ "${iso}" = "sysresccd" ]; then
    initrd="initrd (loop)/sysresccd/boot/intel_ucode.img (loop)/sysresccd/boot/amd_ucode.img (loop)/sysresccd/boot/x86_64/sysresccd.img"
  else
    initrd="initrd (loop)/live/initrd.img"
  fi
  echo "  ${initrd}" >> ${grub_file}

  # closing bracket
  echo "}" >> ${grub_file}

  chmod 755 ${grub_file}
  update-grub
}

remove_iso() {
  local iso=$1
  local iso_pattern="${RM[$iso]}"
  local grub_file=${GRUB_FILES[$iso]}

  echo "Removing ${iso} ISOs..."
  find /boot -type f -name "${iso_pattern}" -ls -delete
  echo "Removing GRUB entry..."
  rm -fv ${grub_file}
  update-grub
}

# Print one tab separated line per ISO: id, name, installed (0/1) and
# current (1 when the installed ISO is the version this script installs).
status() {
  local iso installed current found
  for iso in clonezilla finnix gpartedlive sysresccd; do
    installed=0
    current=0
    found="$(find /boot -type f -name "${RM[$iso]}" 2>/dev/null | head -n 1)"
    if [ -f "${GRUB_FILES[$iso]}" ] || [ -n "${found}" ]; then
      installed=1
    fi
    if [ -f "${GRUB_FILES[$iso]}" ] && [ "$(basename "${found}")" = "${FILES[$iso]}" ]; then
      current=1
    fi
    printf '%s\t%s\t%s\t%s\n' "${iso}" "${GRUB_NAMES[$iso]}" "${installed}" "${current}"
  done
}

disablesubmenu() {
  if ! grep -q 'GRUB_DISABLE_SUBMENU' ${GRUB}; then
    echo "GRUB_DISABLE_SUBMENU=y" >> ${GRUB}
    update-grub
  fi
}

action="${1,,}"
distro="${2,,}"

case ${action} in
  disablesubmenu)
    disablesubmenu
    ;;

  install)
    mkdir -pv "${ISO_PATH}"
    install_iso "${distro}"
    ;;

  remove)
    remove_iso "${distro}"
    ;;

  status)
    status
    exit 0
    ;;
esac

echo "Done."

exit 0
