#! /bin/bash
#--------------------------------------------------------------------------------------------------------
# Name: Linux Lite - Lite Software
# Architecture: all
# Authors: Misko_2083, Jerry Bezencon, gerito1, Johnathan "ShaggyTwoDope" Jenkins, Ralphy
# Website: https://www.linuxliteos.com
#--------------------------------------------------------------------------------------------------------

# Ensure multi-language support
export LANG=C
# variables
_ICON="/usr/share/icons/zenity-llcc.png"                   # dialog icon 24x24 PNG
_APPNAME="Lite Software"                                 # Application name
_APPINST="/usr/share/liteappsicons/litesoftware/ll-install-software_32x32.png"
_APPREM="/usr/share/liteappsicons/litesoftware/ll-remove-software_32x32.png"
# ask for administrative credentials
if [ "$EUID" -ne "0" ]; then pkexec "$0"; exit 0 ; if [ "${PIPESTATUS[@]}" -eq "126" ]; then exit 0 ; fi; else :; fi

# Kill off any package managers that may be running
if [ "$(pidof synaptic)" ]; then killall -9 synaptic; fi
if [ ! -z "$(pgrep gdebi-gtk)" ]; then killall -9 gdebi-gtk; fi
# Set up log facilities
# Example output: [02/06/15 20:03:12] message input
LOGFILE="/var/log/lite-software.log"
lslog() {
    message="$@"
    echo '['$(date +%D\ %H:%M:%S)']'"$message" >> "$LOGFILE"
}
# Log last activities to retrieve errors
TMP_LOG="/tmp/lite-software.log"

prepare() {
  # Check internet access
  if eval "curl -sk google.com" >> /dev/null 2>&1; then :; else # Prompt ERROR internet connection
    zenity --info --width="390" --ok-label="Got it!" --title=" $_APPNAME - No Internet access" \
            --text="\n<b>Your computer does not seem to be connected to the Internet</b> \n \nYou need to be connected to the Internet to download and install applications." 2>/dev/null
    return
  fi
  # Check if apt-cache was built and ask to update
  if zenity --question --width="360" --height="120" --window-icon="$_ICON" --title=" Update Software Sources" \
            --text="\n<b>Would you like to update software sources now?</b>\n\nIt is recommended to always update software sources before installing applications. \
\n\nClick <b>No</b> to continue without updating or <b>Yes</b> to update software sources next." 2>/dev/null; then
      TOTALREPOS=$(cat /etc/apt/sources.list | grep '^deb' -c) # Total of repositories registered, this is approximated
      apt-get update 2>&1 | awk -v total=$TOTALREPOS '/^Ign|^ Get/{count++;$1=""} FNR { if (total != 0){percentage=int (1000*count/total);print (percentage < 90?percentage:99),"\n#",$0 }; fflush(stdout)}' \
      | zenity --progress --width="600" --pulsate --no-cancel --text="Updating package lists..." --title="Updating Software Sources. Please wait..." --percentage="0" --auto-close 2>/dev/null
      if [ "${PIPESTATUS[0]}" -ne "0" ]; then
        zenity --error --width="300" --height="90" --title="  $_APPNAME - Error" \
               --text="\n<b>Updating sources has failed</b>\n\nRefer to /var/log/lite-software.log for more information." 2>/dev/null
        lslog "ERROR: Updating sources has failed."
      fi
        lslog "INFO: Software sources were updated."
      else
        lslog "INFO: The updating of packages was canceled by the user"
  fi
}
# Set app icon variable
APPICON="/usr/share/liteappsicons/litesoftware/appicons/"

