#!/bin/sh

#this module can work for all users, so I use common directories
alterator_api_version=1
po_domain="alterator-xkb"
cachedir=
ticketdir="/var/lib/alterator/tickets"
x11_keyboard_conf="/etc/X11/xorg.conf.d/00-keyboard.conf"
sysconfig_keyboard="/etc/sysconfig/keyboard"
vconsole_conf="/etc/vconsole.conf"
xkb_config="/etc/X11/xinit/Xkbmap"

if [ -n "$TMPDIR" ]; then
    cachedir="$TMPDIR/alterator-xkb"
else
    cachedir="/var/cache/alterator/alterator-xkb"
fi

#turn off auto expansion
set -f

. alterator-sh-functions

dump_cache()
{
    local langlist="$(write_language "$in_language")"
    local firstlang="${langlist%%:*}"
    LC_ALL="$firstlang" LANGUAGE="$langlist" xkbdatadump
}

clear_cache()
{
    rm -rf "$cachedir"
}

init_cache()
{
    local rc=0
    local msg=
    [ -d "$cachedir/$1" ] && return 0

    mkdir -p "$cachedir/$1"

    cd "$cachedir/$1"
    msg="$(dump_cache 2>&1)"
    rc=$?
    cd - >/dev/null

    [ "$rc" -eq 0 ] ||  write_error "$msg"

    return $rc
}


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

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

list_avail_variant()
{
    grep "^$2\((\|[[:space:]]\)" "$cachedir/$1/layouts"
}


list_avail_layout()
{
    grep '^\([[:alnum:]]\+\)[[:space:]]\+' "$cachedir/$l/layouts"|
    LANG="${in_language%%:*}.UTF-8" sort -k 2,2 2>/dev/null
}

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

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

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

write_down()
{
ed -s "$cachedir/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 $xkb_config)
EOF
    chmod 755 "$name"
    echo "$name"
}

get_ticket()
{
    local ticket="$(find_ticket)"
    [ -n "$ticket" ] || ticket="$(make_ticket)"

    echo "${ticket##*/}"
}

### main part

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

    clear_ticket
    clear_cache

    exit $rc
}

trap exit_handler HUP INT QUIT TERM EXIT

clear_ticket
clear_cache

__write_enum()
{
	sed -e 's/;/,/g' | write_enum
}

save_x11_keyboard_conf() {
    # save_x11_keyboard_conf <layout> <model> <option>
    local layout=$1;shift;local model=$1;shift;local option=$1
    [ ! -e "$x11_keyboard_conf" ] || install -Dm0644 /dev/null $x11_keyboard_conf
cat > $x11_keyboard_conf << EOF
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
	Option "XkbLayout" "$layout"
	Option "XkbModel" "$model"
	Option "XkbOptions" "$option"
EndSection
EOF
}

get_value_x11_keyboard() {
    [ -f "$x11_keyboard_conf" ] || return
    grep "$1" $x11_keyboard_conf | awk -F" " '{print $3}' | tr -d '"' | sed "s/,/\n/g" 2>/dev/null
}

get_value_x11_keyboard_conf() {
    case "$1" in
        "layout") get_value_x11_keyboard "XkbLayout";;
        "model") get_value_x11_keyboard "XkbModel";;
        "grp") get_value_x11_keyboard "XkbOptions";;
    esac
}


get_layout() {
    get_value_x11_keyboard_conf "layout" || xkbmapconf -l
}

get_model() {
    get_value_x11_keyboard_conf "model" || xkbmapconf -m
}

get_group() {
    get_value_x11_keyboard_conf "grp" || xkbmapconf -g
}

on_message()
{
	case "$in_action" in
		list)
		    [ -n "$in_language" ] || in_language="en_US"
		    local l="$in_language"

		    init_cache "$l" || return

		    case "$in__objects" in
			avail_model) cat "$cachedir/$l/models"|__write_enum ;;
			avail_grp) cat "$cachedir/$l/options"|grep '^grp:'|__write_enum ;;
			avail_layout) list_avail_layout|__write_enum;;
			current_layout) list_current_layout "$l"|__write_enum;;
			avail_variant)
			    [ -n "$in_name" ] || in_name="$(list_avail_layout|head -n1|cut -f1)"
			    list_avail_variant  "$l" "$in_name"|__write_enum
			    ;;
		    esac
		    ;;
		read)
		    #firefox extension
		    local ticket="$(get_ticket)"
		    write_string_param alt_exec_description "`_ "Apply saved keyboard settings"`"
		    write_string_param alt_exec_error_message "`_ "Apply failed"`"
		    write_string_param alt_exec_command "${ticket};`_ "Apply"`"

		    local model=`get_model`
		    [ -n "$model" ] || model="pc104"

		     write_string_param model "$model"
		     write_string_param grp `get_group`
		     [ -s "$cachedir/selected_layout" ] &&
		         write_string_param layout "$(cat "$cachedir/selected_layout")"
		    ;;
		write)
		    case "$in__objects" in
			avail_layout*)
			    write_add "$in_variant"
			    ;;
			*)
			    [ -n "$in_layout" ] && echo "$in_layout" >"$cachedir/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
			         local layout=`cat "$cachedir/current_layout" | tr '\n' ','| sed s/,$//`
			         # Set X11 Layout
			         [ -n "$layout" ] || layout=`get_layout`
			         save_x11_keyboard_conf \
			             "$layout" \
			             "$in_model" \
			             "$in_grp"
			         # Set VC Keymap
			         . shell-config &&
			         shell_config_get /etc/sysconfig/keyboard "KEYTABLE"|
			         awk '{printf "KEYMAP=%s", $1}'|tee $vconsole_conf 2>/dev/null

			             [ ! -r "$xkb_config" -o ! -s "$xkb_config" ] || echo -n "" > "$xkb_config"
			    fi
			    ;;
		    esac
		    ;;
	esac
}

message_loop
