#!/bin/sh
set -e

. /usr/share/debconf/confmodule

db_capb backup

localecode="debian-installer/locale"
langname_ascii="languagechooser/language-name-ascii"
langname_latin="languagechooser/language-name-latin"
langname_fb="languagechooser/language-name-fb"
langname_all="languagechooser/language-name"
fallbacklocalecode="debian-installer/fallbacklocale"
languagecode="debian-installer/language"
countrycode="debian-installer/country"
consoledisplay="debian-installer/consoledisplay"
shortlist="countrychooser/shortlist"
fulllist="countrychooser/country-name"
supportedlocales="localechooser/supported-locales"

# This is the iso_3166.tab file location
ISO3166TAB=/usr/share/iso-codes/iso_3166.tab
SUPPORTEDLOCALES=/etc/SUPPORTED-short
if [ ! -f "$SUPPORTEDLOCALES" ]; then
	SUPPORTEDLOCALES=/usr/share/localechooser/SUPPORTED-short
fi
SHORTLISTS=/etc/shortlists
if [ ! -f "$SHORTLISTS" ]; then
	SHORTLISTS=/usr/share/localechooser/shortlists
fi
LANGUAGELISTFILE=/usr/share/languagelist
if [ ! -f "$LANGUAGELISTFILE" ]; then
	LANGUAGELISTFILE=/usr/share/localechooser/languagelist
fi

# This function installs a package (or marks it for install)
# without failing if the install fails
# It outputs a message to the log file
pkginstall() {
	if [ -n "$1" ] ; then
		apt-install $1 || true
		log "Requesting installation of package $1"
	fi
}

error() {
	logger -t localechooser "error: $@"
	exit 1
}

log() {
	logger -t localechooser "info: $@"
}


code2country() {
	if [ -z "$1" ] ; then
		echo
	elif [ -n "$1" ] ; then
		line=`grep "$1" $ISO3166TAB`

		if [ -n "$line" ]; then
			# Remember that country names may have
			# spaces so the code is different than in
			# country2code.
			echo $line | cut -b 4-
		else
			echo
		fi
	else
		error "Missing argument"
	fi
}

country2code() {
	COUNTRYNAME=$(echo "$1" | sed 's/\\,/,/g')
	line=`grep "$COUNTRYNAME$" $ISO3166TAB`

	if [ -n "$line" ]; then
		set $line
		if [ -n "$1" ]; then
			echo "$1"
		fi
	fi
}

locale2langname() {
	if [ ! -f $2 ] ; then
		echo "$2 does not exist"
		exit 1
	fi
	langpart="${1%%_*}"
	if [ "$1" != "C" ]; then
		# Match the language code with 5th field in languagelist
		line=$(cat $2 | grep -v "^#" | cut -f1,5,6 -d\; | grep -v '^C;' | grep ";$langpart;")
		if [ -n "$line" ] ; then
			if [ "$(echo "$line" | grep -c '')" -gt 1 ]; then
				# More than one match; try matching the
				# country as well.
				countrypart="${1#*_}"
				countrypart="${countrypart%%[@.]*}"
				countryline="$(echo "$line" | grep ";$countrypart\$" || true)"
				if [ "$countryline" ]; then
					echo "${countryline%%;*}"
					return
				fi
			fi	
			echo "${line%%;*}"
		fi
	else
		echo "C"
	fi
}

locale2countrycode(){
	if [ -n "$1" ] ; then
		if echo $1 | grep -q "_"; then
			echo $1 | cut -f2 -d_ | cut -f1 -d@ | cut -f1 -d\.
		else
			echo
		fi
	else
		error "Missing argument"
	fi
}

locale2langcode(){
	if [ -n "$1" ] ; then
		if echo $1 | grep -q "_"; then
			echo "${1%%_*}"
		else
			echo
		fi
	else
		error "Missing argument"
	fi
}

# Reset all variables
LANGNAME=""
COUNTRY=""
COUTRYNAME=""
LOCALE=""
LANGUAGE=""

