# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: Copyright 2015-2022 SUSE LLC
# shellcheck shell=bash

if [ -e /etc/os-release ]; then
	. /etc/os-release
else
	. /usr/lib/os-release
fi

stty_size() {
	set -- $(stty size); LINES=$1; COLUMNS=$2
	# stty size can return zero when not ready or
	# its a serial console
	if [ "$COLUMNS" = "0" -o "$LINES" = "0" ]; then
		LINES=24
		COLUMNS=80
	fi

	let dh_menu=LINES-15
	let dh_text=LINES-5
}
stty_size

# Make sure globs and regex are consistent everywhere.
LC_COLLATE=C.UTF-8

result=
list=
password=''
modules=()

_find_modules() {
	local f
	#for f in /etc/wsl-firstboot/modules/* "${wsl_prefix?}/share/wsl-firstboot/modules"/*; do
	for f in /etc/wsl-firstboot/modules/* "/usr/share/wsl-firstboot/modules"/*; do
		if [ -L "$f" ] || [ -f "$f" ]; then
			echo "${f##*/}" "$f"
		fi
	done
}

# Echos the value of the module variable or a fallback if unset.
# Usage: module_get_prop modulename varname defaultvalue
module_get_prop() {
	local module="$1"
	local varname="$2"
	local default="${3-}"
	local fullname="${module}_${varname}"
	echo -n "${!fullname-"${default}"}"
}

init_modules() {
	[ -z "$modules" ] || return 0
	local module f _prio
	local unordered_modules=()
	while read -r module f; do
		if [ -L "$f" ] && [ "$(readlink "$f")" = "/dev/null" ]; then
			continue
		fi
		# shellcheck source=/dev/null
		source "$f" || continue
		unordered_modules+=("${module}")
	done < <(_find_modules|sort -k 1,1 -u)

	# Sort modules by priority
	while read -r _prio module; do
		modules+=("${module}")
	done < <(for module in "${unordered_modules[@]}"; do
			module_get_prop "$module" "priority" 50; echo " $module"
		done | sort -n)
}

module_has_hook() {
	local module="$1"
	local module_func="$2"
	module_function="${module}_${module_func}"
	[ "$(type -t -- "${module_function}")" = "function" ]
}

call_module() {
	local module="$1"
	local module_func="$2"
	module_function="${module}_${module_func}"
	[ "$(type -t -- "${module_function}")" = "function" ] || return 1
	"${module_function}" && true # To not trigger errexit
	ret=$?
	[ $ret -eq 0 ] || return $ret
}

call_module_hook() {
	local hook="$1"
	for module in "${modules[@]}"; do
		call_module "${module}" "${hook}" || continue
	done
	return 0
}

# Run dialog with wsl-firstboot style options applied
d_styled() {
	dialog --backtitle "$PRETTY_NAME" "$@"
}

# Run d_styled and save the output into $result
d_with_result() {
	local retval=0
	local stdoutfd
	# Bash makes it a bit annoying to read the output of a different FD into a variable, it
	# only supports reading stdout by itself. So redirect 3 to stdout and 1 to the real stdout.
	exec {stdoutfd}>&1
	result="$(d_styled --output-fd 3 "$@" 3>&1 1>&${stdoutfd})" || retval=$?
	# Word splitting makes it necessary to use eval here.
	eval "exec ${stdoutfd}>&-"
	return "$retval"
}

# Run d_with_result but exit if cancelled (ESC or Cancel/No button pressed)
d_with_exit_on_fail() {
	while true
	do
		retval=0
		d_with_result "$@" || retval=$?
		case $retval in
		  0)
			return 0
			;;
		  1|255)
			d_styled --yesno $"Do you really want to quit?" 0 0 && exit 1
			continue
			;;
		esac
	done
}

# Run d_with_exit_on_fail, just with the previous unclear name for backwards compat
d() {
	d_with_exit_on_fail "$@"
}

warn(){
	d --title $"Warning" --msgbox "$1" 0 0
}

# Given the number of total item pairs, outputs the number of items to display at once
menuheight() {
	local height=$(($1 / 2))
	[ "$height" -le "$dh_menu" ] || height="$dh_menu"
	echo $height
}

# localectl --no-pager list-keymaps does not list aliases (symlinks), but those are used
# by YaST/langset.sh, so we need to show them.
findkeymaps()
{
	list=()
	local line
	while read line; do
		list+=("${line%.map.gz}" '')
	done < <(find /usr/share/kbd/keymaps -name '*.map.gz' -printf "%f\n" | sort -u)
	[ -n "$list" ]
}

findlocales()
{
	list=()
	local l locale
	# List only locales which are both in live-langset-data and glibc-locale(-base)
	for l in /usr/share/langset/*; do
		locale="${l#/usr/share/langset/}"
		[ -d "/usr/lib/locale/${locale}.utf8" ] || continue
		list+=("${locale}" '')
	done
	[ -n "$list" ]
}

get_current_locale()
{
	cur_locale=$(awk -F= '$1 == "LANG" { print $2; exit }' /etc/locale.conf)
	[ -z "$cur_locale" ] && cur_locale="en_US"
	echo "${cur_locale}"
}

apply_locale()
{
	if [ ! -z "$WSL_LOCALE" ]; then
		run langset.sh "$WSL_LOCALE" || warn $"Setting the locale failed"
	fi
}

apply_locale_and_keytable()
{
	if [ ! -z "$WSL_LOCALE" -a ! -z "$WSL_KEYTABLE" ]; then
		# Activate the selected keyboard layout
		run langset.sh "$WSL_LOCALE" "$WSL_KEYTABLE" || warn $"Setting the keyboard layout failed"
	fi
}

apply_password()
{
	# FIXME: systemd-firstboot doesn't set password if shadow present
	if [ -n "$password" ]; then
		run echo "root:$password" | run /usr/sbin/chpasswd
	fi
}

# Resolves /dev/console and /dev/tty0
resolve_tty() {
	local tty="$1"
	if [ "$tty" = "/dev/console" ]; then
		tty=$(awk '{printf "/dev/%s", $NF}' /sys/class/tty/console/active)
	fi

	if [ "$tty" = "/dev/tty0" ]; then
		printf "/dev/%s" "$(cat /sys/class/tty/tty0/active)"
	else
		echo -n "$tty"
	fi
}

# get systemd credential
# https://systemd.io/CREDENTIALS/
get_credential()
{
	local var="${1:?}"
	local name="${2:?}"
	[ -n "$CREDENTIALS_DIRECTORY" ] || return 1
	[ -e "$CREDENTIALS_DIRECTORY/$name" ] || return 1
	read -r "$var" < "$CREDENTIALS_DIRECTORY/$name" || [ -n "${!var}" ]
}

# vim: syntax=sh
