#!/usr/bin/env bash
#
# The `keyboard` machine action: which layout the game's text entry uses.
#
#   azerty   a French keyboard
#   qwerty   a US keyboard
#
# The machine has no keyboard for the people singing, but it has one for
# whoever plugs one in to name a player or search a song from the couch - and a
# layout that does not match the keys somebody is looking at makes that a
# guessing game.
#
# Written as a second drop-in beside the one the installer wrote, and not by
# editing that one: the installer's carries the account the session runs as,
# and an action that rewrote it would be an action that can take the machine's
# only session away. Later drop-ins win, so this one decides the layout and
# nothing else.

set -euo pipefail

# The shared half of the actions. The runner never sees this directory: it
# executes names out of the actions directory beside it, and a library among
# them would be a name somebody could ask for.
ARCHSTAR_ACTIONS_LIB="${ARCHSTAR_ACTIONS_LIB:-/usr/lib/archstar-actions/lib/common.sh}"
# The path is a runtime one and the linter reads these on standard input, so
# it could not follow it even if it were spelled literally.
# shellcheck source=/dev/null
source "${ARCHSTAR_ACTIONS_LIB}"

LAYOUTS=('azerty' 'qwerty')

DROPIN_DIR="${ARCHSTAR_KIOSK_DROPIN_DIR:-/etc/systemd/system/archstar-kiosk@.service.d}"
DROPIN_FILE='20-keyboard.conf'

# The X keyboard layout behind one of our words. `azerty` and `qwerty` are what
# somebody looking at their keys can answer; `fr` and `us` are what the
# compositor needs, and this is the only place the two meet.
xkb_layout() {
    case "$1" in
        azerty) printf 'fr\n' ;;
        qwerty) printf 'us\n' ;;
        *) die "unknown keyboard '$1'" ;;
    esac
}

# Printed rather than written, so the suite can read what a button press would
# produce without pressing anything.
kiosk_dropin() {
    local layout="$1"
    printf '%s\n' \
        '# Written by the ArchStar keyboard action. Do not edit: the page' \
        '# rewrites this file whole every time somebody chooses a layout.' \
        '#' \
        '# A second drop-in, beside the installer own: that one carries the' \
        '# account the session runs as, and this one carries the layout. Later' \
        '# names win, so nothing here can take the session away.' \
        '[Service]' \
        "Environment=XKB_DEFAULT_LAYOUT=$(xkb_layout "${layout}")" \
        'Environment=XKB_DEFAULT_VARIANT='
}

main() {
    local layout="${1:-}"
    require_one_of "${layout}" "${LAYOUTS[@]}"

    install -d -m 0755 "${DROPIN_DIR}"
    local target="${DROPIN_DIR}/${DROPIN_FILE}" temporary
    temporary="${target}.tmp"
    kiosk_dropin "${layout}" >"${temporary}"
    chmod 0644 "${temporary}"
    mv -f "${temporary}" "${target}"
    printf 'wrote %s\n' "${target}"

    # The unit has to be read again before a restart picks the drop-in up.
    if [[ "${ARCHSTAR_ACTION_RESTART}" == '1' ]]; then
        systemctl daemon-reload 2>/dev/null \
            || printf 'systemd did not reload its units; the layout applies at the next boot\n'
    fi

    remember_setting 'keyboard' "${layout}"

    local verdict="the keyboard is ${layout}"
    if restart_the_game; then
        verdict="${verdict}; the game is restarting"
    else
        verdict="${verdict} from its next start"
    fi
    printf '%s\n' "${verdict}"
}

# Guarded so that the suite can source this file and read what a button press
# would produce without pressing anything.
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
