#!/bin/bash

###########################################################
## Copyright (c) 2024-2024 Alexey Kuryakin daqgroup@mail.ru
###########################################################

###########################################################
## dunst configuration tool.                             ##
###########################################################

###########################################################
source $(crwkit which crwlib_base.sh); # Use base library #
source $(crwkit which crwlib_file.sh); # Use file library #
###########################################################

let abort_notify_uses=0;

###############
# print version
###############
function print_version(){
 local name="$1";
 echo "$name version 1.0";
};

###################
# print help screen
###################
function print_help(){
 local name="$1";
 print_version $name;
 echo "The dunst configuration tool by DaqGroup.";
 echo "Copyright (c) 2024 Alexey Kuryakin daqgroup@mail.ru";
 echo "Help on $name:";
 echo " ====================> Syntax:";
 echo "  $name [Options] Arguments";
 echo " ====================> Options:";
 echo "   --               => options ending, next is params";
 echo "   --version        => print program version and exit";
 echo "   -h,--help        => print this help screen and exit";
 echo "   -u,--update      => update local user configuration (dunstrc):";
 echo "                       copy /etc/xdg/dunst/dunstrc to ~/.config/dunst/";
 echo "   -l,--list        => list running dunst pid(s)";
 echo "   -k,--kill        => kill running dunst pid(s)";
 echo "   -s,--single      => make dunst a single notifier: unregister all other notifiers,";
 echo "                       rename /usr/share/dbus-1/services/ *.service to *.service.off";
 echo "                       for each service Name=org.freedesktop.Notifications";
 echo " Notes:";
 echo " 1) Option -opt equivalent to --opt, so -kill is the same as --kill";
 echo " 2) Option executed in same order as it written, from left to right";
 echo " ====================> Arguments:";
 echo "   None             => must be empty";
 echo " ====================> Exit Code:";
 echo "  Return 0 on success, otherwise return error code";
 echo " ====================> Examples:";
 echo "  $name --version";
 echo "  $name --help";
 echo "  $name --list";
 echo "  $name -u -s";
 echo "  $name -kill";
};

##########################
# program data and options
##########################
readonly serviceid="org.freedesktop.Notifications";
readonly usrdunstrc="$HOME/.config/dunst/dunstrc";
readonly sysdunstrc="/etc/xdg/dunst/dunstrc";
readonly usrdunstdir="$(dirname $usrdunstrc)";
readonly sysdunstdir="$(dirname $sysdunstrc)";
readonly dbusdir="/usr/share/dbus-1/services";
declare -i argnum=0;
declare -a args=();
declare cmnd="";

##################
# Program routines
##################

##################
# which dunst file
##################
function which_dunst(){
 if which dunst; then return 0; else
  fatal 1 "Error: dunst is not found.";
 fi;
};

######################
# list dunst processes
# pid commandline
######################
function list_dunst(){
 if which_dunst > /dev/null 2>&1; then
  pgrep -xa dunst;
 fi;
};

######################
# kill dunst processes
######################
function kill_dunst(){
 if which_dunst > /dev/null 2>&1; then
  pkill -xe dunst;
 fi;
};

################
# update_dunstrc
################
function update_dunstrc(){
 if [ -e $sysdunstrc ]; then
  if mkdir -p $usrdunstdir; then
   cp -ufv --preserve=timestamps $sysdunstrc $usrdunstrc;
  else
   fatal 1 "Error: mkdir $usrdunstdir";
  fi;
 else
  fatal 1 "Error: not found $sysdunstrc.";
 fi;
};

##############
# single_dunst
##############
function single_dunst(){
 if which_dunst > /dev/null 2>&1 && [ -e $dbusdir ]; then
  for fn in $(find $dbusdir/ -name *.service); do
   if [ -e $fn ] && grep -e "$serviceid" $fn > /dev/null 2>&1; then
    local exe="$(cat $fn | grep -i -e "Exec=" | cut -d '=' -f 2 | xargs -n 1 2>/dev/null | head -n 1)";
    exe="$(basename $exe)"; if [ -z "$exe" ]; then continue; fi;
    if [ "$exe" = "dunst" ]; then continue; fi;
    pkill -xe $exe; sudo -n mv -fv $fn $fn.off;
   fi;
  done;
 fi;
};

##################################
# use expression assert_args $1 $*
# to check $* has $1 args at least
##################################
function assert_args(){
 local n=$1; shift;
 if [ $# -lt $n ]; then
  abort 1 "Error: Not enough arguments specified. See --help.\nArguments: ${args[*]}";
 fi;
};

##################
# handle arguments
##################
function handle_args(){
 if [ -n "$1" ]; then
  let argnum++;
  local arg="$1";
  args+=("$arg");
  cmnd="${args[0]}";
 fi;
};

############################
# process command/arguments,
# then clear (cmnd) & (args)
############################
function process_cmnd_args(){
 if [ -n "$cmnd" ]; then
  fatal 1 "Error: unexpected arguments.";
 fi;
 cmnd="";
 args=();
};

################
# main processor
################
function main(){
 ######################
 # command line parsing
 ######################
 if [ $# -lt 1 ]; then
  abort 2 "Error: No arguments. See --help.";
 fi;
 local opt="";
 local isopt=1;
 for i in $(seq $#); do
  local arg="$1"; shift;
  if is_option "$arg" && [ $isopt -eq 1 ] && [ -z "$opt" ]; then
   case $arg in
    --)                  isopt=0; ;; # marker of options end
    --version)           print_version $scriptname; exit 0; ;;
    -h|-help|--help)     print_help    $scriptname; exit 0; ;;
    -l|-list|--list)     list_dunst; opt=""; ;;
    -k|-kill|--kill)     kill_dunst; opt=""; ;;
    -s|-single|--single) single_dunst; opt=""; ;;
    -u|-update|--update) update_dunstrc; opt=""; ;;
    *)                   handle_args "$arg"; opt=""; ;;
   esac;
  else
   case $opt in
    '')        handle_args "$arg"; ;;
    *)         abort 1 "Error: unknown option $opt. See --help."; ;;
   esac;
   opt="";
  fi;
 done;
 ################
 # Task execution
 ################
 process_cmnd_args;
 return 0;
};

main "$@";

##############
## END OF FILE
##############