# BEGIN LANGUAGE SELECTION

# debconf/language is an alias for debian-installer/language
db_register "$languagecode" "debconf/language"

# Only display the translated texts (ie the English "translation")
# when in UTF-8 mode.
if echo $LANG $LC_CTYPE | grep -q UTF-8; then
	db_set debconf/language en
else
	db_set debconf/language C
fi

# Support preseeding of the locale all in one variable for convenience.
db_get $localecode
if [ "$RET" ] ; then
	LOCALE="$RET"
	log "Locale has been preseeded to $LOCALE"

	# Only mark variables seen if this one was preseeded seen.
	db_fget $localecode seen
	seenflag=$RET
	
	# Only populate debconf if this is a supported locale
	# and if the language is supported in D-I
	LANGUAGE=$(locale2langcode "$LOCALE")
	LANGNAME=$(locale2langname "$LOCALE" "$LANGUAGELISTFILE")
	if [ -n "$LANGNAME" ] ; then
		db_set ${langname_all} $LANGNAME
		log "Set ${langname_all} = '$LANGNAME'"
		db_fset ${langname_all} seen $seenflag || true
		COUNTRY=$(locale2countrycode "$LOCALE")
		if [ -n "$COUNTRY" ] ; then
			if grep -q "${LANGUAGE}_${COUNTRY}" $SHORTLISTS ; then
				db_set $shortlist-${LANGUAGE}_${COUNTRY} "$COUNTRY"
				log "Set $shortlist-${LANGUAGE}_${COUNTRY} = '$COUNTRY'"
				db_register $shortlist-${LANGUAGE}_${COUNTRY} $shortlist
				# cdebconf handles this as intended, but
				# debconf needs us to set the registered
				# question too.
				db_set $shortlist "$COUNTRY"
				db_fset $shortlist seen $seenflag || true
			elif grep -q "$LANGUAGE" $SHORTLISTS ; then
				db_set $shortlist-$LANGUAGE "$COUNTRY"
				log "Set $shortlist-$LANGUAGE = '$COUNTRY'"
				db_register $shortlist-$LANGUAGE $shortlist
				# cdebconf handles this as intended, but
				# debconf needs us to set the registered
				# question too.
				db_set $shortlist "$COUNTRY"
				db_fset $shortlist seen $seenflag || true
			fi
			db_fset $fulllist seen $seenflag || true
			if grep -q "$LOCALE" $SUPPORTEDLOCALES ; then
				db_set $localecode $LOCALE
				db_fset $localecode seen $seenflag || true
				log "Set $localecode = '$LOCALE'"
			else
				# The locale was invalid, empty it
				LOCALE=""
			fi
		else
			# The locale was invalid, empty it
			LOCALE=""
		fi
	fi
fi

# Find the display level
#
# No framebuffer and text interface      -->level 0 (only ASCII)
# No framebuffer and other interface     -->level 1 (only Latin1)
# Framebuffer and non graphical interface-->level 2 (no combining langs)
# Framebuffer and graphical interface    -->level 3 (all langs)
# Depending on these values, we use different templates with a different
# list of languages. These lists are built at the package build-time
# from the contents of the second field of languagelist entries
#
# We do this only when the language was not preseeded
# If the language was preseeded, we assume the user was 
# smart enough to preseed it to a supported value
# so the template uses all possible values
if [ -z "$LANGNAME" ] ; then
	log "Frontend in use: $DEBIAN_FRONTEND"
	case $DEBIAN_FRONTEND in
	    text)
		# Stricto-sensu, the text interface could use all languages
		# but it will most often be used in situation where the display
		# is "poor", so let's assume that only ASCII languages may be 
		# displayed, then
		template=${langname_ascii}
		;;
	    gtk)
		# We assume that the GTK interface handles all languages
		template=${langname_all}
		;;
	    *)
		# Only keep Latin1 languages if we don't have the framebuffer
		db_get debian-installer/framebuffer || true
		if [ "$RET" = "false" -o -z "$RET" ] ; then
			template=${langname_latin}
		else
			template=${langname_fb}
		fi
		# Try to detect serial consoles
		[ -f /lib/debian-installer/detect-console ] && . /lib/debian-installer/detect-console
		if [ "${TERM_TYPE}" = "serial" ] ; then
			template=${langname_ascii}	    
		fi
		# For cases we have a dumb terminal, we're stuck with ASCII
		if [ "${TERM}" = "dumb" ] ; then
			template=${langname_ascii}	    
		fi
		;;
	esac
