#!/bin/bash

if [ "$(id -u)" = "0"  ] ; then
	echo "You do not want this to run as root!"
	exit 1
fi

if [ -z "$XDG_RUNTIME_DIR" ] ; then
	echo "XDG_RUNTIME_DIR is not set but required!"
	if [ -d "/run/user/$(id -u)" ] ; then
		XDG_RUNTIME_DIR="/run/user/$(id -u)"
		export XDG_RUNTIME_DIR
		echo "Could recover by using $XDG_RUNTIME_DIR." >&2
	else
		exit 1
	fi
fi

# Make the script fail when a command fails
set -e

XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"

# Settings variables go here
FUCHS_KIOSK_SETTINGS_DIR="${FUCHS_KIOSK_SETTINGS_DIR:-$XDG_DATA_HOME/fuchs-kiosk}"
FUCHS_KIOSK_RUNTIME_DIR="${FUCHS_KIOSK_RUNTIME_DIR:-$XDG_RUNTIME_DIR/fuchs-kiosk}"
FUCHS_KIOSK_LOG_DIR="${FUCHS_KIOSK_LOG_DIR:-$XDG_CACHE_HOME/fuchs-kiosk/log}"

parse_step=0
COMMAND=""
SUBCOMMAND=""
ARG=""
FORCE_FLAG=""

show_help() {
cat <<EOF
Usage: fuchs-kiosk <command> [<subcommand>] [<arg>] [<option> ...]

fuchs-kiosk is a program for managing a kiosk system based on runit.
It is intended to run in a sway envoirnment with the interactive-kiosk-browser and squeekboard.

Options:
	--settings-dir
		Specify a directory where the fuchs-kiosk will write its settings to.
		Default: \$XDG_DATA_HOME/fuchs-kiosk
	--runtime-dir
		Specify a directory for storing runtime information (mainly the svdir)
		Default \$XDG_RUNTIME_DIR/fuchs-kiosk
	--log-dir <directory>
		Specify a directory to write logs to
		Default: \$XDG_CACHE_HOME/fuchs-kiosk
	-f, --force
	--help
		Displays this text

Commands:
	dashboard
		Shows a dashboard giving an overview.
	check-dependencies
		Shows an overview of needed commands that might be missing


	status [<service>]
		display the status of a given service (or all serices)
	run runsv
		Run the service manager (runit).
		Mainly used internally, see the startup command for starting.
	run <service>
		run the command behind a service directly
	start|stop|restart <service>
		start and stop a given service 
	enable|disable <service>
		enable and disable a given serive
	startup
		For starting the service inside a session

	get-sctive
		retrieve the current activity status.
	set-active active|idle|inactive|unknown
		Set a custom activity status.

	ikb reload-home
		This will reload the homepage if the terminal is currently inactive
	ikb soft-restart
		If the terminal is currently inactive restart the browser
		if it is active the browser will restart anyway once the terminal goes inactive.
	
	screen on|off
		Manually turn the screen on or off
	screen on-inactive on|off
		When set to off the screen is turned off when the terminal goes idle.
	peek
		Takes a screenshot and saves it to the log directory as last_screenshot.png
		Also attempty to show a preview using sixel.

	settings set-upstream <url>
		Set the given url as the upstream git repository containing configuration.
	settings pull
		Pull the configuration from the configured repository (using a shallow clone).
		Apply it and trigger a ikb soft-restart.
	settings set-name <name>
		Set the name of this terminal, if left empty the name will default to
		the machines hostname.
	settings save-for-rollback
		Save the current configuration as a known working in case errors occour.
	settings rollback
		Manually roll back to the last configuration that was saved as known working.
		This will be triggered by the ikb starter in case it detects that the last
		run of ikb logged an error.

Services:
	sqeekboard
		Starts squeekboard as the given keyboard after setting the layout (currently hardcoded to de)
	ikb
		Starts the interactive-kiosk-browser
		Configuration path: "<settings-dir>/config/ikb-<name>.json" or "<settings-dir>/config/ikb.json"
		Also attempts to recover from broken configurations on restart.
	swayidle
		Starts swayidle to change activity states.
		Currently the following hardcoded settings apply:
			after 1 minute: idle
			after 5 minutes: inactive
	command_runner
		Listens for commands to the session on aq fifo and
		makes the screen and peek commands work.

Envoirnment:
	For the log runtime and settings directory the following envoirnment variables can be used
	when the corresponding command line arguments are not used. (If they are used they are exported to all called programs)

	FUCHS_KIOSK_LOG_DIR
	FUCHS_KIOSK_RUNTIME_DIR
	FUCHS_KIOSK_SETTINGS_DIR
EOF
}

