#!/bin/bash

Info () {
title="Info"
author="Peter Starfinger"
mail="E-Mail: info@die-starfingers.de"
year="2023"
app="$(basename $0)"
msgid="The Starbuntu application
<i>\$app</i>
was written by"
info="$(gettext "$msgid" | (export PATH `envsubst --variables "$msgid"`; envsubst "$msgid"))"

yad --center --fixed --title="$title" --window-icon="info" --image="info" --borders=20 --text="$info"$'\n'$'\n'"$author"$'\n'"$mail"$'\n'$'\n'"$year"$'\n' --text-align=center --selectable-labels --button="OK" &
wunwa "$title" > /dev/null; xdotool key Home key Down
}

search () {
local result
title=$"Search"
ask=$"&#10;Search column?&#10;"
IFS=$'\n'
space="               "
clms=(${space}1 ${space}2 ${space}3)
clm_nr=`yad --center --fixed --height=215 --title="$title" --window-icon="$HOME/.icons/taste.png" --image="dialog-question" --borders=20 --text="$ask" --text-align=center --list --no-headers --column=Columns ${clms[@]} --button=$"Cancel":1 --button="OK":0`
result=$?
clm_nr=${clm_nr// }; clm_nr=${clm_nr::1}
[ $result -eq 0 ] && echo "$clm_nr" > /tmp/hsperfdata_$USER/search-column
del yad
}

param="$1"
[ "$param" = "info" ] && Info && exit 0
[ "$param" = "search" ] && search && exit 0

leave=false
sort_bind=false
echo "1" > /tmp/hsperfdata_$USER/search-column

new_hotkey () {
    ok=false
    until $ok; do
	binding=""
	while [ -z "$binding" ]; do get_keypress; done
	for (( k=0; k<l; ++k )); do
	    hk_cb="${row[$k]%¦*}"; hk_cb="${hk_cb##*¦}"
	    if [ "$hk_cb" = "$mb" ] && [ $k -ne $nr ]; then
		if $sort_bind; then
		    name="${row[$k]#*¦}"; name="${name%%¦*}"
		else
		    name="${row[$k]%%¦*}"
		fi
		text=$"&#10;&#9;Hotkey '$binding' already used for '$name'!&#10;&#9;After 'OK' press hotkey again!&#10;"
		yad --center --title=$"Error" --window-icon="$HOME/.icons/taste.png" --image="dialog-warning" --fixed --borders=20 --text "$text" --button="OK":0
		break
	    fi
	done
	if [ $k == $l ]; then ok=true; fi
    done
}

reconstr_keys () {
    for (( k=0; k<l; ++k )); do
	line=${row[$k]}
	if $sort_bind; then
	    keys[$(( k*4 + 3 ))]="${line%%¦*}"
	    line="${line#*¦}"
	    for (( i=0; i<3; i++ )); do
		keys[$(( k*4 + i ))]="${line%%¦*}"
		line="${line#*¦}"
	    done
	else
	    keys[$(( k*4 ))]="${line%%¦*}"
	    line="${line#*¦}"
	    keys[$(( k*4 + 3 ))]="${line%%¦*}"
	    line="${line#*¦}"
	    keys[$(( k*4 + 1 ))]="${line%%¦*}"
	    line="${line#*¦}"
	    keys[$(( k*4 + 2 ))]="${line%%¦*}"
	fi
	keys[$(( k*4 ))]="#${keys[$(( k*4 ))]}"
	keys[$(( k*4 + 1 ))]="\"${keys[$(( k*4 + 1 ))]//&amp;/\&}\""
    done
}

xbk_write () {
    local ziel="$HOME/.xbindkeysrc"
    echo -n "$prefile" > "$ziel"
    for (( k=0; k<l; ++k )); do
	for (( i=0; i<4; i++ )); do
	    echo "${keys[$(( k*4 + i ))]}" | sed 's~&amp;~\&~g' >> $ziel
	done
	if [[ $k -lt $((l-1)) ]]; then echo >> "$ziel"; fi
    done
    echo "$postfile" >> "$ziel"
    killall xbindkeys
    xbindkeys &
}

get_keypress () {
    IFS=$'\n'
    killall xbindkeys
    dim=$(xdpyinfo | grep dimensions)
    h_dim=${dim%%x*}
    h_dim=${h_dim##* }
    v_dim=${dim#*x}
    v_dim=${v_dim%% *}
    xdotool mousemove $((h_dim/2)) $((v_dim/2))
    kp=($(timeout 3s xev -geometry 178x178+0+0))
    i=0; kpb=()
    for k in ${kp[@]}; do
	kk="$(echo "$k" | egrep "^    state" | grep -v "is_hint" | grep -v "Visibility")"
	if [ -n "$kk" ]; then
	    kpb[$i]="$kk"
	    ((i++))
	fi
    done
    sleep 0.3	
    l_kpb=${#kpb[@]}
    lb=$(( (l_kpb+1)/2 - 1 ))
    mb="${kpb[$lb]%, *}"
    mb="${mb% (*}"
    mb="${mb/, / + }"
    mb="${mb/    state /m:}"
    mb="${mb/keycode /c:}"
    mb="${mb/button /b:}"
    [ "${mb: -3}" = "c:8" ] && mb="${mb/c:8/c:49}"
    mod="${mb: 2}"
    mod="${mod%% *}"
    case $mod in
	0x0  ) binding="" ;;
	0x1  ) binding="Shift+" ;;
	0x4  ) binding="Control+" ;;
	0x5  ) binding="Control+Shift+" ;;
	0x8  ) binding="Alt+" ;;
	0x9  ) binding="Shift+Alt+" ;;
	0xc  ) binding="Control+Alt+" ;;
	0xd  ) binding="Control+Shift+Alt+" ;;
	0x40 ) binding="Super+" ;;
	0x41 ) binding="Shift+Super+" ;;
	0x44 ) binding="Control+Super+" ;;
	0x45 ) binding="Control+Shift+Super+" ;;
	0x48 ) binding="Super+Alt+" ;;
	0x49 ) binding="Shift+Super+Alt+" ;;
	0x4c ) binding="Control+Super+Alt+" ;;
	0x4d ) binding="Control+Shift+Super+Alt+" ;;
    esac
    k="${kpb[$lb]%, *}"
    k="${k##*, }"
    k="${k/)/}"
    if [ ${#k} = 1 ]; then k=${k,,}; fi
    binding=$binding$k
    binding="${binding/ /}"
    xbindkeys &
    unset IFS
}

save_hotkeys() {
    answer=$1
    if [ $answer -eq 0 ]; then
	cp $HOME/.xbindkeysrc $HOME/.xbindkeysrc.bak
    fi
}


body ()

{
if ! $sort_bind; then infix=$" by the labels"; else infix=""; fi
warning=$"&#10;    Please wait!&#10;&#10;    Hotkeys are being read&#10;    and sorted$infix ...&#10;"

yad --center --title="Hotkeys" --fixed --borders=20 --window-icon="$HOME/.icons/taste.png" --image="dialog-warning" --text="$warning" --no-buttons --close-on-unfocus &

IFS=$'\n'
if [[ ! -f $HOME/.xbindkeysrc ]]; then
    killall xbindkeys
    echo "### Begin of xbindkeys configuration file ###"$'\n' > $HOME/.xbindkeysrc
    echo "#Browser" >> $HOME/.xbindkeysrc
    echo "\"x-www-browser\"" >> $HOME/.xbindkeysrc
    echo "m:0xc + c:31" >> $HOME/.xbindkeysrc
    echo "Control+Alt+i"$'\n' >> $HOME/.xbindkeysrc
    echo "#Editor" >> $HOME/.xbindkeysrc
    echo "\"dbus-launch $(xdg-mime query default text/plain)\"" >> $HOME/.xbindkeysrc
    echo "m:0xc + c:26" >> $HOME/.xbindkeysrc
    echo "Control+Alt+e"$'\n' >> $HOME/.xbindkeysrc
    echo "#File Manager" >> $HOME/.xbindkeysrc
    echo "\"dbus-launch $(xdg-mime query default inode/directory) .\"" >> $HOME/.xbindkeysrc
    echo "m:0xc + c:41" >> $HOME/.xbindkeysrc
    echo "Control+Alt+d"$'\n' >> $HOME/.xbindkeysrc
    echo "#Hotkeys" >> $HOME/.xbindkeysrc
    echo "\"xbindings\"" >> $HOME/.xbindkeysrc
    echo "m:0xc + c:45" >> $HOME/.xbindkeysrc
    echo "Control+Alt+k"$'\n' >> $HOME/.xbindkeysrc
    echo "#Terminal" >> $HOME/.xbindkeysrc
    echo "\"x-terminal-emulator\"" >> $HOME/.xbindkeysrc
    echo "m:0xc + c:28" >> $HOME/.xbindkeysrc
    echo "Control+Alt+t"$'\n' >> $HOME/.xbindkeysrc
    echo "### End of xbindkeys configuration file ###" >> $HOME/.xbindkeysrc
    xbindkeys
fi
xbinding=$(cat $HOME/.xbindkeysrc)
xbind=($xbinding)
length=${#xbind[@]}
for (( k=0; k<length; k++ )); do xbind[$k]=$(echo ${xbind[$k]} | sed 's/^ *//g'); done
found_begin=false
for (( k=0; k<length; k++ )); do
    if [ "${xbind[$k]::1}" = '#' ] && [ "${xbind[$((k+1))]::1}" = '"' ] && [ "${xbind[$((k+2))]::1}" = 'm' ]; then begin=$k; found_begin=true; break; fi
done
if $found_begin; then
    prefile="${xbinding%%${xbind[$begin]}*}"
    found_end=false
    for (( k=begin; k<length; k=k+4 )); do
	if [[ "${xbind[$k]::1}" != '#' ]] || [[ "${xbind[$((k+1))]::1}" != '"' ]] || [[ "${xbind[$((k+2))]::1}" != 'm' ]]; then end=$k; found_end=true; break; fi
    done
    if $found_end; then
	postfile="${xbinding##*${xbind[((end-1))]}$'\n'}"
	keys=("${xbind[@]:$begin:$((end-begin))}")
    else
	postfile=""
	keys=("${xbind[@]:$begin}")
    fi
else
    prefile="$xbinding"$'\n\n'
    postfile=""
    keys=()
fi

compr=(); l_keys=${#keys[@]}
if $sort_bind; then
    for (( k=0; k<l_keys; ++k )); do if [ ${keys[$k]:0:1} = "#" ]; then compr[$(( k / 4 ))]="${keys[$(( k + 3 ))]##*+}""¦""${keys[$(( k + 3 ))]// /}""¦""${keys[$k]}""¦""${keys[$(( k + 1 ))]}""¦""${keys[$(( k + 2 ))]}"; fi; done
else
    for (( k=0; k<l_keys; ++k )); do if [ ${keys[$k]:0:1} = "#" ]; then compr[$(( k / 4 ))]="${keys[$k]}""¦""${keys[$(( k + 3 ))]// /}""¦""${keys[$(( k + 1 ))]}""¦""${keys[$(( k + 2 ))]}"; fi; done
fi

sorted=($(sort <<<"${compr[*]}"))
l=${#sorted[@]}

for (( k=0; k<l; ++k )); do
    if $sort_bind; then
	sorted[$k]=${sorted[$k]#*¦}
    fi
done

sortstr=""
for (( k=0; k<l; ++k )); do sortstr=$sortstr${sorted[$k]}"¦"; done
if [ -n "$sortstr" ]; then
    sortstr=${sortstr::-1}
fi
sortstr=$(echo $sortstr | sed 's/#//g; s/¦"/¦/g; s/"¦/¦/g; s/&/&amp;/g')  # Ersetzen der Spaces durch Nonbreakable Spaces, Löschen von # und von " am Anfang und Ende

IFS='¦'

dim=$(xdpyinfo | grep dimensions)
v_dim=${dim#*x}
v_dim=${v_dim%% *}
height=$(( v_dim-134 ))
clm_nr=$(cat /tmp/hsperfdata_$USER/search-column)
changed=true

text=$"Please confirm every hotkey entry with 'OK'!&#10;The hotkey may initially be left blank and typed later after request!"
action=$"Action"
ok=$"OK!!Adoption of the changes"
L_H=$"Labels ↔ Hotkeys!!Reorder"
help=$"Help"
lang_dir=$"C"
term=$"Quit!!Apply changes and quit"

while $changed || [ $button -eq 143 ]; do
  if $sort_bind; then
    keybindings=`yad --center --title="Hotkeys" --height=$height --width=570 --no-click --text="$text" --text-align=center --window-icon=$HOME/.icons/taste.png --no-escape --print-all --always-print-result --list --separator="¦" --ellipsize=end --editable --expand-column=0 --search-column=$(cat /tmp/hsperfdata_$USER/search-column) --regex-search --column=$"Hotkey" --column=§"Label" --column=$action --column=Hotcomb:HD $sortstr --button="$term":3 --button="$L_H":1 --button=$"Search":"$0 search" --button="$help":"yelp /usr/share/help/$lang_dir/Starbuntu/starbuntu-apps-details.page#xbindings" --button="Info":"$0 info" --button="$ok":0`
  else
    keybindings=`yad --center --title="Hotkeys" --height=$height --width=570 --no-click --text="$text" --text-align=center --window-icon=$HOME/.icons/taste.png --no-escape --print-all --always-print-result --list --separator="¦" --ellipsize=end --editable --expand-column=0 --search-column=$(cat /tmp/hsperfdata_$USER/search-column) --regex-search --column=$"Label" --column=$"Hotkey" --column=$action --column=Hotcomb:HD $sortstr --button="$term":3 --button="$L_H":1 --button=$"Search":"$0 search" --button="$help":"yelp /usr/share/help/$lang_dir/Starbuntu/starbuntu-apps-details.page#xbindings" --button="Info":"$0 info" --button="$ok":0`
  fi
  button=$?
  if [ $(cat /tmp/hsperfdata_$USER/search-column) -eq $clm_nr ]; then
    changed=false
  else
    clm_nr=$(cat /tmp/hsperfdata_$USER/search-column)
  fi
done

[ $button -eq 252 ] && exit 252

bindstr="$keybindings"
bindstr=$(echo "$bindstr" | tr -d '\n')
[ -n "$bindstr" ] && bindstr=${bindstr::-1}
if [ "$sortstr" = "$bindstr" ]; then return; fi

IFS=$'\n'
row=($keybindings)
l=${#row[@]}

for (( k=0; k<l; ++k )); do
    if $sort_bind; then
	pre="${sorted[$k]%%¦*}"
	post="${row[$k]%%¦*}"
	label="${row[$k]#*¦}"; aktion="${label#*¦}"; label="${label%%¦*}"
    else
	pre="${sorted[$k]#*¦}"; pre="${pre%%¦*}"
	post="${row[$k]#*¦}"; aktion="${post#*¦}"; post="${post%%¦*}"
	label="${row[$k]%%¦*}"
    fi
    aktion="${aktion%%¦*}"
    hk_cb_pre="${sorted[$k]##*¦}"
    hk_cb_post="${row[$k]%¦*}"; hk_cb_post="${hk_cb_post##*¦}"
    if [[ $k -ge 1 ]]; then hk_cb_prepost="${row[$((k-1))]%¦*}"; hk_cb_prepost="${hk_cb_prepost##*¦}"; fi
    if [ "$label" = "(null)" ] || [ -z "$label" ] || [ -z "$aktion" ]; then return 0; fi
    if [[ "$pre" != "$post" ]] && [ "$hk_cb_pre" = "$hk_cb_post" ] ||  [ "$hk_cb_prepost" = "$hk_cb_post" ] ||  [ "$hk_cb_post" = "(null)" ]; then
	nr=$k; modifs=""; testa=""; coda=""; text=""
	if [ -n "$post" ] && [[ "$post" != "(null)" ]]; then
	    if [ "${post: -2}" = "++" ]; then post="${post::-2}+plus"; fi
	    if [[ "$post" =~ "+" ]]; then modifs="${post%+*}"; fi
	    post="${post##*+}"
	    [ "$post" = "-" ] && post="minus"
	    [ "$post" = "^" ] && post="asciicircum"
	    [ "$post" = "ß" ] && post="ssharp"
	    [ "$post" = "\`" ] && post="numbersign"
	    [ "$post" = "ü" ] && post="udiaeresis"
	    [ "$post" = "ö" ] && post="odiaeresis"
	    [ "$post" = "ä" ] && post="adiaeresis"
	    [ "$post" = "#" ] && post="numbersign"
	    [ "$post" = "<" ] && post="less"
	    [ "$post" = "," ] && post="comma"
	    [ "$post" = "." ] && post="period"
	    if [ "${post::-1}" = "button" ]; then
		post="click ${post: -1} "
	    else
		post="key $post "
	    fi
	    if [ -n "$modifs" ]; then
		testa="keydown $modifs "; coda="keyup $modifs"
	    fi
	else
	    if $sort_bind; then
		label="${row[$nr]#*¦}"; label="${label%%¦*}"
	    else
		label="${row[$nr]%%¦*}"
	    fi
	    text=$"&#10;&#9;For '$label' press hotkey after 'OK'!&#10;"
	fi
	if [ -z "$text" ]; then
	    eval "xdotool sleep 3.5 $testa$post$coda &"
	    sleep 2.5
	else
	    yad --center --title="Hotkey" --window-icon="$HOME/.icons/taste.png" --image="info" --borders=20 --fixed --text="$text" --button="OK":0
	    sleep 0.3
	fi
	new_hotkey
	if $sort_bind; then
	    mid="${row[$nr]#*¦}"; mid="${mid%¦*}"; mid="${mid%¦*}"
	    row[$nr]="$binding¦$mid¦$mb¦"
	else
	    pre="${row[$nr]%%¦*}"; mid="${row[$nr]#*¦}"; mid="${mid#*¦}"; mid="${mid%%¦*}"
	    row[$nr]="$pre¦$binding¦$mid¦$mb¦"
	fi
    fi
done

reconstr_keys
sleep 1
xbk_write

text=$"&#9;Hotkey file rewritten!&#10;&#9;Backup all Hotkeys?&#10;&#10;"
button1=$"Yes"; button2=$"No"
yad --center --title="Backup" --window-icon="$HOME/.icons/taste.png" --image="info" --borders=20 --fixed --text="$text" --button="$button2":1 --button="$button1":0
save_hotkeys "$?"

}

while ! $leave; do
    body
    if [ "$button" = "1" ]; then
	if $sort_bind; then sort_bind=false; else sort_bind=true; fi
    fi
    if [ "$button" = "3" ] || [ "$button" = "252" ]; then leave=true; fi
done

unset IFS

exit 0
