#!/bin/bash

# Description:       The purpose of fll-locales is to calculate required
#                    strings to configure the locale settings of system
#                    according to given lang= string.

###
# F.U.L.L.S.T.O.R.Y
#
# Copyright: (C) 2007 - 2024 Kel Modderman <kelvmod@gmail.com>
#            (C) 2008 Michael Deelwater <michael.deelwater@googlemail.com>
#            (C) 2016 Niall Walsh <niallwalsh@celtux.org>
#            (C) 2017 - 2024 Stefan Lippers-Hollmann <s.l-h@gmx.de>
# License:   GPLv2
#
# F.U.L.L.S.T.O.R.Y Project Homepage:
# https://github.com/fullstory
###

PATH=/usr/sbin:/usr/bin
NAME="fll-locales"

if [ "${1}" = "list" ]; then
	sed -n 's![ \t]\+\([a-z-]\+\)|\?\([a-z]\+\)\?).*### [A-Z][A-Z] \(.\+\) kb:\(.\+\) ###!\1, \3,\4!p' "${0}"
	exit 0
fi

###
# source distro-defaults, no-op unless in live mode
###
FLL_DISTRO_MODE="installed"
FLL_DISTRO_NAME="siduction"

if [ -r /etc/default/distro ]; then
	. /etc/default/distro
fi

if [ "${FLL_DISTRO_MODE}" != "live" ]; then
	[ -n "${FLL_LANG}" ] || exit 0
fi

###
# source fll functions
###
. /lib/init/fll

###
# source LANG functions
###
. /usr/share/fll-live-initscripts/locales

###
# some console-setup defaults
###
CHARMAP="UTF-8"
CODESET="Uni2"
# Debian agrees that Terminus doesn't look great enough to be default
# http://bugs.debian.org/497331
FONTFACE="VGA"
# Keep the default size of 16 here to avoid clearing VT 1/2 way through
# bootup sequence
FONTSIZE="16"

###
# some keyboard-configuration defaults
###
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS="lv3:ralt_switch,compose:lwin,grp:alt_shift_toggle"

###
# cheatcode handling
###
if [ -f /proc/cmdline ]; then
	for param in $(cat /proc/cmdline); do
		case "${param}" in
			lang=*)
				LANGUAGE=$(awk 'BEGIN{ print tolower("'"${param#lang=}"'") }')
				;;
			utc=yes)
				UTC="yes"
				;;
			utc|gmt)
				CUSTOM_TZ="Etc/UTC"
				;;
			tz=*)
				CUSTOM_TZ="${param#tz=}"
				;;
			noaptlang)
				NOAPTLANG="yes"
				;;
			xkboptions=*)
				KBOPTIONS="${param#xkboptions=}"
				;;
			keytable=*)
				KEYTABLE="${param#keytable=}"
				;;
			xkbmodel=*)
				KBMODEL="${param#xkbmodel=}"
				;;
			xkbvariant=*)
				KBVARIANT="${param#xkbvariant=}"
				;;
		esac
	done
fi

###
# allow FLL_LANG environment variable to trump
###
if [ -n "${FLL_LANG}" ]; then
	LANGUAGE="${FLL_LANG}"
fi

###
# lang cheatcode can optionally be made of two dash-separated parts ll-cc
# ll -> language code
# cc -> demographic code
###
LANG_CODE=${LANGUAGE%%[-_]*}
DEMO_CODE="$(echo ${LANGUAGE##*[-_]} | awk '{print toupper($1)}')"

LANGS=$(locale -a)
LANG=""

# First check if they entered a built in lang
for LOCALE in ${LANGS}; do
	[ "${LOCALE}" = "${LANG_CODE}_${DEMO_CODE}.utf8" ] && LANG="${LOCALE}" && break

	# match the language to find the default and possible locales
	case "${LOCALE}" in
		${LANG_CODE}_*)
			[ -z "${LANG_POSS}" ] && LANG_POSS="${LOCALE}"
			fll_locale_default ${LOCALE} && LANG_DEF="${LOCALE}"
			;;
	esac
done

# See if we have some knowledge on how to setup the requested locale
if [ -z "${LANG}" ]; then
	for LOCALE in fll_locale_cheats; do
		[ "${LOCALE}" = "${LANG_CODE}_${DEMO_CODE}.utf8" ] && \
			fll_locale_lang ${LOCALE} && break
	done
fi

