#!/bin/bash

recursiveEx="ubuntustudio-installer" # Used for debugging

_autoRemovePkgFn () {
  # shellcheck disable=SC2124
  _meta=$@
  _pkg=$(apt-cache depends "${_meta}" | grep ":" | cut -d ":" -f 2 | cut -c 2-)
  # shellcheck disable=SC2206
  _pkgArry=(${_pkg})
  # shellcheck disable=SC2068
  for i in ${!_pkgArry[@]}; do
    if [ "${_pkgArry[i]}" = "386" ]; then
      unset '_pkgArry[i]'
    fi
  done
  # shellcheck disable=SC2068
  for _mark in ${_pkgArry[@]}; do
    apt-mark auto "${_mark}" || true
  done

  apt-get autoremove "${_meta}" -y
}

rmPPAFn () {
  ppaToRm=$2
  ppaRepFile=$3
  ppa-purge "${ppaToRm}"
  if [ -e "${ppaRepFile}" ]; then
    rm "${ppaRepFile}"
  fi
}

# shellcheck disable=SC2124
args=$@
if [ "${args}" != "" ]; then
  if [ "$1" = "ppapurge" ]; then
    rmPPAFn ${args}
    exit 0
  else
  # shellcheck disable=SC2206
   argArry=($args)
   for i in "${!argArry[@]}"; do
     _autoRemovePkgFn "${argArry[i]}";
   done
  fi
fi

# Before we begin, let's make sure the cache is updated
qapt-batch --update

while true; do

(
  echo 10; sleep 1
  echo 20; sleep 1
  echo 30; sleep 1
  echo 40; sleep 1
  echo 50; sleep 1
  echo 60; sleep 1
  echo 70; sleep 1
  echo 80; sleep 1
  echo 90; sleep 1
  echo 100; sleep 1
) | zenity --progress \
  --title="Please Wait" \
  --width=600 \
  --text="Building Package Table..." \
  --percentage=0 \
  --auto-close \
  --no-cancel &

# List or packages to potentially install
declare -a pkgListArry=(
[0]="linux-lowlatency"
[1]="ubuntustudio-lowlatency-settings"
[2]="ubuntustudio-performance-tweaks"
[3]="ubuntustudio-pipewire-config"
[4]="ubuntustudio-audio"
[5]="ubuntustudio-graphics"
[6]="ubuntustudio-photography"
[7]="ubuntustudio-publishing"
[8]="ubuntustudio-video"
[9]="ubuntustudio-wallpapers"
[10]="ubuntustudio-menu"
[11]="ubuntustudio-pulseaudio-config"
)

pkgTable=()
# shellcheck disable=SC2068
for pkg in ${pkgListArry[@]}; do
  if dpkg -s "${pkg}" &> /dev/null; then
    pkgInst="TRUE"
  else
    pkgInst="FALSE"
  fi
  pkgTable+=("${pkgInst}")
  pkgTable+=("${pkg}")
  if [ "${pkg}" = "linux-lowlatency" ]; then
    pkgDesc="Low-Latency Ubuntu Linux Kernel"
  else
    pkgDesc=$(apt-cache search "${pkg}" | head -n 1 | sed -e "s/${pkg} - //g")
  fi
  pkgTable+=("${pkgDesc}")
done

codename=$(lsb_release -c | cut -d ':' -f 2 | sed -e 's/       //g' | sed -e 's/\t//g')

# PPA Special Handlers - Repeats per PPA
# Format: "/path/to/repository/file/on/system"
#         "PPA-{handler-name}" <- MUST BE PREFIXED WITH PPA
#         "{Handler Description}"

declare -a PPAHndlArry=(
[0]="/etc/apt/sources.list.d/ubuntustudio-ppa-ubuntu-backports-${codename}.list"
[1]="PPA-ubuntustudio-backports"
[2]="Fast updates of Ubuntu Studio's included software"
)

if [ "${XDG_CURRENT_DESKTOP}" = "KDE" ]; then
  PPaHndlArry+=(
[3]="/etc/apt/sources.list.d/kubuntu-ppa-ubuntu-backports-${codename}.list"
[4]="PPA-kubuntu-backports"
[5]="Updated versions of KDE Plasma and other KDE software"
)
fi