#--------------------------------------------------------------------------------------------------------
# soft_list is the list of package aliases to check/install/remove
# Consist in a list describing aspect for every package
# package_alias=( "element 0" "element 1" "element 2" "element 3" "element 4" "element 5" "element 6")
# element 0: TRUE\FALSE for being selected
# element 1: The Application name ie: Google Chrome, iDevices Manager
# element 2: The category which belongs to (one only) ie:  Internet, Multimedia
# element 3: Status of the package ie: Installed, Not Installed
# element 4: Description of the package ie: "Easily locate files and folders in your computer", "Clementine is a modern music player and library organizer"
# element 5: List of packages needed to provide the application ie: "aisleriot gnome-mahjongg gnome-mines gnome-hearts"
# element 6: List of additional packages (this is optional) ie: libavformat-extra-54
#--------------------------------------------------------------------------------------------------------
soft_list=(audacity
  calibre
  cherrytree
  chromiumbr
  dropbox
  filezilla
  gamespack
  idevices
  imessenger
  kodi
  clementine
  passmgr
  pinta
  playonlinux
  remote
  extras
  shotwell
  skype
  spotify
  steam
  teamviewer
  torrent
  tor
  videoedit
  vbox
  weather
  guvcview
  wine )

# Check system arch, don't list 64bit only apps in i686 system eg. skypeforlinux is only available in 64bit
# The unset soft_list number corresponds to the item above the application you DON'Twant to list in 32bit systems
# eg. skypeforlinux is actually number 18 in the list, so its unset soft_list number becomes 17
UNAME=$(uname -m)
if [ "i686" == ${UNAME} ]; then
    unset soft_list[17]
    unset soft_list[18]
#    unset soft_list[5] # list another application here, and so on
else
    :
fi

audacity=("$APPICON/audacity.png" "Audacity" "Multimedia" "" "Software for recording and editing sounds" "audacity" "" )
calibre=("$APPICON/calibre.png" "Calibre" "Office" "" "A free and open source e-book library management application" "calibre" "" )
cherrytree=("$APPICON/cherrytree.png" "Cherrytree" "Accessories" "" "A hierarchical note taking application" "cherrytree" "" )
chromiumbr=("$APPICON/chromium.png" "Chromium Web Browser" "Internet" "" "Open-source alternative to the Google Chrome web browser" "chromium-browser" "" )
dropbox=("$APPICON/dropbox.png" "Dropbox" "Internet" "" "A popular cloud storage application" "dropbox thunar-dropbox-plugin" "" )
filezilla=("$APPICON/filezilla.png" "Filezilla" "Internet" "" "A robust and full-featured FTP/FTPS/SFTP client application" "filezilla" "" )
gamespack=("$APPICON/gamespack.png" "Games Pack" "Games" "" "Provides - Solitaire, Mahjongg, Mines and Hearts games" "aisleriot gnome-mahjongg gnome-mines gnome-hearts" "" )
idevices=("$APPICON/gtkpod.png" "iDevices Manager" "Multimedia" "" "Manage your iDevices with Gtkpod" "gtkpod" "" )
imessenger=("$APPICON/pidgin.png" "Instant Messenger" "Internet" "" "Pidgin, a multi-protocol Instant Messenging client" "pidgin" "" )
kodi=("$APPICON/kodi.png" "Kodi" "Multimedia" "" "The Kodi Media Center (formerly known as XBMC)" "kodi" "" )
clementine=("$APPICON/clementine.png" "Music Player" "Multimedia" "" "Clementine is a modern music player and library organizer" "clementine" "")
passmgr=("$APPICON/keepassx.png" "Password Manager" "Accessories" "" "KeePassX, a full featured password manager" "keepassx" "" )
pinta=("$APPICON/pinta.png" "Pinta" "Graphics" "" "An easy to use drawing program similar to Paint.Net" "pinta" "" )
playonlinux=("$APPICON/playonlinux.png" "PlayOnLinux" "Cross Platform" "" "Use numerous games and apps designed to run with Windows" "playonlinux" "" )
remote=("$APPICON/remmina.png" "Remote Desktop Software" "Internet" "" "Remmina Remote Desktop Client for Windows (RDP) and VNC Servers" "remmina" "" )
extras=("$APPICON/extras.png" "Restricted Extras" "Multimedia" "" "Additional codecs and useful file formats (highly recommended)" "ubuntu-restricted-extras" "libavcodec-extra" )
shotwell=("$APPICON/shotwell.png" "Shotwell" "Image Organizer" "" "An image organizer designed to provide personal photo management" "shotwell shotwell-common" "" )
skype=("$APPICON/skype.png" "Skype" "Internet" "" "A popular audio and video chat application" "skypeforlinux" "" )
spotify=("$APPICON/spotify.png" "Spotify" "Multimedia" "" "A digital music service" "spotify-client" "" )
steam=("$APPICON/steam.png" "Steam" "Games" "" "A cross platform gaming client" "steam-launcher" "" )
teamviewer=("$APPICON/teamviewer.png" "Teamviewer" "Internet" "" "Remote Desktop Support software" "teamviewer:i386" "" )
torrent=("$APPICON/deluge.png" "Torrent Software" "Internet" "" "Deluge Torrent client software" "deluge deluge-common" "" )
tor=("$APPICON/tor.png" "Tor Web Browser" "Internet" "" "A privacy respecting web browser" "tor-web-browser" "" )
videoedit=("$APPICON/openshot.png" "Video Editing Software" "Multimedia" "" "Openshot, a simple to use yet powerful video editor for linux" "openshot blender imagemagick" "")
vbox=("$APPICON/virtualbox.png" "VirtualBox" "System" "" "Install other operating systems like Windows from within Linux Lite" "virtualbox" "" )
weather=("$APPICON/weather.png" "Weather Monitor" "System Tray" "" "A Weather Monitor Plugin for your tray" "xfce4-weather-plugin" "" )
guvcview=("$APPICON/guvcview.png" "Webcam Software" "Internet" "" "Guvcview, webcam software for your computer" "guvcview" "" )
wine=("$APPICON/wine.png" "Wine" "Cross Platform" "" "Install and run some Windows programs and games on Linux Lite" "wine1.8" "")