# Ok just fallback to the default language, or whatever we know about or en_US
if [ -z "$LANG" ]; then
	if [ -n "${LANG_DEF}" ]; then
		LANG="${LANG_DEF}"
	else
		if [ -n "${LANG_POSS}" ]; then
			LANG="${LANG_POSS}"
		else
			LANG="en_US.utf8"
		fi
	fi
fi
export LANG

###
# if demographic code was ommitted, extract default demo_code from LANG
###
if [ -z "${DEMO_CODE}" ]; then
	LANG_CHECK="${LANG%%.*}"
	DEMO_CODE="${LANG_CHECK##*_}"
fi

#set tz, mirror, xkb via fll_locale_demo
if [ "${LANG}" = "${LANG_CODE}_${DEMO_CODE}.utf8" ]; then
	fll_locale_demo ${LANG}
else
	# We've altered their LANG
	fll_locale_cheats
	for LOCALE in ${FLL_LOCALE_CHEATS}; do
		# if we have their locale
		if [ "${LOCALE}" = "${LANG_CODE}_${DEMO_CODE}.utf8" ]; then
			DEMO="${LOCALE}"
			break
		fi

		# if we have a locale in their country
		if [ "${LOCALE#*_}" = "${DEMO_CODE}.utf8" ]; then
			[ -z "${DEMO_POSS}" ] && DEMO_POSS="${LOCALE}"
		fi
	done

	# if it's not a country we know about fallback to default 00_00
	if [ -z "${DEMO}" ]; then
		if [ -n "${DEMO_POSS}" ]; then
			DEMO="${DEMO_POSS}"
		else
			DEMO="00_00.utf8"
		fi
	fi

	fll_locale_demo ${DEMO}
fi

###
# allow CUSTOM_TZ to override above TZ definitions
###
if [ -n "${CUSTOM_TZ}" ]; then
	case "${CUSTOM_TZ}" in
		utc|UTC)
			CUSTOM_TZ="Etc/UTC"
			;;
	esac
	[ -f "/usr/share/zoneinfo/${CUSTOM_TZ}" ] && TZ="${CUSTOM_TZ}"
fi

###
# allow KEYTABLE to update above XKBLAYOUT settings
###
if [ -n "${KEYTABLE}" ]; then
	XKBLAYOUT="${KEYTABLE}"
fi

###
# allow KBOPTIONS to update above XKBOPTIONS settings
###
if [ -n "${KBOPTIONS}" ]; then
	XKBOPTIONS="${KBOPTIONS}"
fi

###
# allow KBMODEL to update above XKBMODEL settings
###
if [ -n "${KBMODEL}" ]; then
	XKBMODEL="${KBMODEL}"
fi

###
# allow KBVARIANT to update above XKBVARIANT settings
###
if [ -n "${KBVARIANT}" ]; then
	XKBVARIANT="${KBVARIANT}"
fi

set_timezone()
{
	###
	# configure timezone, fallback to UTC
	###
	[ -f "/usr/share/zoneinfo/${TZ}" ] || TZ="Etc/UTC"
	echo "configuring timezone data for '${TZ}'"
	echo "${TZ}" > /etc/timezone
	rm -f /etc/localtime && ln -s "/usr/share/zoneinfo/${TZ}" /etc/localtime
#	rm -f /etc/localtime && cp -f "/usr/share/zoneinfo/${TZ}" /etc/localtime
	###
	# hack rcS, make localtime default, unless tz=Etc/UTC or utc=yes
	###
	if [ "${TZ}" = "Etc/UTC" ] || [ "${UTC}" = "yes" ]; then
		printf "0.000000 0 0.000000\n0\nUTC\n" > /etc/adjtime
	else
		# debian defaults to UTC=yes, which is rumored to be dual-boot unfriendly
		printf "0.000000 0 0.000000\n0\nUTC\n" > /etc/adjtime

		# update the system clock a'la /lib/udev/rules.d/85-hwclock.rules
		/sbin/hwclock --rtc=/dev/rtc0 --systz
		/sbin/hwclock --rtc=/dev/rtc0 --hctosys
	fi
}

set_locale()
{
	###
	# select default locale and configure console-data via debconf
	###
	echo "${NAME}: configuring locales for '${LANG}'"

	echo "locales locales/default_environment_locale select ${LANG}" | \
		debconf-set-selections
	update-locale "LANG=${LANG}"
}