else
	template=${langname_all}
fi
log "Language input template is $template"

db_input high $template || [ $? -eq 30 ]

if db_go; then
	db_get $template
	if [ "$RET" ] ; then
		LANGNAME="$RET"
		db_set ${langname_all} "$LANGNAME"
		. languagemap
		db_set "$languagecode" "$LANGUAGELIST"
		db_set "$localecode"   "$LOCALE"
		db_set "$fallbacklocalecode"   "$FALLBACKLOCALE"
 		db_set "$countrycode"  "$COUNTRY"
		db_set "$consoledisplay"  "$CONSOLE"
		log "Set $languagecode = '$LANGUAGELIST'"
		log "Set $localecode = '$LOCALE'"
		log "Set $fallbacklocalecode = '$FALLBACKLOCALE'"
		log "Set $countrycode = '$COUNTRY'"
		log "Set $consoledisplay = '$CONSOLE'"
	else
		# Error, not sure how to handle it
		:
	fi
else
	# Error, not sure how to handle it
	:
fi

db_set "debconf/language" "$LANGUAGELIST"
log "Set debconf/language = '$LANGUAGELIST'"

# Install specific packages depending on selected language
# Those we install here are those required immediately
# Otherwise we will install them in prebaseconfig
if [ "$LOCALE" != "C" ] ; then
	case "$LANGUAGE" in
		ar|el|fa|he|ja|ko|ku|tr|vi|wo|zh)
		# We need a complete font for later steps
		anna-install bterm-unifont
		;;
	esac
fi

# BEGIN COUNTRY SELECTION

# This is needed later in the script
COUNTRYCODE_LANGUAGECHOOSER=$COUNTRY
COUNTRY_LANGUAGECHOOSER=$(code2country $COUNTRY)
# Set correct default
db_set $fulllist "${COUNTRY_LANGUAGECHOOSER}"
log "Set $fulllist = '${COUNTRY_LANGUAGECHOOSER}'"

# Keep track of values we have after language selection step
LOCALE_LANGUAGECHOOSER=$LOCALE
LANGUAGECODE_LANGUAGECHOOSER=$LANGUAGE
# If present, keep track of charset or modifier we got previously
EXTRA_LANGUAGECHOOSER=`echo $FALLBACKLOCALE | sed -e 's/^[^.@]*//'`

FIRST_LANG="${LANGUAGELIST%%:*}"

# We use /etc/shortlists to check if we should present a shortlist
use_lang=""
if [ "$LOCALE" != "C" ] ; then
	if grep -q "^$FIRST_LANG" $SHORTLISTS; then
		use_lang=$FIRST_LANG
	elif grep -q "^$LANGUAGE" $SHORTLISTS; then
		use_lang=$LANGUAGE
	fi
fi

