#!/bin/ash
# choose locale for user
# Copyright (C) James Budiono 2012, 2014
# License: GNU GPL Version 3 or later
#
# 2014-01 L18L - localisation
#141202 omit territory in dialog, ex: German Germany. Now just: German de_DE.UTF - German locale for Germany
#141212 launch script $0.i18n for localizing desktop without need to RestartX
#141231 --no-cancel and move actual language to top of list
#200127 disable locale_to_top for now as it is not working correctly

export TEXTDOMAIN=fatdog

### configuration
APPTITLE="$(gettext 'Fatdog64 Locale Selector')"
SUPPORTED_GLIBC_LOCALES=/usr/share/i18n/SUPPORTED
LOCALE_DEF_DIR=/usr/share/i18n/locales
LOCALE_DIR=/usr/lib64/locale
LANG_CONFIG=$FATDOG_STATE_DIR/language	# read by /etc/profile and xwin
CACHE_DIR=/tmp/${0##*/}
CACHE_FILE=$CACHE_DIR/xdialog-cache
COUNT_FILE=$CACHE_DIR/count
FIXED_LOCALES_DIR=$CACHE_DIR/locales
WORKDIR=/tmp/${0##*/}.$$

# helper - create Xdialog treeview strings for all supported locales.
# this is an extra long pipeline - so cache this result for later
supported_locales_xdialog_helper() {
	local index p q src TI LN LA CN TE
	# use the simplified locale list, if it exists
	[ -e ${SUPPORTED_GLIBC_LOCALES}_simple ] && SUPPORTED_GLIBC_LOCALES=${SUPPORTED_GLIBC_LOCALES}_simple
	index=0
	while read -r p; do
		case $p in
			\#*|SUPPORTED*) ;;	# ignore these
			*)	# read the locale / charmap combination
				index=$(( index + 1))
				p=${p% \\}	# remove trailing space and backslash
				src=${p%%/*}; src=${src%%.*}

				# only process if we have the source file
				if [ -e $FIXED_LOCALES_DIR/$src ]; then
					# locale and charmaps
					echo -n "${p%%/*}|${p##*/}|"

					# read the source for title (description), language, and territory (country)
					LN='' CN=''
					while read -r q ; do
					case $q in
							%*) ;; # comment, ignore
							title*)        TI="\"${q#*\"}" ;;
							lang_name*)    LN="${q#*\"}"; LN="${LN%\"*} " ;;
							language*)     LA="${q#*\"}"; LA="${LA%\"*}" ;;
							country_name*) CN="${q#*\"}"; CN="${CN%\"*} " ;;
							territory*)    TE="${q#*\"}"; TE="${TE%\"*}" ;;
						esac
					done < $FIXED_LOCALES_DIR/$src
					[ "$LA" = "${LN% }" ] && LN='' #avoid "Afrikaans Afrikaans"
					[ "$TE" = "${CN% }" ] && CN='' #avoid "Bulgaria Bulgaria"
					echo "${TI}|\"${LN}${LA}\"|\"${CN}${TE}\""
				fi
				;;
		esac
	done < $SUPPORTED_GLIBC_LOCALES | tr -d '"' |
	awk -F"|" -v OFS="|" '
	# rearrange columns
	# input:  locale  |charmap |title  |language|territory
	#         $1       $2       $3      $4       $5
	# output: language|country |locale |charmap |description
	{ print   $4,      $5,      $1,     $2,      $3}' |
	sort -f |
	#tee /dev/tty | # debug
	awk -F"|" '#{{{awk
	# format for Xdialog tree widget
	# output: language | locale, "off"(set), 0(language) | 1(locale)
	# input:  language |country |locale |charmap |description
	#         $1        $2       $3      $4       $5
	{
		if ( $1 != language ) { # enter new language for new countries
			language=$1
			country=""
			off0 = sprintf("\"%s\" \"%s\" off 0", language, language)
			if ( ! Out[off0] ) {
				Out[off0] = Off0[++nOff0] = off0
			}
		}
		Out[off0] = sprintf("%s\n\"%s+%s\" \"%s - %s\" off 1", Out[off0], $3, $4, $3, $5)
	}
	END {
		for ( i = 1; i <= nOff0; i++ ) {
			print Out[Off0[i]]
		}
	}
	#awk}}}'
}