set_console()
{
	# write configuration: console-setup
	cat > /etc/default/console-setup <<EOF
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="${CHARMAP}"
CODESET="${CODESET}"
FONTFACE="${FONTFACE}"
FONTSIZE="${FONTSIZE}"
EOF

	# write configuration: keyboard-configuration
	# only set one layout
	# FIXME: investigate debconfsettings!
	sed -i	-e "s/^\(XKBMODEL\=\).*/\1\"${XKBMODEL}\"/" \
		-e "s/^\(XKBLAYOUT\=\).*/\1\"${XKBLAYOUT%%,*}\"/" \
		-e "s/^\(XKBVARIANT\=\).*/\1\"${XKBVARIANT}\"/" \
		-e "s/^\(XKBOPTIONS\=\).*/\1\"${XKBOPTIONS}\"/" \
			/etc/default/keyboard

#	setupcon --save-only
	setupcon --save

	udevadm trigger --property-match=ID_INPUT_KEYBOARD=1
}

apt_install_lang() {
	###
	# install debs for lang from deb archive on cd
	###
	if [ -n "$NOAPTLANG" ]; then
		return
	fi

	LIVEAPT="${FLL_MOUNTPOINT}./i18n"
	if [ ! -d "${LIVEAPT}" ]; then
		return
	fi

	APTARCH=$(dpkg --print-architecture)
	# e.g. try /fll/sr0/i18n/i386/de_AT then the first de_* found
	if [ -f "${LIVEAPT}/${APTARCH}/${LANG%%[.]*}" ]; then
		# we have the variant requested
		LANGPACKS=$(cat "${LIVEAPT}/${APTARCH}/${LANG%%[.]*}")
	elif [ "${LANG%%[_]*}" != 'en' ]; then
		# try fll-locales to find one
		for lf in ${LIVEAPT}/${APTARCH}/${LANG%[_]*}*; do
			if [ -f "${lf}" ]; then
				# we have a file for the language
				LANGPACKS=$(cat "${lf}")
				break
			fi
		done
		[ -z "${LANGPACKS}" ] && return
	else
		# it's english and we don't have the variant requested
		return
	fi

	echo "installing language packages for '${LANG}'"

	# don't touch apt if it has been used
	if [ "/var/lib/dpkg/status" -nt "$(fll_get_mnt)/${FLL_IMAGE_LOCATION}" ]; then
		echo "dpkg already updated"
		return
	fi

	LIVEAPTSOURCES=$(mktemp -d -t liveapt.XXXXXX)
	APTGETBASE="apt-get -o Dir::Etc=$LIVEAPTSOURCES"
	echo 'deb [ trusted=yes allow-insecure=yes ] file://'${LIVEAPT}' sid main' > ${LIVEAPTSOURCES}/sources.list
	mkdir ${LIVEAPTSOURCES}/preferences.d

	if ! ${APTGETBASE} update > /dev/null; then
		echo "apt-get update for i18n packages from cd failed"
		apt_install_lang_clean
		return
	fi

	APTGETBASE="${APTGETBASE} -o Acquire::Check-Date=false --allow-unauthenticated  --assume-yes --no-remove"

	# do a dry-run to calculate size of packages and that will be used
	APTUSESRAW=$(LANG=C ${APTGETBASE} --print-uris install ${LANGPACKS} | \
		awk '/^After\ this\ operation\,\ /{print $4}')
	APTUSES=${APTUSESRAW%%[.]*MB}
	APTUSES=$(echo $APTUSESRAW | sed 's|MB$||;')

	# lets assume it is <MB and ok if it's not in MB
	if [ "${APTUSES}" != "${APTUSESRAW}" ]; then
		APTUSES=$(echo $APTUSES | sed 's|\.[0-9]*$||;')

		# get a free memory figure
		FREEMEM=$(LANG=C free -m | awk '/\-\/\+\ buffers/{print $4}')

		# check free - used > minspace (256M)
		MEMAFTER=$(( ${FREEMEM} - ${APTUSES} ))
		if [ ${MEMAFTER} -lt 256 ]; then
			echo "minimum 256MB free ram needed for i18n packages"
			echo "you would only have ${MEMAFTER}MB free, not installing"
			apt_install_lang_clean
			return
		fi

		# check used/free > minratio
		USESRATIO=$(( ${FREEMEM} / ${APTUSES} ))
		if [ ${USESRATIO} -lt 5 ]; then
			echo "i18n packages would use (${APTUSES}MB) more then 20% of available memory (${FREEMEM}MB), not installing."
			apt_install_lang_clean
			return
		fi
	fi

	# install the packages
	${APTGETBASE} install ${LANGPACKS} > /dev/null

	# clean up
	apt_install_lang_clean
}