while [[ "$#" -gt 0 ]]; do
	case "$1" in
		--settings-dir) FUCHS_KIOSK_SETTINGS_DIR="$(realpath "$2")"; shift 2;;
		--runtime-dir) FUCHS_KIOSK_RUNTIME_DIR="$(realpath "$2")"; shift 2;;
		--log-dir) FUCHS_KIOSK_LOG_DIR="$(realpath "$2")"; shift 2;;
		-f|--force) FORCE_FLAG="y"; shift 1;;
		
		--help) show_help; exit 0;;
		-*) printf "Unknown option: %s\n" "$1"; exit 1;;
		*)
			case "$parse_step" in
				0) COMMAND="$1" ;;
				1) SUBCOMMAND="$1" ;;
				2) ARG="$1" ;;
				*) ;;
			esac
			parse_step="$((parse_step + 1))"
			shift 1
		;;
	esac
done

cd "$HOME"
SVDIR="$FUCHS_KIOSK_RUNTIME_DIR/sv"

export FUCHS_KIOSK_SETTINGS_DIR
export FUCHS_KIOSK_RUNTIME_DIR
export FUCHS_KIOSK_LOG_DIR
export SVDIR

[ -d "$FUCHS_KIOSK_SETTINGS_DIR" ] || mkdir -p "$FUCHS_KIOSK_SETTINGS_DIR"
[ -d "$FUCHS_KIOSK_RUNTIME_DIR" ] || mkdir -p "$FUCHS_KIOSK_RUNTIME_DIR"
[ -d "$FUCHS_KIOSK_LOG_DIR" ] || mkdir -p "$FUCHS_KIOSK_LOG_DIR"
[ -d "$SVDIR" ] || mkdir -p "$SVDIR"

########## Library

function check_command_v() {
	if command -v "$1" >&- 2>&- ; then
		printf "%s: \x1b[32mavailable\x1b[00m\n" "$1"
	else
		printf "%s: \x1b[01;31mmissing\x1b[00m\n" "$1"
	fi
}

function command_check_dependencies() {
	check_command_v "runsvdir"
	check_command_v "squeekboard"
	check_command_v "interactive-kiosk-browser"
	check_command_v "fuchs-kiosk-ikb-json"
	check_command_v "grim"
}

function require_command() {
	if ! command -v "$1" >&- 2>&- ; then
		printf "Required command is not available: %s\n" "$1"
		exit 3
	fi
}

# (command_to_run)
function command_run() {
	cd "$FUCHS_KIOSK_SETTINGS_DIR"
	case "$1" in
		squeekboard)
			echo "running squeekboard"
			require_command "squeekboard"
			gsettings set org.gnome.desktop.a11y.applications screen-keyboard-enabled true
			gsettings set org.gnome.desktop.input-sources sources "[('xkb','de')]"
			exec squeekboard
		;;
		ikb)
			if [ -f "$FUCHS_KIOSK_LOG_DIR/ikb_error.log" ] &&
				[ "$(date -r "$FUCHS_KIOSK_LOG_DIR/ikb_error.log" +%s)" -gt "$(date -r "$FUCHS_KIOSK_SETTINGS_DIR/config" +%s)" ] ; then
				
				if grep -q "error" "$FUCHS_KIOSK_LOG_DIR/ikb_error.log" ; then
					echo "Last restart was an error. Attempting rollback ..."
					# go on even iuf the rollback failed
					settings_rollback || true
					mv "$FUCHS_KIOSK_LOG_DIR/ikb_error.log" "$FUCHS_KIOSK_LOG_DIR/ikb_error.log.old"
				fi
			fi
			require_command "interactive-kiosk-browser"
			require_command "fuchs-kiosk-ikb-json"
			cd "$FUCHS_KIOSK_SETTINGS_DIR/config"
			config_file="ikb-$(get_option name).json"
			[ -r "$config_file" ] || config_file="ikb.json"
			if ! [ -r "$config_file" ] ; then
				echo "No configuration file for ikb present."
				return 2
			fi
			echo "Starting ikb with configuration file: $config_file"
			exec fuchs-kiosk-ikb-json "$config_file" 2> "$FUCHS_KIOSK_LOG_DIR/ikb_error.log"
		;;
		swayidle)
			[ "_$(get_active)" != "_unknown" ] || set_active active
			run_swayidle
		;;
		runsv)
			require_command "runsvdir"
			exec runsvdir "$SVDIR"
		;;
		command_runner)
			command_runner ;;
		*)
			echo "Unknown run subcommand, available commands are:"
			echo " * ikb"
			echo " * runsv"
			echo " * squeekboard"
			echo " * swayidle"
			exit 1
		;;
	esac
}

function dashboard() {
	echo "Dashboard for $(get_option name)"
	if [ -f "$FUCHS_KIOSK_RUNTIME_DIR/active_status" ] ; then
		echo "Activity: $(head -n 1 "$FUCHS_KIOSK_RUNTIME_DIR/active_status")"
	else
		echo "Activity: unknown"
	fi
	echo ""
	echo "Services"
	sv_status | sed "s/^/| /"
}

# (service?)
function sv_status() {
	if [ -n "$1" ] ; then
		check_is_valid_service_v "$1"
		sv status "$1"
	else
		has_service=""
		for service in "$SVDIR"/* ; do
			has_service=y
			sv status "$service"
		done
		if [ -z "$has_service" ] ; then
			echo "[info] No services running." >&2
		fi
	fi
}

# (service)
function sv_enable() {
	check_is_valid_service_v "$1"
	this_script="$0"
	if grep -q "^\./" <<< "$0" ; then this_script="$(realpath "$0")" ; fi
	mkdir -p "$SVDIR/$1"
	printf "#!/bin/sh\nexec %s run %s\n" "$this_script" "$1" > "$SVDIR/$1/run"
	chmod +x "$SVDIR/$1/run"
	case "$1" in
		swayidle)
			printf "#!/bin/sh\nexec %s set-active unknown\n" "$this_script" > "$SVDIR/$1/finish"
			chmod +x "$SVDIR/$1/finish"
		;;
	esac
}

# (service)
function sv_disable() {
	check_is_valid_service_v "$1"
	if [ -d "${SVDIR:?}/$1" ] ; then
		[ ! -e "$SVDIR/$1/supervise/ok" ] || sv stop "$SVDIR/$1"
		rm -r "${SVDIR:?}/$1"
	fi
}

# (service)
function is_valid_service() {
	case "$1" in
		ikb|squeekboard|swayidle|command_runner)
			return 0 ;;
		*)
			return 1 ;;
	esac
}

function check_is_valid_service_v() {
	if ! is_valid_service "$1" ; then
		printf "'%s' is not a valid service name.\n" "$1" >&2
		return 1
	fi
}

function sv_is_running() {
	[ -d "$SVDIR/$1" ] || return 1
	sv status "$1" | grep -q "^run:"
}

# (cmd, service)
function sv_command() {
	case "$1" in
		enable)
			sv_enable "$2" ;;
		disable)
			sv_disable "$2" ;;
		start)
			if ! [ -d "$SVDIR/$2" ] ; then
				check_is_valid_service_v "$2"
				printf "Service '%s' is not enabled, enabling ...\n" "$2"
				sv_enable "$2"
			else
				sv start "$2"
			fi
		;;
		stop|restart|usr1|usr2)
			sv "$1" "$2" ;;
		status)
			sv_status "$2" ;;
	esac
}

## Activity logger

function get_active() {
	if [ -f "$FUCHS_KIOSK_RUNTIME_DIR/active_status" ] ; then
		if [ "$(date +%s -r "$FUCHS_KIOSK_RUNTIME_DIR/active_status" )" -gt "$(date +%s --date "10 min ago" )" ] ; then
			head -n 1 "$FUCHS_KIOSK_RUNTIME_DIR/active_status"
			return
		fi
	fi
	echo "unknown"
}

function is_active() {
	case "$(get_active)" in
		active|idle)
			return 0 ;;
		*)
			return 1 ;;
	esac
}

# (activity)
function log_activity() {
	echo "$(date -Is), $1" > "$FUCHS_KIOSK_LOG_DIR/activity_$(date "+%Y-%m").csv"
}

function set_active() {
	case "$1" in
		active)
			echo "active" > "$FUCHS_KIOSK_RUNTIME_DIR/active_status"
			log_activity active
			command_runner_send dpms-on
			sv start ikb || true
		;;
		inactive)
			echo "inactive" > "$FUCHS_KIOSK_RUNTIME_DIR/active_status"
			rm "$FUCHS_KIOSK_RUNTIME_DIR/is-active" >&- 2>&- || true
			log_activity inactive
			# hooks
			sv_command restart ikb || true
			if [ -n "$(get_option screen_off_when_inactive)" ] ; then
				command_runner_send dpms-off
				sv stop ikb || true
			fi
			;;
		idle)
			echo "idle" > "$FUCHS_KIOSK_RUNTIME_DIR/active_status"
			log_activity idle
		;;
		unknown)
			echo "unknown" > "$FUCHS_KIOSK_RUNTIME_DIR/active_status"
			log_activity unknown
		;;
		*)
			echo "Invalid active status, valid ones are active,inactive,idle,unknown"
			return 1
		;;
	esac
}

function run_swayidle() {
	exec swayidle \
		timeout 60 "$0 set-active idle" \
		resume "$0 set-active active" \
		timeout 300 "$0 set-active inactive"
}

## Command runner

function log() {
	sev="$1"
	pat="$2"
	shift 2
	printf "[%s] $pat\n" "$sev" "$@" 2>&-
}

function command_runner() {
	rm "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo" 2>&- || true
	trap 'rm "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo"' EXIT
	mkfifo "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo"
	while true ; do
		read -r c < "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo"
		case "$c" in
			info)
				log info "%s" "$(dashboard)" ;;
			pull)
				settings_pull || true
				log info "Settings pull done!"
			;;
			rollback)
				settings_rollback || true
				log info "Rollback done!"
			;;
			peek)
				grim -- "$FUCHS_KIOSK_LOG_DIR/last_screenshot.png"
				log_activity "admin_screenshot"
				log info "Screenshot taken!"
			;;
			dpms-get)
				if swaymsg -t get_outputs --raw | jq '.[].dpms' | grep -q 'true' ; then
					rm "$FUCHS_KIOSK_RUNTIME_DIR/screen-is-on" || true
				else
					touch "$FUCHS_KIOSK_RUNTIME_DIR/screen-is-on" || true
				fi
				touch "$FUCHS_KIOSK_RUNTIME_DIR/screen-on-updated"
			;;
			dpms-off)
				swaymsg output '*' dpms off
				rm "$FUCHS_KIOSK_RUNTIME_DIR/screen-is-on" || true
			;;
			dpms-on)
				swaymsg output '*' dpms on
				touch "$FUCHS_KIOSK_RUNTIME_DIR/screen-is-on" || true
			;;
			*)
				log error "No such command_runner command! ('%s')" "$c";;
		esac
		touch "$FUCHS_KIOSK_RUNTIME_DIR/command_finished"
	done
}

# (command)
function command_runner_send() {
	if [ -w "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo" ] ; then
		echo "$1" > "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo"
	fi
}

## IKB controls

# (ikb_command)
function command_ikb() {
	if ! sv_is_running ikb ; then
		echo "The ikb isn't currently running."
		return 3
	fi
	case "$1" in
		reload-home)
			if is_active ; then
				echo "Not reloading, someone is currently using the terminal."
				echo "The reload will happen with the restart that occours when the terminal goes idle."
				return 4
			else
				sv_command usr1 ikb
			fi
		;;
		soft-restart)
			if is_active ; then
				echo "Terminal is currently in use."
				echo "Regular ikb restart will be triggered when terminal goes idle."
				return 4
			else
				sv_command restart ikb
			fi
		;;
		log)
			if [ -f "$FUCHS_KIOSK_LOG_DIR/ikb_error.log" ] ; then
				less "$FUCHS_KIOSK_LOG_DIR/ikb_error.log"
			else
				echo "No available logfile for ikb."
			fi
		;;
		*)
			echo "Unknown ikb subcommand."
			echo "Available ikb subcommands are:"
			echo " * reload-home"
			echo " * soft-restart"
			return 1
		;;
	esac
}

## Settings controls

# key, value
set_option() {
	option_path="$FUCHS_KIOSK_SETTINGS_DIR/option/$1"
	mkdir -p "$FUCHS_KIOSK_SETTINGS_DIR/option"
	if [ -n "$1" ] ; then
		printf "%s\n" "$2" > "$option_path"
	else
		rm "$option_path"
	fi
}

# (key)
get_option() {
	option_path="$FUCHS_KIOSK_SETTINGS_DIR/option/$1"
	if [ -r "$option_path" ] ; then
		head -n 1 "$option_path"
		return
	fi
	case "$1" in
		name) printf "%s\n" "$HOSTNAME";;
		*) printf "\n" ;;
	esac
}

settings_pull() {
	upstream="$(get_option upstream_settings_url)"
	if [ -z "$upstream" ] ; then
		echo "No upstream url set." >&2
		return 3
	fi
	if git clone --depth 1 -- "$upstream" "$FUCHS_KIOSK_SETTINGS_DIR/config.new" ; then
		log_activity "successful_pull"
		if [ -d "$FUCHS_KIOSK_SETTINGS_DIR/config" ] ; then
			[ ! -d "$FUCHS_KIOSK_SETTINGS_DIR/config.bak" ] || rm -rf "$FUCHS_KIOSK_SETTINGS_DIR/config.bak"
			mv "$FUCHS_KIOSK_SETTINGS_DIR/config" "$FUCHS_KIOSK_SETTINGS_DIR/config.bak"
		fi
		mv "$FUCHS_KIOSK_SETTINGS_DIR/config.new" "$FUCHS_KIOSK_SETTINGS_DIR/config"
		echo "soft-restarting ikb …"
		command_ikb soft-restart
	else
		log_activity "failed_pull"
	fi
}

settings_save_for_rollback() {
	if ! [ -d "$FUCHS_KIOSK_SETTINGS_DIR/config" ] ; then
		echo "No configuration directory to save for rollback" >&2
		return 4
	fi
	[ ! -d "$FUCHS_KIOSK_SETTINGS_DIR/config.known_working" ] || rm -rf "$FUCHS_KIOSK_SETTINGS_DIR/config.known_working"
	cp -r "$FUCHS_KIOSK_SETTINGS_DIR/config" "$FUCHS_KIOSK_SETTINGS_DIR/config.known_working"
}

settings_rollback() {
	if ! [ -d "$FUCHS_KIOSK_SETTINGS_DIR/config.known_working" ] ; then
		echo "No configuration directory to roll back to." >&2
		return 4
	fi
	if [ -d "$FUCHS_KIOSK_SETTINGS_DIR/config" ] ; then
		[ ! -d "$FUCHS_KIOSK_SETTINGS_DIR/config.broken" ] || rm -rf "$FUCHS_KIOSK_SETTINGS_DIR/config.broken"
		mv "$FUCHS_KIOSK_SETTINGS_DIR/config" "$FUCHS_KIOSK_SETTINGS_DIR/config.broken"
	fi
	cp -r "$FUCHS_KIOSK_SETTINGS_DIR/config.known_working" "$FUCHS_KIOSK_SETTINGS_DIR/config"
}


# (subcommand,arg)
command_settings() {
	case "$1" in
		pull)
			settings_pull ;;
		set-upstream)
			set_option upstream_settings_url "$2" ;;
		set-name)
			set_option name "$2" ;;
		save-for-rollback)
			settings_save_for_rollback ;;
		rollback)
			settings_rollback ;;
		*)
			echo "Unknown settings subcommand."
			echo "Available commands are:"
			echo " * pull"
			echo " * set-upstream"
			echo " * set-name"
			echo " * save-for-rollback"
			echo " * rollback"
			return 1
		;;
	esac
}

## screen

function is_screen_on() {
	test -f "$FUCHS_KIOSK_RUNTIME_DIR/screen-is-on"
}

# (file,timeout,event)
function wait_for_file() {
	timeout "${2:-3}" inotifywait -e "${3:-close_write}" "$1" 2>/dev/null >/dev/null
}

function command_peek() {
	require_command grim
	require_command inotifywait
	admin_ui_require_command_runner
	if is_active && [ -z "$FORCE_FLAG" ] ; then
		echo "The terminal is currently in use."
		echo "Please respect the users privacy and consider not taking a screenshot."
		echo "In case you want to take a screenshot anyway use --force"
		exit 4
	fi
	command_runner_send dpms-get
	command_runner_send peek
	screenshot_file="$FUCHS_KIOSK_LOG_DIR/last_screenshot.png"
	[ -f "$screenshot_file" ] || touch "$screenshot_file"
	echo "Waiting for screenshot ..."
	if wait_for_file "$screenshot_file" ; then
		echo "screenshot taken."
		if command -v img2sixel >&- 2>&- ; then
			img2sixel -w "$(tput cols)0" "$FUCHS_KIOSK_LOG_DIR/last_screenshot.png"
		fi
	fi
	if ! is_screen_on ; then
		echo "The screen is currently off."
		exit 4
	fi
}

#(subcommand, arg)
function command_screen() {
	case "$1" in
		on)
			admin_ui_require_command_runner
			command_runner_send dpms-on
		;;
		off)
			admin_ui_require_command_runner
			command_runner_send dpms-off
		;;
		on-inactive)
			case "$2" in
				on)
					set_option screen_off_when_inactive ""
					command_runner_send dpms-on
				;;
				off)
					set_option screen_off_when_inactive y
					if ! is_active ; then
						command_runner_send dpms-on
					fi
				;;
				""|get)
					if [ -n "$(get_option screen_off_when_inactive)" ] ; then
						echo on
					else
						echo off
					fi
				;;
				*)
					echo "Either on, off or get …"
					exit 1
				;;
			esac
		;;
		""|get)
			admin_ui_require_command_runner
			command_runner_send dpms-get
			update_file="$FUCHS_KIOSK_RUNTIME_DIR/screen-on-updated"
			[ -f "$update_file" ] || touch "$update_file"
			if wait_for_file "$update_file" ; then
				if is_screen_on ; then
					echo on
				else
					echo off
				fi
			else
				echo "Timeout waiting for result."
				return 5
			fi
		;;
		*)
			echo "Unknown screen subcommand."
			echo "Available commands are:"
			echo " * on"
			echo " * off"
			echo " * get"
			echo " * on-interactive (on|off|get)"
			exit 1
		;;
	esac

}

## Admin ui

admin_ui_require_command_runner() {
	if [ ! -w "$FUCHS_KIOSK_RUNTIME_DIR/command-fifo" ] ; then
		echo "The command_runner is not active."
		echo "Consider starting or enabling it."
		exit 3
	fi
}

########## Do stuff

case "$COMMAND" in
	status)
		sv_status "$SUBCOMMAND" ;;
	run)
		command_run "$SUBCOMMAND" ;;
	check-dependencies)
		command_check_dependencies ;;
	start|stop|enable|disable|restart)
		sv_command "$COMMAND" "$SUBCOMMAND" ;;
	set-active)
		set_active "$SUBCOMMAND" ;;
	get-active)
		get_active ;;
	dash|dashboard)
		dashboard ;;
	ikb)
		command_ikb "$SUBCOMMAND";;
	settings)
		command_settings "$SUBCOMMAND" "$ARG" ;;
	peek)
		command_peek
	;;
	screen)
		command_screen "$SUBCOMMAND" "$ARG"
	;;
	startup)
		if [ -z "$XDG_RUNTIME_DIR$WAYLAND_DISPLAY" ] ; then
			echo "An XDG_RUNTIME_DIR and WAYLAND_DISPLAY are required."
			exit 1
		fi
		"$0" run runsv &
		RUN_PID="$!"
		trap 'kill -1 "$RUN_PID"' EXIT
		inotifywait "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" -e DELETE_SELF
		kill -1 "$RUN_PID"
	;;
	*)
		printf "Unknown command: %s\n" "$COMMAND"
		exit 1 ;;
esac