get_pkg_status() {
  result="Installed"
  for PKG in  $@
  do
    TEST_PKG=(`apt-cache policy "$PKG" | grep "Installed:"`)
    if [ "${TEST_PKG[1]}" == "(none)" ];then
      result="Not Installed"
      break
    fi
  done
  read ${2} <<< ${result}
  unset result
  unset TEST_PKG
}

# Check for installed packages
check_installed() {
  for element in ${soft_list[*]}
  do
    current_pkg="$element[5]"
    status="$element[3]"
    get_pkg_status "${!current_pkg}" status # Get the status of the main package
    read ${element}"[3]" <<< ${status}      # Write the status in the package status
  done
}

install_pkgs() {
  declare -a pkg_arr=("${!1}")

  lslog "INFO: Installation of packages initiated: ${pkg_arr[@]}"
  apt-get install -f --show-progress ${pkg_arr[@]} -y 2>&1 | tee "$TMP_LOG" | awk ' BEGIN { FS=" "; total=1;end_download=0} /upgraded/ {total= $1 + $3;FS="[ :]" } /^Get:[[:digit:]]+/ {printf "#Downloading %s %s %s\n",$7,$(NF-1),$NF;print int(($2 - 1) * 100 / total); fflush(stdout)} /^\(Reading / {if (end_download==0){print 100;fflush(stdout);end_download=1}} /^(Preparing|Unpacking|Selecting|Processing|Setting|Download)/ {print "#", $0; fflush(stdout)}  /^Progress/ {print  match($0, /([0-9]+)/, arr); if(arr[1] != "") print arr[1] ; fflush(stdout)}' \
   | ( zenity --window-icon="$_ICON" --progress --no-cancel --width="600" --text="Downloading package(s)...\nThis may take a while." --title="$_APPNAME - Downloading. Please wait..." --percentage="0" --auto-close 2>/dev/null ; zenity --progress --no-cancel --window-icon="$_ICON" --width="600" --text="Installing and configuring packages...\nThis may take a while." --title="$_APPNAME - Installing. Please wait..." --auto-close 2>/dev/null)
  if [ "${PIPESTATUS[0]}" -ne "0" ]; then
    err_msg=$(awk '/^E:/{$1=""; print $0}' "$TMP_LOG" | tail -n 1)
    lslog "ERROR:$err_msg"
    zenity --error --width="340" --height="80" --title="  $_APPNAME - Error" --text="\n$_APPNAME Error:\n\n-$err_msg \n\n- Make sure your computer is connected to the Internet and try again." 2>/dev/null
    return
  else
    zenity --info --width="240" --height="80" --title="   $_APPNAME - Installation" --text="\nInstallation successfully completed." 2>/dev/null
    lslog "INFO: Installation was a success."
  fi
}