apt_install_lang_clean() {
	echo '' > ${LIVEAPTSOURCES}/sources.list
	apt-get -o Dir::Etc=$LIVEAPTSOURCES update > /dev/null
	apt-get -o Dir::Etc=$LIVEAPTSOURCES clean > /dev/null
	rm -rf ${LIVEAPTSOURCES}
}

write_deb822() {
# Preparation an entry for the .sources files.
	for typ in $(echo "${types}"); do
		if [ "X${typ}" == "Xdeb-src" ]; then
			yes_no="no"
			echo "" >> ${target}
		fi
	
	cat << EOF >> ${target}
	Types:      ${typ}
	URIs:       ${url}
	Suites:     ${suites}
	Components: ${compo}
	Enabled:    ${yes_no}
	Signed-By:  ${key}
EOF
	done
}

localize_sources() {
	# Deploy load balancing for siduction mirrors.
	# Assign mirror URLs to states and state groups.
	# Select the mirror that matches the country code.
	# Mirrors available in: AT BE DE DK EC HK HU IT NL RU SE US

	full_list=(Austria Belgium Denmark Ecuador Germany Hong_Kong Hungary Italy \
			Netherlands Russia Sweden United_States)

	# LOCALE GROUPS                                             # MIRROR POOL
	#-----------------------------------------------------------#------------
	# america_north: AG CA US MX                                # US
	# america_south: BO BR CL CO CR EC GT NI PA PE PR SV UY VE  # EC
	# asia:          CN HK IN JP KR PH SG TW                    # HK
	# europe_east:   BY CY HR PL RO UA TR                       # HU RU
	# europe_north:  EE FI IE IS NO                             # DK SE
	# europe_south:  BA BG GR SI                                # IT
	# europe_center_west and all those not listed:              # AT DE BE NL

	# Arrays containing the URLs.
	Austria=(\
		https://siduction.office-vienna.at/)
	Belgium=(\
		https://ftp.belnet.be/mirror/siduction/)
	Denmark=(\
		https://mirrors.dotsrc.org/siduction/)
	Ecuador=(\
		https://mirror.cedia.org.ec/siduction/)
	Germany=(\
		https://packages.siduction.org/ \
		https://ftp.gwdg.de/pub/linux/siduction/ \
		https://ftp.halifax.rwth-aachen.de/siduction/ \
		https://ftp.spline.de/pub/siduction/ \
		https://ftp.uni-stuttgart.de/siduction/)
	Hong_Kong=(\
		https://mirror-hk.koddos.net/siduction/)
	Hungary=(\
		https://quantum-mirror.hu/mirrors/pub/siduction/)
	Italy=(\
		https://siduction.mirror.garr.it/)
	Netherlands=(\
		https://ftp.snt.utwente.nl/pub/linux/siduction/)
	Russia=(\
		https://mirror.yandex.ru/mirrors/siduction/)
	Sweden=(\
		https://ftp.acc.umu.se/mirror/siduction.org/)
	United_States=(\
		http://ftp.gtlib.gatech.edu/pub/siduction/ \
		https://mirror.math.princeton.edu/pub/siduction/ \
		https://liquorix.net/siduction/)

	# Selecting the mirror according to the locale.
	case $DEMO_CODE in 
		AT)
		mirror=(${Austria[@]})
		;;
		BE)
		mirror=(${Belgium[@]})
		;;
		DE)
		mirror=(${Germany[@]})
		;;
		DK)
		mirror=(${Denmark[@]})
		;;
		HU)
		mirror=(${Hungary[@]})
		;;
		NL)
		mirror=(${Netherlands[@]})
		;;
		RU)
		mirror=(${Russia[@]})
		;;
		SE)
		mirror=(${Sweden[@]})
		;;
		AG|CA|US|MX) # america_north
		mirror=(${United_States[@]})
		;;
		BO|BR|CL|CO|CR|EC|GT|NI|PA|PE|PR|SV|UY|VE) # america_south
		mirror=(${Ecuador[@]})
		;;
		CN|HK|IN|JP|KR|PH|SG|TW) # asia
		mirror=(${Hong_Kong[@]})
		;;
		BY|CY|HR|PL|RO|UA|TR) # europe_east
		mirror=(${Hungary[@]} ${Russia[@]})
		;;
		EE|FI|IE|IS|NO) # europe_north
		mirror=(${Denmark[@]} ${Sweden[@]})
		;;
		BA|BG|GR|IT|SI) # europe_south
		mirror=(${Italy[@]})
		;;
		*) # europe_center_west
		mirror=(${Austria[@]} ${Germany[@]} ${Belgium[@]} ${Netherlands[@]})
		;;
	esac

	# Load balancing with multiple mirrors.
	nr=${#mirror[@]}
	NR="$(mawk 'BEGIN{print int('"$nr"' * rand())}')"
	FLL_MIRROR=${mirror[NR]}

	# debian.sources
	target="/etc/apt/sources.list.d/debian.sources"
	types="deb deb-src"
	url="https://deb.debian.org/debian/"
	suites="unstable"
	compo="main non-free-firmware"
	yes_no="yes"
	key="/usr/share/keyrings/debian-archive-keyring.gpg"

	echo "# debian loadbalancer" > ${target}
	echo "" >> ${target}
	write_deb822

	suites="experimental"
	yes_no="no"
	echo "" >> ${target}
	echo "" >> ${target}
	write_deb822

	url="https://incoming.debian.org/debian-buildd"
	suites="buildd-unstable"
	echo "" >> ${target}
	echo "" >> ${target}
	write_deb822


	# debian debug.sources
	target="/etc/apt/sources.list.d/dbgsym.sources"
	types="deb"
	url="https://debug.mirrors.debian.org/debian-debug"
	suites="testing-debug"
	compo="main contrib non-free-firmware"
	echo "# debian debug" > ${target}
	echo "" >> ${target}
	write_deb822

	suites="unstable-debug"
	echo "" >> ${target}
	write_deb822

	suites="experimental-debug"
	echo "" >> ${target}
	write_deb822


	# siduction extra.sources and fixes.sources
	types="deb deb-src"
	suites="unstable"
	compo="main non-free-firmware"
	key="/usr/share/keyrings/siduction-archive-keyring.gpg"

	for target_file in "extra" "fixes"; do
		target="/etc/apt/sources.list.d/${target_file}.sources"
		url="${FLL_MIRROR}${target_file}"
		yes_no="yes"
		
		cat << EOF > $target
# This is the default mirror, choosen at first boot.
# One might consider to choose the geographical nearest or the fastest mirror.

EOF
		
		write_deb822
		
		for country in ${full_list[@]}; do
			number=1
			echo "" >> ${target}
			echo "" >> ${target}
			echo "# $country:" >> ${target}
			
			# Set and use indirection to access array values.
			choice=$country[@]
			for url in ${!choice}; do
				url="${url}/${target_file}"
				if [ $number -gt 1 ]; then
					echo "" >> ${target}
					echo "" >> ${target}
				fi
				write_deb822
				((++number))
			done
		done
	done

	# we don't provide a i386 kernel anymore -
	# we choose the fine liquorix kernel instead.
	# so we should provide a upgrade path for this kernel
	target="/etc/apt/sources.list.d/liquorix.sources"
	url="https://liquorix.net/debian"
	suites="sid"
	compo="main"
	yes_no="no"
	key="/usr/share/keyrings/liquorix-keyring.gpg"

	echo "# liquorix kernel" > ${target}
	echo "" >> ${target}
	write_deb822

	# Remove obsolete .list files if .sources files have been created.
	if ls /etc/apt/sources.list.d/*.sources &>/dev/null; then
		echo "Remove obsolete *.list files."
		find /etc/apt/sources.list.d/ -maxdepth 1 -name "*.list" -delete
	fi
}

save_locale_variables() {
	for var in FLL_MIRROR CHARMAP CODESET FONTFACE FONTSIZE \
		   XKBMODEL XKBLAYOUT XKBVARIANT XKBOPTIONS; do
		val=$(eval echo \$${var})
		echo "${var}=\"${val}\""
	done > "/etc/default/${NAME}"
}

case "${1}" in
	start)
		set_timezone
		set_locale
		set_console
		apt_install_lang
		localize_sources
		save_locale_variables
		;;
	localize)
		# localize
		set_locale
		set_console
		apt_install_lang
		localize_sources
		save_locale_variables
		;;
	*)
		echo "Usage: ${NAME} {start|localize}" >&2
		exit 3
		;;
esac

:
