#!/bin/bash

## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

#set -x
#exec >  >(tee -a "/home/user/msgprogressbarlog")
#exec 2> >(tee -a "/home/user/msgprogressbarlog" >&2)

set -e
set -o pipefail

scriptname="$(basename "$BASH_SOURCE")"

error_handler() {
   local exit_code="$?"

   local msg="\
###############################################################################
## $scriptname script bug.
## No panic. Nothing is broken. Just some rare condition has been hit.
## Try again later. There is likely a solution for this problem.
## Please see Whonix News, Whonix Blog and Whonix User Help Forum.
## Please report this bug!
##
## BASH_COMMAND: $BASH_COMMAND
## exit_code: $exit_code
###############################################################################\
"
   echo "$msg" >&2
   if [ ! -d ~/".msgcollector" ]; then
      mkdir --parents ~/".msgcollector"
   fi
   echo "$scriptname: BASH_COMMAND: $BASH_COMMAND | exit_code: $exit_code" | tee -a ~/".msgcollector/msgdispatcher-error.log" >/dev/null
   exit 1
}

trap "error_handler" ERR

parse_cmd_options() {
   trap "error_handler" ERR

   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/035

   while true; do
       case $1 in
           --verbose)
               set -x
               verbose="1"
               shift
               ;;
           --identifier)
               identifier="$2"
               shift 2
               ;;
           --progressbaridx)
               progressbaridx="$2"
               shift 2
               ;;
           --progressbartitlex)
               progressbartitlex="$2"
               shift 2
               ;;
           --animate)
               animate="1"
               shift
               ;;
           --message)
               message="$2"
               shift 2
               if [ "$message" = "" ]; then
                  echo "$BASH_SOURCE ERROR: variable message is empty."
                  exit 1
               fi
               ;;
           --)
               shift
               break
               ;;
           -*)
               echo "$scriptname unknown option: $1" >&2
               exit 1
               ;;
           *)
               break
               ;;
       esac
   done

   ## If there are input files (for example) that follow the options, they
   ## will remain in the "$@" positional parameters.
}

preparation() {
   trap "error_handler" ERR
   fifo="${msgcollector_run_dir}/${identifier}_${progressbaridx}_fifo"
   progress_txt_file="${msgcollector_run_dir}/${identifier}_${progressbaridx}_progresstxt"
   parent_pid_file="${msgcollector_run_dir}/${identifier}_${progressbaridx}_parentpid"
   zenity_progress_pid_file="${msgcollector_run_dir}/${identifier}_${progressbaridx}_zenityprogresspid"
}

cleanup_self() {
   trap "error_handler" ERR

   true "$0 $FUNCNAME: killing zenity_progress_pid $zenity_progress_pid..."
   kill -s sigterm "$zenity_progress_pid" >/dev/null 2>/dev/null || true
   safe-rm --force "$fifo"
   safe-rm --force "$progress_txt_file"
   safe-rm --force "$zenity_progress_pid_file"
   safe-rm --force "$parent_pid_file"
}

output_ex() {
   trap "error_handler" ERR

   ## This function is called when the cancel button in zenity gets pressed or
   ## when $progress_txt_file contains 100.

   ## Debugging.
   #echo "progress: $progress | caller: $PPID | $caller | killing $zenity_progress_pid" >> /home/user/progresslog

   if [ -f "$parent_pid_file" ]; then
      "/usr/libexec/msgcollector/msgprogressbar_kill_helper" "${identifier}" "${progressbaridx}"
   else
      true "$output_signal_caught caught. Not killing parentpid $parentpid, \
because $parent_pid_file does not exist."
   fi

   cleanup_self
   exit 0
}

output_sighup() {
   trap "error_handler" ERR
   output_signal_caught="SIGHUP"
   output_ex
}

trap "output_sighup" SIGHUP

output_sigterm() {
   trap "error_handler" ERR
   output_signal_caught="SIGTERM"
   output_ex
}

trap "output_sigterm" SIGTERM