remove_pkgs() {
  declare -a pkg_arr=("${!1}")

  lslog "INFO: Removal of packages initiated: ${pkg_arr[@]}"
  apt-get remove -f ${pkg_arr[@]} -y 2>&1 | tee "$TMP_LOG" | awk ' BEGIN { FS=" "; total=0; pkg=0}  /upgraded/ {total=$6 } /^Removing/ {print "#", $0;pkg+=1;print int((pkg - 1) * 100 / total); fflush(stdout)}' \
    | zenity --progress --window-icon="$_ICON" --no-cancel --width="600" --text="Removing package(s)...\nThis may take a while." --title="$_APPNAME - Removing. Please wait..." --percentage="0" --auto-close 2>/dev/null
  if [ "${PIPESTATUS[0]}" -ne "0" ]; then
    err_msg=$(awk '/^E:/{$1=""; print $0}' "$TMP_LOG" | tail -n 1)
    lslog "ERROR:$err_msg"
    zenity --error --title="  $_APPNAME - Error" --text="\n$_APPNAME Error:\n\n-$err_msg" 2>/dev/null
    return
  else
    zenity --info --width="240" --height="80" --title="   $_APPNAME - Removal" --text="\nRemoval successfully completed." 2>/dev/null
    lslog "INFO: Removal was a success."
  fi
}