# PPA Repository Definitions - Repeats per PPA
# Format: "PPA-{handler-name}" <- MUST MATCH ABOVE HANDLER NAME
#         "ppa:{launchpad-user-or-team-name}/{ppa-name}"

ppaExAr=(
[0]="PPA-ubuntustudio-backports"
[1]="ppa:ubuntustudio-ppa/backports"
[2]="PPA-kubuntu-backports"
[3]="ppa:kubuntu-ppa/backports"
)

i=0
while [ $i -lt ${#PPAHndlArry[@]} ]; do
  if [ -e "${PPAHndlArry[i]}" ]; then
    pkgTable+=("TRUE")
  else
    pkgTable+=("FALSE")
  fi
  ((i++))
  if [ -n "${PPAHndlArry[i]}" ]; then
    pkgTable+=("${PPAHndlArry[i]}")
  fi
  ((i++))
  if [ -n "${PPAHndlArry[i]}" ]; then
    pkgTable+=("${PPAHndlArry[i]}")
  fi
  ((i++))
done

textMsg="Select or deselect package(s) to modify installation status.\n\
NOTE: Instlling ubuntustudio-pulseaudio-config will remove the\n\
pipewire configuration"

selectedPkg=$(zenity \
  --title="Ubuntu Studio Installer" \
  --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
  --width=800 \
  --height=600 \
  --list \
  --multiple \
  --checklist \
  --separator=" " \
  --text="${textMsg}" \
  --ok-label="Modify Installed Package Selection" \
  --cancel-label="Close" \
  --column "Installed" \
  --column "Metapackage" \
  --column "Description" \
  "${pkgTable[@]}");
selExit=$? 

if [ -z "${selectedPkg}" ]; then
 if [ "${selExit}" = "1" ]; then exit 0; fi
fi

# shellcheck disable=SC2206
selectedArry=($selectedPkg)

# Get all PPA names
ppaArry=()
# shellcheck disable=SC2068
for ppa in ${ppaExAr[@]}; do
  maybeppa=$(echo "${ppa}" | cut -d '-' -f 1)
  if [ "${maybeppa}" = "PPA" ]; then
    ppaArry+=("${ppa}")
  fi
done

# Index only the PPAs in selectedArry
selPPAArry=()
# shellcheck disable=SC2068
for pkg in ${selectedArry[@]}; do
  maybeppa=$(echo "${pkg}" | cut -d '-' -f 1)
  if [ "${maybeppa}"  = "PPA" ]; then
    selPPAArry+=("${pkg}")
  fi
done

# Index only the PPAs that aren't installed
instPPAArry=()
  i=0
  while [ $i -lt ${#PPAHndlArry[@]} ]; do
    ((i++))
    maybeppa=$(echo "${PPAHndlArry[i]}" | cut -d '-' -f 1)
    if [ "${maybeppa}" = "PPA" ]; then
      b=$((i-1))
      # shellcheck disable=SC2068
      if ! [ -e "${PPAHndlArry[b]}" ]; then
        for ppa in ${selPPAArry[@]}; do
          if [ "${ppa}" = "${PPAHndlArry[i]}" ]; then        
          # shellcheck disable=SC2206
            instPPAArry+=($ppa)
          fi
        done
      fi
    fi
  done

# Index the PPAs that were previously installed but unselected
# shellcheck disable=SC2206
unselPPAArry=(${ppaArry[@]})
# shellcheck disable=SC2068
for sel in ${selPPAArry[@]}; do
  for i in "${!unselPPAArry[@]}"; do
    # shellcheck disable=SC2053
    if [[ ${unselPPAArry[i]} = $sel ]]; then
      unset 'unselPPAArry[i]'
    fi
  done
done

# Determine PPAs to remove if any
rmPPAArry=()
# shellcheck disable=SC2068
i=0
while [ $i -lt ${#PPAHndlArry[@]} ]; do
((i++))
  # shellcheck disable=SC2086
  maybeppa=$(echo ${PPAHndlArry[i]} | cut -d '-' -f 1)
  if [ "${maybeppa}" = "PPA" ]; then
    b=$((i-1))
    if [ -e "${PPAHndlArry[b]}" ]; then
      # shellcheck disable=SC2068
      for ppa in ${unselPPAArry[@]}; do
        if [ "${ppa}" = "${PPAHndlArry[i]}" ]; then 
          # shellcheck disable=SC2206
          rmPPAArry+=($ppa)
        fi
      done
    fi
  fi
done


ppaInstFn () {
# shellcheck disable=SC2068
  for sel in ${selPPAArry[@]}; do
    i=0
    while [ $i -lt ${#ppaExAr[@]} ]; do
      if [ "${sel}" = "${ppaExAr[i]}" ]; then
        c=$((i+1))
        pkexec add-apt-repository -y "${ppaExAr[c]}"
        ((i++))
      fi
    ((i++))
    done
  done
}

ppaRmFn () {
  i=0
  while [ $i -lt ${#PPAHndlArry[@]} ]; do
    ((i++))
    maybeppa=$(echo "${PPAHndlArry[i]}" | cut -d '-' -f 1)
    if [ "${maybeppa}" = "PPA" ]; then
      b=$((i-1))
      # shellcheck disable=SC2068
      for uns in ${unselPPAArry[@]}; do
        if [ -e "${PPAHndlArry[b]}" ]; then
          j=0
          while [ $j -lt ${#ppaExAr[@]} ]; do
            isppa=$(echo "${ppaExAr[j]}" | cut -d '-' -f 1)
            if [ "${isppa}" = "PPA" ]; then
              if [ "${uns}" = "${ppaExAr[j]}" ]; then
                p=$((j+1))
                pkexec "${recursiveEx}" ppapurge "${ppaExAr[p]}" "${PPAHndlArry[b]}" | \
                  zenity --progress --auto-close --no-cancel --pulsate;
              fi
            fi
            ((j++))
          done
        fi
      done
    fi
  done
}

ppaInstConfFn () {
  ppaStrArry=()
  # shellcheck disable=SC2068
  for ppa in ${instPPAArry[@]}; do
    ppaname=$(echo "${ppa}" | cut -c 5-)
    ppaStrArry+=("${ppaname}")
  done
  ppaWarnStr=$(cat <<EOF
The following Personal Package Archive(s) (PPA) will be added to your system:

${ppaStrArry[@]}

PPAs are considered external repositories to the Ubuntu system and packages
inside may not receive the same level of support, quality, or security.
Support, security, and quality of packages in PPAs are the responsibility
of the PPA owners.

If you trust the owners of this/these PPA(s), feel free to continue.
EOF
)
  zenity \
  --title "Ubuntu Studio Installer" \
  --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
  --width "600" \
  --height "400" \
  --question \
  --text "${ppaWarnStr}" \
  --ok-label "Continue" \
  --cancel-label "Skip/Go Back"
}

ppaRmConfFn () {
  ppaStrArry=()
  # shellcheck disable=SC2068
  for ppa in ${rmPPAArry[@]}; do
    ppaname=$(echo "${ppa}" | cut -c 5-)
    ppaStrArry+=("${ppaname}")
  done
  ppaRmWarnStr=$(cat <<EOF
The following Personal Package Archive(s) (PPA) will be be purged from your system:

${ppaStrArry[@]}

Some packages may be downgraded while others may be removed in order to satisfy
the dependencies of the system prior to the addition of the PPA(s). This will
return your system to a state closer to the Ubuntu repositories without
additions.

You will be asked for your password more than once, and this process could take several minutes.

Do you wish to continue?
EOF
)
  zenity \
  --title "Ubuntu Studio Installer" \
  --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
  --width "600" \
  --height "400" \
  --question \
  --text "${ppaRmWarnStr}" \
  --ok-label "Continue" \
  --cancel-label "Skip/Go Back"
}


# Act on PPA handlers
if ! [ -z "${instPPAArry[0]}" ]; then
  if ppaInstConfFn; then
    ppaInstFn
  fi
fi

# If previously selected PPA was unselected, purge it and remove its .list file
if ! [ -z "${rmPPAArry[0]}" ]; then
  if ppaRmConfFn; then
    ppaRmFn
  fi
fi

# Remove PPAs from Selected Array
# shellcheck disable=SC2206
selArry=(${selectedArry[@]})
# shellcheck disable=SC2068
for sel in ${selArry[@]}; do
  maybeppa=$(echo ${sel} | cut -d '-' -f 1)
  if [ "${maybeppa}" = "PPA" ]; then
    for i in "${!selectedArry[@]}"; do
      # shellcheck disable=SC2053
      if [[ ${selectedArry[i]} = $sel ]]; then
        unset 'selectedArry[i]'
      fi
    done
  fi
done

selPkgNotinst=()
# shellcheck disable=SC2068
for pkg in ${selectedArry[@]}; do
  if dpkg -s "${pkg}" &> /dev/null; then
    true
  else
    selPkgNotinst+=("${pkg}")
  fi
done

instSelPkgFn () {
  if [ -x /usr/bin/qapt-batch ]; then
    qapt-batch --install --qwindowtitle "Ubuntu Studio Installer" "${selPkgNotinst[@]}"
    # shellcheck disable=SC2068
    for pkg in ${selPkgNotinst[@]}; do
      if [ "${pkg}" = "ubuntustudio-audio" ]; then
        pkexec /usr/sbin/ubuntustudio-installer-fix
          zenity \
            --title "Ubuntu Studio Installer" \
            --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
            --width "200" \
            --warning \
            --text "Please log-out and log-in for proper audio configuration to take effect."
      fi
    done
  fi
}

instSelPkgConfFn () {
    # shellcheck disable=SC2128
    warnStr=$(cat <<EOF
The following packages will be installed by this action:

${selPkgNotinst[@]}

You may be asked for your password more than once.
Do you wish to continue?
EOF
)
  zenity \
  --title "Ubuntu Studio Installer" \
  --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
  --width "600" \
  --height "400" \
  --question \
  --text "${warnStr}" \
  --ok-label "Continue" \
  --cancel-label "Skip/Go Back"
}

if [ -n "${selPkgNotinst[0]}" ]; then
  if instSelPkgConfFn; then
    instSelPkgFn
  fi
fi

# shellcheck disable=SC2206
unselArry=(${pkgListArry[@]})
# shellcheck disable=SC2068
for sel in ${selectedArry[@]}; do
  for i in "${!unselArry[@]}"; do
    # shellcheck disable=SC2053
    if [[ ${unselArry[i]} = $sel ]]; then
      unset 'unselArry[i]'
    fi
  done
done

unSelPkginst=()
# shellcheck disable=SC2068
for pkg in ${unselArry[@]}; do
  if dpkg -s "${pkg}" &> /dev/null; then
    unSelPkginst+=("${pkg}")
  fi
done

removeConfirmFn () {
  warnStr=$(cat <<EOF
The following packages may be removed by this action:

${uninstDepRecInl[@]}

If you do not wish to have any one of these individual packages removed,
simply reinstall them. No settings are being removed by uninstallation.
Additionally, some of these packages may be required by other packages and
may not be uninstalled, so parts of this list may not apply to you.
EOF
)
  zenity \
  --title "Ubuntu Studio Installer" \
  --window-icon=/usr/share/icons/hicolor/scalable/apps/ubuntustudio-installer.svg \
  --width "600" \
  --height "400" \
  --question \
  --text "${warnStr}" \
  --ok-label "Continue" \
  --cancel-label "Skip/Go Back"
}


if [ -n "${unSelPkginst[0]}" ]; then
  _uninstDepRec=$(apt-cache depends "${unSelPkginst[0]}" | grep ":" | cut -d ":" -f 2 | cut -c 2-)
  # shellcheck disable=SC2206
  uninstDepRecArry=(${_uninstDepRec})
  for i in "${!uninstDepRecArry[@]}"; do
    if [ "${uninstDepRecArry[i]}" = "386" ]; then
      unset 'uninstDepRecArry[i]'
    fi
  done
  # shellcheck disable=SC2068
  uninstDepRecInl=$(echo ${uninstDepRecArry[@]} | fmt -w 80)
  if removeConfirmFn; then
    # shellcheck disable=SC2068
    pkexec "${recursiveEx}" ${unSelPkginst[@]} | \
      zenity --progress --auto-close --no-cancel --pulsate
  fi
fi

done