start_progress_bar() {
   trap "error_handler" ERR

   if [ "$message" = "" ]; then
      message="Progress bar message is empty, please report this msgcollector bug!"
   fi

   if [ "$progressbartitlex" = "" ]; then
      progressbartitlex="Variable progressbartitlex does not exist. Please report this bug!"
   fi

   if [ -f "${msgcollector_run_dir}/${identifier}_icon" ]; then
      local icon
      icon="$(cat "${msgcollector_run_dir}/${identifier}_icon")"
   fi

   if [ "$icon" = "" ]; then
      ## TODO: write error log
      local icon="/usr/share/icons/gnome/24x24/status/info.png"
   fi

   if [ -f "${msgcollector_run_dir}/${identifier}_lefttop" ]; then
      local lefttop="1"
   fi

   if [ "$display" = "" ]; then
      display=":0"
   fi

   if [ -f "$parent_pid_file" ]; then
      true "parent_pid_file $parent_pid_file exists."
   else
      true "parent_pid_file $parent_pid_file does not exist."
   fi

   if [ -f "$progress_txt_file" ]; then
      ## Sometimes there is a race condition preventing the progressbar
      ## being closed. Let's use this alternative approach.
      progress_txt_file_progress="$(cat "$progress_txt_file")"
      if [ "$progress_txt_file_progress" = "100" ]; then
         true "Already 100%. Not even opening progress bar."
         cleanup_self
         exit 0
      fi
   fi

   ## Sanity test for $progress_txt_file_progress, because we use it without
   ## quotes as argument for zenity below.
   ## Also matches $when progress_txt_file_progress is unset.
   if [[ "$progress_txt_file_progress" != *[!0-9]* ]]; then
      true "'$progress_txt_file_progress' is strictly numeric."
   else
      error "'$progress_txt_file_progress' is NOT strictly numeric!"
      exit 1
   fi

   if [ ! "$progress_txt_file_progress" = "" ]; then
      percentage_maybe_add="--percentage $progress_txt_file_progress"
   fi

   ## Clean up eventual old progress bar.
   safe-rm --force "$fifo"

   mkfifo "$fifo"

   ## sanity test
   test -p "$fifo"

   ## Do not use < > inside zenity progress messages, zenity will mess that up.
   ## zenity --auto-kill will result in zenity sending a sighup signal upon
   ## pressing of cancel button.
   zenity \
      --display="$display" \
      --timeout "86400" \
      --no-markup \
      --window-icon "$icon" \
      --title="$progressbartitlex" \
      --auto-kill \
      --auto-close \
      --progress \
      $percentage_maybe_add \
      --text "$message" \
      < "$fifo" & zenity_progress_pid="$!"

   exec 3>"$fifo"

   echo "$zenity_progress_pid" > "$zenity_progress_pid_file"

   if [ "$lefttop" = "1" ]; then
      ## set progressbar variable to 1, so the progress bar window will not be
      ## maximized by output_wmctrl.
      progressbar="1"

      ## provided by /usr/libexec/msgcollector/msgwmctrl
      output_wmctrl_move_window_to_left_top "$progressbartitlex"
   fi

   while true; do
      if [ -f "$progress_txt_file" ]; then
         ## Sometimes there is a race condition preventing the progressbar
         ## being closed. Let's use this alternative approach.
         progress_txt_file_progress="$(cat "$progress_txt_file")"
         if [ "$progress_txt_file_progress" = "100" ]; then
            cleanup_self
            exit 0
         fi
      fi
      ## Alternatively (most cases) waiting for SIGHUP.
      ## Happens when zentiy reached 100% or when cancel button is pressed.
      ## This will call the output_sighup function.

      ## Check if still running.
      local ps__p_exit_code
      ps__p_exit_code="0"
      ps -p "$zenity_progress_pid" >/dev/null 2>/dev/null || { ps__p_exit_code="$?"; true; };
      if [ ! "$ps__p_exit_code" = "0" ]; then
         cleanup_self
         exit 0
      fi

      sleep "2" &
      wait "$!"
   done
}

source /usr/libexec/msgcollector/msgcollector_shared
## sets: ${msgcollector_run_dir}
folder_init

source /usr/libexec/msgcollector/msgwmctrl
fallbacks ## provided by /usr/libexec/msgcollector/msgwmctrl
parse_cmd_options "$@"
preparation
start_progress_bar