# At this step we should have either xx, or xx_YY in LANGNAME
STATE=1
LASTSTATE=3
fullprio=high
shortprio=high
LANGUAGE_CHANGED=
while [ "$STATE" != 0 -a "$STATE" -le "$LASTSTATE" ]; do
	case "$STATE" in
	    1)
		# If the locale includes a country, then
		# don't display the short list, and only show the
		# full list at medium priority.
		askedshort=0
		if echo $LOCALE | grep "_" >/dev/null 2>&1; then
			fullprio=medium
		else
			if [ "$use_lang" ]; then
				shortlist_template="$shortlist-$use_lang"
				db_register $shortlist_template $shortlist
				# Set the default
				db_fget $shortlist seen
				if [ "$RET" = false ]; then
					db_set $shortlist $COUNTRYCODE_LANGUAGECHOOSER
				fi
				db_input $shortprio $shortlist || [ $? -eq 30 ]
				askedshort=1
			fi
		fi
		;;
	    2)
		if [ "$askedshort" = 1 ] ; then
			db_get $shortlist
			if [ -n "$RET" ] && [ "$RET" != "other" ]; then
				COUNTRYCODE="$RET"
				break
			fi

			if [ "$LANGUAGE_CHANGED" ]; then
				break
			fi
		fi

		db_input $fullprio $fulllist || [ $? -eq 30 ]
		;;
	    3)
		db_get $fulllist
		COUNTRYCODE="$(country2code "$RET")" || true
		if [ -n "$COUNTRYCODE" ]; then
			break
		else
			# User probably selected a region
			STATE=2
			continue
		fi
		;;
	esac

	# When running under oem-config, the language may be changed
	# while asking the country question, so we have to
	# recalculate a few things. This would probably be
	# unnecessary if localechooser became one big state machine,
	# and would certainly be easier if it were possible to
	# change debconf's language on the fly.
	db_get "$langname_all"
	if [ "$RET" != "$LANGNAME" ]; then
		LANGNAME="$RET"
		unset LOCALE
		unset FALLBACKLOCALE
		unset LANGUAGE
		unset COUNTRY
		unset LANGUAGELIST
		. languagemap
		db_set "$languagecode" "$LANGUAGELIST"
		db_set "$localecode" "$LOCALE"
		db_set "$fallbacklocalecode" "$FALLBACKLOCALE"
		db_set "$countrycode" "$COUNTRY"
		COUNTRYCODE_LANGUAGECHOOSER="$COUNTRY"
		COUNTRY_LANGUAGECHOOSER="$(code2country "$COUNTRY")"
		db_set "$fulllist" "$COUNTRY_LANGUAGECHOOSER"
		LOCALE_LANGUAGECHOOSER="$LOCALE"
		LANGUAGECODE_LANGUAGECHOOSER="$LANGUAGE"
		EXTRA_LANGUAGECHOOSER="$(echo "$FALLBACKLOCALE" | sed -e 's/^[^.@]*//')"
		# Process the results of this INPUT, but then break.
		LANGUAGE_CHANGED=1
	fi

	if db_go; then
		STATE=$(($STATE + 1))
	else
		STATE=$(($STATE - 1))
	fi
done

if [ "$STATE" = 0 ]; then
	exit 10 # back out to main menu
fi
db_set "$countrycode"  "$COUNTRYCODE"
log "Set $countrycode = '$COUNTRYCODE'"


# DETERMINE DEFAULT LOCALE

# Find a supported locale which best fits the selected language and country.
# Locale refinement: we try to use the modifier inherited from language
# selection. However, we do this only if the locale is valid.
 
# No refinment if the locale was preseeded
if [ "$LOCALE" != "C" ] ; then 
	OLDLOCALE=$LOCALE
	LOCALE=""

	db_get $localecode
	if [ -z "$LOG" -o -z "$RET" ] ; then
		for entry in ${LANGUAGE}_${COUNTRYCODE}${EXTRA_LANGUAGECHOOSER} \
		             ${LANGUAGE}_${COUNTRYCODE}; do
			# Is the locale we inherited really a complete locale?
			LOCALE_LANGUAGECHOOSER_COMPLETE=$(echo $OLDLOCALE | grep "_" || true)
			if grep -q "^${entry}$" $SUPPORTEDLOCALES; then
				# Special handling of cases where the locale
				# in languagechooser is NOT the combination of
				# language_COUNTRY. Used for Norwegian
				# Bokmal transition in order to keep no_NO as
				# locale. May be used in the future for other
				# special cases, so we'd better keep this.
				if \
				    [ "$LANGUAGE" = "${LANGUAGECODE_LANGUAGECHOOSER}" \
				      -a \
				      "$COUNTRYCODE" = "${COUNTRYCODE_LANGUAGECHOOSER}" \
				      -a \
				      "${LANGUAGE}_${COUNTRYCODE}" != "$OLDLOCALE" \
				      -a \
				      -n "${LOCALE_LANGUAGECHOOSER_COMPLETE}" \
				    ] ;  then
					# Explanation: we revert back to the
					# locale inherited from the language
					# step if the country step did NOT
					# induce change in language and country
					# but the resulting locale is different
					# from the one we had in first step.
					LOCALE=$OLDLOCALE
				else
					LOCALE="${entry}"
				fi
				break
			fi
		done
	else
		# LOCALE was valid
		LOCALE=$OLDLOCALE
	fi
	
	# Fall back to a supported locale.
	if [ -z "${LOCALE}" ]; then
		if grep -q "^${FALLBACKLOCALE}$" $SUPPORTEDLOCALES; then
			LOCALE="$FALLBACKLOCALE"
		else
			LOCALE=`echo $FALLBACKLOCALE | sed -e 's/[.@].*$//'`
		fi
		log "Falling back to locale '$LOCALE'"
	fi
