#!/bin/sh

#this module can work for all users, so I use common directories
CACHE_DIR="/tmp/alterator-xkb"
TICKETDIR="/var/lib/alterator/tickets"


make_cache()
{
    [ -d "$CACHE_DIR/$1" ] && return

    mkdir -p "$CACHE_DIR/$1"
    cd "$CACHE_DIR/$1"; xkbdatadump "$1"; cd - >/dev/null
}

_()
{
LANG=${in_language%%;*}.utf8 gettext "alterator-xkb" "$1"
}

list_model()
{
    sed -r 's,^([^[:space:]]+)[[:space:]]+(.*),("\1" label "\2"),' "$CACHE_DIR/$1/models"
}

list_grp()
{
    sed -r 's,^([^[:space:]]+)[[:space:]]+(.*),("\1" label "\2"),' "$CACHE_DIR/$1/options"
}

list_layout()
{
    sed -nr 's,^([[:alnum:]]+)[[:space:]]+(.*),("\1" label "\2"),p' "$CACHE_DIR/$1/layouts"
}

list_variant()
{
    sed -nr "s,^$2(\\([^\\)]+\\))?[[:space:]]+(.+),(\"$2\\1\" label \"\\2\"),p" "$CACHE_DIR/$1/layouts"
}

read_current_layout()
{
    if [ -f "$CACHE_DIR/current_layout" ];then
	cat "$CACHE_DIR/current_layout"
    else
	xkbmapconf -l|tee "$CACHE_DIR/current_layout"
    fi
}

list_current_layout()
{
    read_current_layout|
    while read layout; do
	local name="$(grep -m1 "^$layout[[:space:]]" "$CACHE_DIR/$1/layouts" | cut -f2)"
	[ -n "$name" ] || name="$layout"
	printf '("%s" label "%s")' "$layout" "$name"
    done
}

write_add()
{
    grep -qs "^$1\$" "$CACHE_DIR/current_layout" ||
	echo "$1" >>"$CACHE_DIR/current_layout"
}

write_remove()
{
ed -s "$CACHE_DIR/current_layout" 2>/dev/null <<EOF
/$1/d
wq
EOF
}

write_up()
{
ed -s "$CACHE_DIR/current_layout" 2>/dev/null <<EOF
/$1/m/$1/--
wq
EOF
}

write_down()
{
ed -s "$CACHE_DIR/current_layout" 2>/dev/null <<EOF
/$1/m/$1/+
wq
EOF
}

### tickets
clear_ticket()
{
    find "$TICKETDIR"  -mindepth 1 -maxdepth 1 -type f -name 'xkb-ticket-*' -delete
}

find_ticket()
{
    find "$TICKETDIR"  -mindepth 1 -maxdepth 1 -type f -name 'xkb-ticket-*' -print -quit
}

make_ticket()
{
    [ -d "$TICKETDIR" ] || install -d -m755 "$TICKETDIR"

    name="$TICKETDIR/xkb-ticket-$(uuidgen)"
    
    cat>"$name"<<EOF
#!/bin/sh
setxkbmap -option && setxkbmap \$(cat /etc/X11/xinit/Xkbmap)
EOF
    chmod 755 "$name"
    echo "$name"
}

get_ticket()
{
    local ticket="$(find_ticket)"
    [ -n "$ticket" ] || ticket="$(make_ticket)"
    
    echo "${ticket##*/}"
}


read_firefox()
{
    local ticket="$(get_ticket)"
    
    printf 'alt-exec-description "%s"' "`_ "Apply saved keyboard settings"`"
    printf 'alt-exec-error-message "%s"' "`_ "Apply failed"`"
    printf 'alt-exec-command "%s"' "${ticket};`_ "Apply"`"
}


### main part

exit_handler()
{
    local rc=$?
    trap - EXIT

    clear_ticket
    rm -rf "$CACHE_DIR"

    exit $rc
}

trap exit_handler HUP INT QUIT TERM EXIT

#turn off auto expansion
set -f

clear_ticket
rm -rf "$CACHE_DIR"

. /usr/share/alterator/build/backend3.sh

on_message()
{
	case "$in_action" in
		list)
		    [ -n "$in_language" ] || in_language="en_US"
		    local lang="${in_language%%;*}"    
		    
		    make_cache "$lang"
		    
		    echo '('
		    case "$in__objects" in
			avail_model) list_model  "$lang" ;;
			avail_grp) list_grp  "$lang" ;;
			avail_layout) list_layout  "$lang" ;;
			avail_layout/*)
			    local layout="${in__objects%%/avail_variant}"
			    layout="${layout##*/}"
			    list_variant  "$lang" "$layout"
			;;
			current_layout) list_current_layout "$lang";;
		    esac
		    echo ')'
		    ;;
		read)
		    echo '('
		    
		    read_firefox
		    
		    printf 'model "%s"' "$(xkbmapconf -m)"
		    printf 'grp "%s"' "$(xkbmapconf -g)"
		    [ -s "$CACHE_DIR/selected_layout" ] &&
			printf 'layout "%s"' "$(cat "$CACHE_DIR/selected_layout")"
		    echo ')'
		    ;;
		write)
		    case "$in__objects" in
			avail_layout*)
			    write_add "$in_variant"
			    ;;
			*)
			    [ -n "$in_layout" ] && echo "$in_layout" >"$CACHE_DIR/selected_layout"
		    	    if [ -n "$in_remove" ];then
				write_remove "$in_layout"
			    elif [ -n "$in_up" ];then
				write_up "$in_layout"
			    elif [ -n "$in_down" ];then
				write_down "$in_layout"
			    elif [ -n "$in_submit" ];then
				xkbmapconf -s -- \
				    -model "$in_model" \
				    -option "$in_grp" \
				    -layout "$(cat "$CACHE_DIR/current_layout" | tr '\n' ','| sed s/,$//)"
				[ "$in_update" = "#t" ] &&
    				    setxkbmap -option && 
				    setxkbmap $(cat /etc/X11/xinit/Xkbmap) >/dev/null 2>/dev/null
			    fi
			    ;;
		    esac
			echo '()'
		    ;;
		*)
			echo '#f'
	esac
}

message_loop