###
build_xdialog_cache() {
	local count=0 files=0 p

	[ -e $COUNT_FILE ] && read count < $COUNT_FILE &&
	files=$(ls -l $LOCALE_DEF_DIR | wc -l)
	if
		# the number of system source files didn't change
		[  $files -eq $count ] &&
		# no system or cached source file is newer than the xdialog cache file
		[ -e $CACHE_FILE ] &&
			! [ "$(find $LOCALE_DEF_DIR $FIXED_LOCALES_DIR -newer $CACHE_FILE -print -quit)" ]
	then
		# xdialog cache is valid as is
		return
	fi

	# update the source file count and build a new cache
	echo $files > $COUNT_FILE
	rm -f $FIXED_LOCALES_DIR/*

	# it will be long, tell user to wait
	Xdialog --no-buttons --title "$APPTITLE" \
	--infobox "$(gettext 'Please wait, computing available locales.')" 0 0 1000000 &
	XPID=$!

	# fix locale files - add missing lang_name
	mkdir -p $WORKDIR/bad $WORKDIR/good $WORKDIR/locales

	# copy files & separate those that have langnames from those that don't
	find $LOCALE_DEF_DIR -type f -print0 | xargs -0 grep -l ^lang_name | xargs cp -t $WORKDIR/good
	find $LOCALE_DEF_DIR -type f -print0 | xargs -0 grep -L ^lang_name | xargs cp -t $WORKDIR/bad
	find $WORKDIR \( -name 'iso*' -o -name 'translit*' -o -name 'i18n' -o -name 'POSIX' \) -delete
	#find $WORKDIR -type f

	# for every locale file that don't have langnames, try to find a sensible one
	ls $WORKDIR/bad | while read -r p; do
		lang_name=$(grep -m1 ^lang_name $WORKDIR/good/${p%%_*}_* 2> /dev/null)
		case "$lang_name" in
			*FIXME*|"") cp $WORKDIR/bad/"$p" $WORKDIR/locales ;; # can't do anything, too bad
			*) { cat $WORKDIR/bad/"$p"; echo "$lang_name"; } > $WORKDIR/locales/"$p" ;;
		esac
	done

	# copy the rest of the good files
	cp $WORKDIR/good/* $WORKDIR/locales
	#ls $WORKDIR/locales

	# special treatment
	[ -w $WORKDIR/locales/ht_HT ] && sed -i -e 's#language   "U006Breyol"#language   "Kreyol"#' $WORKDIR/locales/ht_HT
	for p in $WORKDIR/locales/nl_*; do
		[ -w "$p" ] && sed -i -e 's#lang_name "<U0064><U0075><U0074><U0063><U0068>"#lang_name "Nederlands"#' "$p"
	done

	# convert UCS to UTF, join lines split by /
	sed -i -e ':x; /\/$/ { N; s/\/\n//; tx }' $WORKDIR/locales/*
	ls $WORKDIR/locales | while read -r p; do
		show-ucs-data $WORKDIR/locales/"$p" > $FIXED_LOCALES_DIR/"$p"
	done
	rm -rf $WORKDIR

	# generate Xdialog strings
	supported_locales_xdialog_helper > $CACHE_FILE
	kill $XPID
}

# L18L: $1-locale to move to top
# Prints the locale moved to top
locale_to_top()
{
    # Trim .* just in case we're passed a full $LANG instead of its head,
    # which we losely refer to as the "locale".
    local pp=${1%.*}
    echo move LOCALE $pp to top of list >&2

    # select locale pp's cached entries including their language label (-B 1),
    # which occurs exactly once.
    grep -B 1 "^\"${pp}\." $CACHE_FILE > $CACHE_FILE.$pp

    # erase lines in pp's cache from the global cache
    awk '#{{{awk
    # Learn erase patterns
    FILENAME == ARGV[1] { Erase[$0] = 1; next }
    # Filter out Erase patterns
    FILENAME == ARGV[2] { if ( !($0 in Erase) ) print }
    #awk}}}' $CACHE_FILE.$pp $CACHE_FILE > $CACHE_FILE.not.$pp

    cat $CACHE_FILE.$pp $CACHE_FILE.not.$pp > $CACHE_FILE
    rm $CACHE_FILE.$pp $CACHE_FILE.not.$pp
    echo $pp
}

# L18L: move current locale to top [ $1-default-locale ]
actual_locale_to_top()
{
    local pp=${LANG:-$1} # $LANG, if set, takes precedence over "en_US"
    [ -r "$LANG_CONFIG" ] && read pp < "$LANG_CONFIG" # $LANG_CONFIG overrides both
    #locale_to_top ${pp%.*} ## disable for now - this does not work correctly
    echo ${pp%.*}
}


### main ###

mkdir -p $FIXED_LOCALES_DIR
build_xdialog_cache

# edit xdialog cache to move the currently selected language block to the top of the file.
# If current language isn't initialized fall back to default "en_US".
# IMPORTANT: since Fatdog64-800 you must pass "en_US" not just "en".
CURRENT_LOCALE=$(actual_locale_to_top en_US)

CURR_LOCALE_TEXT="\
$(eval echo $(gettext 'Current locale is ${CURRENT_LOCALE}') ) \n
$(awk -F\" '/^title/ {print $2}' $FIXED_LOCALES_DIR/$CURRENT_LOCALE 2>/dev/null)"

if ! [ $? = 0 ] || ! locale -a | grep -qm1 "$CURRENT_LOCALE" 2>/dev/null; then
	CURR_LOCALE_TEXT="$CURR_LOCALE_TEXT \n
	$(eval echo $(gettext '!!! Locale ${CURRENT_LOCALE} is disabled or missing !!!') )"
fi

# --treeview <text> <height> <width> <list height> <tag1> <item1> <status1> <item_depth1> {<help1>}
if selection=$(eval Xdialog --stdout --title \"$APPTITLE\" \
	       --backtitle \" $CURR_LOCALE_TEXT \" \
	       --treeview \"$(gettext 'Select your locale')\" 20 80 5 $([ -s $CACHE_FILE ] && cat $CACHE_FILE || echo '"" "" off 0' ) ); then
	locale=${selection%+*}; source=${locale%.*}
	charmap=${selection#*+}
	#echo $locale $source $charmap
	case $selection in *+*) ;; *)
		Xdialog --title "$APPTITLE" --infobox "$(gettext 'You need to choose the specific locale; not only the language or the country.')" 0 0 10000
		exec "$0"
	esac

	locale_dir=$(echo $locale | sed 's/UTF-8/utf8/')
	if [ ! -e $LOCALE_DIR/$locale_dir ]; then
		# locale not yet compiled, need to generate it
		if [ $(id -u) -ne 0 ]; then gtksu "$(gettext 'Create new locale definition')" localedef -f $charmap -i $source --no-archive $locale
		else localedef -f $charmap -i $source --no-archive $locale
		fi

		# check that it is actually created now, only if it is we set the locale
		if [ $? -eq 0 ]; then
			echo $locale > $LANG_CONFIG; ok=ok
		fi
	else
		echo $locale > $LANG_CONFIG; ok=ok
	fi
fi

if [ $ok ]; then
    [ -r ${0}.i18n ] && . ${0}.i18n # 141212 - run this file if it exists.
    [ -z $NO_RESTART ] && # if set, don't ask and don't restart
	Xdialog --title "$APPTITLE" --yesno "
$(eval echo $(gettext 'Your new locale will be set to $locale after you restart X server.'))
$(eval echo $(gettext 'Locale configuration is stored in $LANG_CONFIG.'))\n\n
$(gettext 'Do you want to restart X server now?')
" 0 0 && wmexit restart
else
	Xdialog --title "$APPTITLE" --infobox "$(gettext 'Cancelled, nothing is changed.')" 0 0 10000
fi