# The installation menu
install_menu() {
  while (true); do
  check_installed

  selection=$(for element in ${soft_list[*]}
    do
      pkg_status="$element[3]"
      #Only list Not Installed applications
      if [ "${!pkg_status}" == "Installed" ]; then
        continue;
      fi
      row="$element[@]"                          #grab the whole row
      printf  '%s\n' "${!row}"                 #print every element in the row separated with a newline
    done | zenity --window-icon="$_ICON" --list --imagelist --multiple --width="920" --height="760" --print-column="2,6,7" --separator="| " --column="Select" --column="Name" --column="Category" --column="Status" \
      --column="Description" --column="Packages" --column="Optional Packages" \
      --text='    <span font="Sans 9">Select the program or programs you want then click the <b>Install</b> button. \n\n<b> - Sort</b> columns by clicking on the column headers. \n<b> - Ctrl key:</b> Hold down <b>Ctrl</b> and click on applications <b>anywhere</b> on the list. \n<b> - Shift key:</b> Hold down <b>Shift</b> and click the <b>first</b> and then the <b>last</b> application you want from the list.\n </span>' \
      --title=" Install Software" --cancel-label="Back to Task Selector" --ok-label="Install" --hide-column="6,7" 2>/dev/null)

  # If Cancel is clicked then return to main loop
  if [ "${PIPESTATUS[0]}" -ne "0" ]; then return; fi

  # Check if anything is selected
  echo "$selection" | grep '[a-zA-Z0-9]'
  if [ "${PIPESTATUS[1]}" -ne "0" ]; then
    zenity --info  --width="280" --title="  Install Software" --text="\nNo application was selected for installation." 2>/dev/null
    continue
  fi

  # Split selection
  OIFS=$IFS
  IFS='|'
  selection_array=($selection)
  PKGS_NAMES=""
  PKGS=""
  for ((i=0; i<${#selection_array[@]}; ++i));
  do
    if (( i % 3 == 0 )); then
      PKGS_NAMES=$PKGS_NAMES${selection_array[$i]}"\n"
      continue
    fi
    PKGS=$PKGS${selection_array[$i]}" "
  done
  IFS=$OIFS

  zenity --question --width="300" --window-icon="$_ICON" --title="  $_APPNAME - Install" \
         --text="\nThe following software has been selected:<b>\n\n ${PKGS_NAMES} </b>\nDo you want to proceed with the installation?" 2>/dev/null
  if [ "$?" -eq "0" ]; then
    install_pkgs PKGS[@]; return; else continue
  fi
  done
}

# The installation menu
remove_menu() {
  while (true); do
  check_installed

  selection=$(for element in ${soft_list[*]}
    do
      pkg_status="$element[3]"
      #Only list Installed applications
      if [ "${!pkg_status}" == "Not Installed" ]; then
        continue;
      fi
      row="$element[@]"                          #grab the whole row
      printf  '%s\n' "${!row}"                 #print every element in the row separated with a newline
    done | zenity --window-icon="$_ICON" --list --imagelist --multiple --width="920" --height="760" --print-column="2,6" --separator="| " --column="Select" --column="Name" --column="Category" --column="Status" \
      --column="Description" --column="Packages" --column="Optional Packages" \
      --text='    <span font="Sans 9">Select the program or programs you want to remove, then click the <b>Remove</b> button. \n\n<b> - Sort</b> columns by clicking on the column headers. \n<b> - Ctrl key:</b> Hold down <b>Ctrl</b> and click on applications <b>anywhere</b> on the list. \n<b> - Shift key:</b> Hold down <b>Shift</b> and click the <b>first</b> and then the <b>last</b> application you want from the list.\n </span>' \
      --title="Remove Software" --cancel-label="Back to Task Selector" --ok-label="Remove" --hide-column=6,7 2>/dev/null)

  # if cancel is clicked then return to main loop
  if [ "${PIPESTATUS[0]}" -ne "0" ]; then return; fi

  # Check if anything is selected
  echo "$selection" | grep '[a-zA-Z0-9]'
  if [ "${PIPESTATUS[1]}" -ne "0" ]; then
    zenity --info --width="260" --title="  Remove Software" --text="\nNo application was selected for removal." 2>/dev/null
    continue
  fi

  # Split selection
  OIFS=$IFS
  IFS='|'
  selection_array=($selection)
  PKGS_NAMES=""
  PKGS=""
  for ((i=0; i<${#selection_array[@]}; ++i));
  do
    if (( i % 2 == 0 )); then
      PKGS_NAMES=$PKGS_NAMES${selection_array[$i]}"\n"
      continue
    fi
    PKGS=$PKGS${selection_array[$i]}" "
  done
  IFS=$OIFS
  zenity --question --width="300" --window-icon="$_ICON" --title="  $_APPNAME - Remove" \
         --text="\nThe following software has been selected:<b>\n\n ${PKGS_NAMES} </b>\n Do you want to proceed  with the removal?" 2>/dev/null
  if [ "$?" -eq "0" ]; then
    remove_pkgs PKGS[@]; return; else continue
  fi
  done
}
# We begin here
prepare
# The main loop
while (true); do
  TASK=$(zenity --list --imagelist --width="240" --height="158" --cancel-label="Quit" --window-icon="$_ICON" \
  --text='    <span font="Sans Bold 9">Please select a Task below</span>:\n' \
  --title="  $_APPNAME" --hide-header --column="Icons" --column="Task" --column="Code Task" --hide-column="3" --print-column="3" \
  "$_APPINST" "  Install Software" "1" "$_APPREM" "  Remove Software" "2" 2>/dev/null)
  if [ "${PIPESTATUS[0]}" -ne "0" ]; then
    exit 0
  elif [ -n "${TASK}" ];then
    case "$TASK" in
      "1") install_menu ;;
      "2") remove_menu ;;
    esac
  fi
done
exit 0