fi

# Set the locale.
db_set "$localecode" "$LOCALE"
log "Set $localecode = '$LOCALE'"

# The code below adds lang_COUNTRY at the beginning of the language
# list we got from languagechooser
# We shouldn't just add this before the former list in case the country 
# is changed several times.
if [ "$COUNTRYCODE" != "$COUNTRYCODE_LANGUAGECHOOSER" -a -n "$COUNTRYCODE" -a -n "$LANGUAGE" -a "$LOCALE" != "C" ]; then
	LANGUAGELIST=${LANGUAGE}_${COUNTRYCODE}:${LANGUAGELIST}
	# Languagelist setting
	db_set "$languagecode" "$LANGUAGELIST"
	log "Set $languagecode = '$LANGUAGELIST'"
fi


# SELECT ADDITIONAL LOCALES

# We will select from supported locales
# for LANGUAGE_COUNTRY
if [ "$LOCALE" != "C" ] ; then
	POSSIBLELOCALES=$(grep -e "^${LANGUAGE}_${COUNTRYCODE}" $SUPPORTEDLOCALES || true)
	if [ -z "$POSSIBLELOCALES" ] ; then
		POSSIBLELOCALES=$(grep -e "^${LANGUAGE}_${COUNTRYCODE_LANGUAGECHOOSER}" $SUPPORTEDLOCALES || true)
	fi
	if [ $(echo $POSSIBLELOCALES | wc -w) -gt 1 ] ; then
		CHOICES=""
		for i in $POSSIBLELOCALES ; do
			if [ -z "$CHOICES" ] ; then
				CHOICES=$i
			else
				CHOICES="$CHOICES, $i"
			fi
		done
		db_subst $localecode LOCALELIST "$CHOICES"
		db_input medium $localecode || [ $? -eq 30 ]
		if db_go ; then
			log "Locale set successfully"
		else
			exit 10
		fi
		db_get $localecode
		LOCALE="$RET"
	fi

	# Ask for additional locales to be generated
	CHOICES=
	# *.UTF-8@euro locales are deprecated; don't use them.
	for i in $(grep -v '\.UTF-8@euro$' $SUPPORTEDLOCALES | grep -v "^$LOCALE$"); do
		if [ -z "$CHOICES" ]; then
			CHOICES="$i"
		else
			CHOICES="$CHOICES, $i"
		fi
	done
	db_subst $supportedlocales LOCALELIST "$CHOICES"
	db_fget $supportedlocales seen
	if [ "$RET" = false ]; then
		# Always support English (unless preseeded otherwise), so that we
		# get English language packs etc.
		if [ "$LOCALE" = en_US.UTF-8 ]; then
			db_set $supportedlocales "$LOCALE"
		else
			db_set $supportedlocales "$LOCALE, en_US.UTF-8"
		fi
	fi
	db_input medium $supportedlocales || [ $? -eq 30 ]
	if db_go; then
		log "Supported locales successfully set"
	else
		exit 10
	fi
fi

exit 0
