#!@BASH@
#
# babelize -- this is the complex game localization utility.
#
# Copyright (c) 2003-2007 Maik Broemme <mbroemme@plusserver.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# $Id$

# @_babelize__printf()
#
# @_${1}: text string
#
# this function shows something on stdout ;)
function babelize__printf() {

	# echo to stdout.
	echo -e "${@}"

	# if no error was found, return zero.
	return 0
}

# @_babelize__signal_handler()
#
# function for signal handling.
function babelize__signal_handler() {

	# cleaning up /tmp.
	[ -n "${BABELIZE_LANGPACK_REFERENCE}" ] && [ -d "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}" ] && @RM@ -R "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}"

	# if no error was found, return zero.
	return 0
}

# @_babelize__show_header()
#
# this function shows the header.
function babelize__show_header() {

	# show the main script version.
	babelize__printf "${BABELIZE_PROCESS_NAME} (native-ports) ${BABELIZE_VERSION} ${BABELIZE_RELEASE}"
	babelize__printf "Written by ${BABELIZE_AUTHOR}"

	# if no error was found, return zero.
	return 0
}

# @_babelize__show_footer()
#
# this function shows the footer.
function babelize__show_footer() {

	# show some useful copyright information.
	babelize__printf "This is free software; see the source for copying conditions.  There is NO"
	babelize__printf "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."

	# if no error was found, return zero.
	return 0
}

# @_babelize__validate_langpack()
#
# @_${1}: language pack
#
# this function checks if the language pack is valid.
function babelize__validate_langpack() {

	# first check if the archive exist.
	[ -e "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1}" ] && {

		# third check if the config file exist.
		[ -e "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1/tar.gz/conf}" ] && {

			# now try to load the config file.
			source "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1/tar.gz/conf}" || {

				# show user what we do.
				babelize__printf "The given config file '${1/tar.gz/conf}' seems to be corrupt"

				# the config file is corrupt, break execution.
				return 1
			}
		} || {

			# show user what we do.
			babelize__printf "The given langpack config '${1/tar.gz/conf}' does not exist."

			# the config file is missing, break execution.
			return 1
		}
	} || {

		# show user what we do.
		babelize__printf "The given langpack archive '${1}' does not exist."

		# the archive file is missing, break execution.
		return 1
	}

	# if no error was found, return zero.
	return 0
}

# @_babelize__validate_gameroot()
#
# @_${1}: game directory
#
# this function checks if a given gameroot directory exist.
function babelize__validate_gameroot() {

	# check if the gameroot exist.
	[ -d "${1}" ] || {

		# show user what we do.
		babelize__printf "The gameroot directory '${1}' does not exist."

		# the gameroot directory did not exist, break execution.
		return 1
	}

	# if no error was found, return zero.
	return 0
}

# @_babelize__validate_cdpath()
#
# @_${1}: cd directories
#
# this function checks if a given cdpath directory exist.
function babelize__validate_cdpath() {

	# loop through all directories.
	local LOCAL__directory
	for LOCAL__directory in "${@}" ; do

		# check if the cdpath exist.
		[ -d "${LOCAL__directory}" ] || {

			# show user what we do.
			babelize__printf "The cdpath directory '${LOCAL__directory}' does not exist."

			# the gameroot directory did not exist, break execution.
			return 1
		}
	done

	# if no error was found, return zero.
	return 0
}

# @_babelize__validate_diskspace()
#
# @_${1}: language pack
#       
# this function checks if enough diskspace is available for extracting language pack.
function babelize__validate_diskspace() {

	# check if we have enough diskspace.
	local LOCAL__diskspace=$(($(@STAT@ -f --format %f "${LANGPACK_EXTRACT_DIR:-/tmp}") * $(/usr/bin/stat -f --format %s "${LANGPACK_EXTRACT_DIR:-/tmp}")))
	local LOCAL__filesize=$(($(@STAT@ --format %s "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1}") + $(@STAT@ --format %s "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1}") / 100 * 5))

	# check if filesize plus 5% is smaller than diskspace
	[ "$((${LOCAL__filesize} + ${LOCAL__filesize} / 100 * 5))" -ge "${LOCAL__diskspace}" ] && {

		# show user what we do.
		babelize__printf "The diskspace '${LOCAL__diskspace}' is less than required diskspace '$((${LOCAL__filesize} + ${LOCAL__filesize} / 100 * 5))'"

		# the diskspace is not enough, break execution.
		return 1
	}

        # if no error was found, return zero.
        return 0
}

# @_babelize__validate_version()
#
# this function checks if the used babelize version is correct.
function babelize__validate_version() {

	# check if all required variables were exported.
	{
		set | @GREP@ -q ^BABELIZE_REQUIRED_VERSION &&
		set | @GREP@ -q ^BABELIZE_GAME_NAME &&
		set | @GREP@ -q ^BABELIZE_LANGKACK_VERSION &&
		set | @GREP@ -q ^BABELIZE_LANGPACK_LANGUAGE &&
		set | @GREP@ -q ^BABELIZE_LANGPACK_LOCALE &&
		set | @GREP@ -q ^BABELIZE_LANGPACK_REFERENCE &&
		set | @GREP@ -q ^BABELIZE_FILES
	} || return 1

	# check if the babelize version is known to work with that langpack version.
	[[ "${BABELIZE_REQUIRED_VERSION}" > "${BABELIZE_VERSION}" ]] && {

		# show user what we do.
		babelize__printf "Your babelize version is to old, please upgrade it to at least '${BABELIZE_REQUIRED_VERSION}'"

		# skip to next file if version number is to high.
		return 1
	}

	# if no error was found, return zero.
	return 0
}

# @_babelize__list_langpacks()
#
# this function shows the installed langpacks.
function babelize__list_langpacks() {

	# first check if the langpack directory exist.
	[ ! -d "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}" ] && {

		# show user the error.
		babelize__printf "The langpack directory '${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}' does not exist."

		# something wents wrong, so break execution.
		return 1
	}

	# prepare header.
	babelize__printf ""

	# search for langpacks.
	local LOCAL__file
	for LOCAL__file in $(@FIND@ "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}" -mindepth 1 -maxdepth 1 -type f -name \*.tar.gz | sort) ; do

		# check if the config file exist.
		[ -e "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/$(@BASENAME@ ${LOCAL__file/tar.gz/conf})" ] && {

			# now try to load the config file.
			source "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/$(@BASENAME@ ${LOCAL__file/tar.gz/conf})" || {

				# skip to next file.
				continue
			}
		}

		# now check if all required variables were exported.
		{
			set | @GREP@ -q ^BABELIZE_REQUIRED_VERSION &&
			set | @GREP@ -q ^BABELIZE_GAME_NAME &&
			set | @GREP@ -q ^BABELIZE_LANGKACK_VERSION &&
			set | @GREP@ -q ^BABELIZE_LANGPACK_LANGUAGE &&
			set | @GREP@ -q ^BABELIZE_LANGPACK_LOCALE &&
			set | @GREP@ -q ^BABELIZE_LANGPACK_REFERENCE &&
			set | @GREP@ -q ^BABELIZE_FILES
		} || {

			# skip to next file.
			continue
		}

		# if the archive exist, show user collected information.
		babelize__printf "[${BABELIZE_LANGPACK_REFERENCE}-${BABELIZE_LANGPACK_LOCALE}]"
		babelize__printf ""

		# check if the babelize version is known to work with that langpack version.
		[[ "${BABELIZE_REQUIRED_VERSION}" > "${BABELIZE_VERSION}" ]] && {

			# babelize version needs to be upgraded before using that language pack.
			babelize__printf "  Required Babelize:\t${BABELIZE_REQUIRED_VERSION} (${BABELIZE_VERSION} found) - UPDATE REQUIRED"
		} || {

			# babelize version is good for that language pack.
			babelize__printf "  Required Babelize:\t${BABELIZE_REQUIRED_VERSION} (${BABELIZE_VERSION} found)"
		}

		babelize__printf "  Game name:\t\t${BABELIZE_GAME_NAME}"
		babelize__printf "  Langpack version:\t${BABELIZE_LANGKACK_VERSION}"
		babelize__printf "  Langpack language:\t${BABELIZE_LANGPACK_LANGUAGE}"
		babelize__printf "  Langpack archive:\t$(@BASENAME@ ${LOCAL__file})"
		babelize__printf ""

		# unset variable, maybe next language pack is missing one.
		unset BABELIZE_REQUIRED_VERSION
		unset BABELIZE_GAME_NAME
		unset BABELIZE_LANGKACK_VERSION
		unset BABELIZE_LANGPACK_LANGUAGE
		unset BABELIZE_LANGPACK_LOCALE
		unset BABELIZE_LANGPACK_REFERENCE
		unset BABELIZE_FILES

		# create marker, that we found at least one working language pack.
		local LOCAL__found="${LOCAL__file}"
	done

	# check if we found any langpack.
	[ -z "${LOCAL__found}" ] && {

		# show user the error.
		babelize__printf "No available langpacks in '${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}' were found."

		# something wents wrong, so break execution.
		return 1
	}

	# if no error was found, return zero.
	return 0
}

# @_babelize__remove()
#
# @_${1}: language pack
# @_${2}: game directory
#
# this function removes files from previous localization.
function babelize__remove() {

	# first check if the archive exist.
	babelize__validate_langpack "${1}" || return 1

	# second check if the gameroot exist.
	babelize__validate_gameroot "${2}" || return 1

	# third check if babelize version is correct.
	babelize__validate_version || return 1

	# show user what we do.
	babelize__printf "Cleaning up '${2}'"

	# loop through all files and build new file array without duplicates.
	declare -a LOCAL__files=()
	local LOCAL__line
	for LOCAL__line in "${BABELIZE_FILES[@]}" ; do

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:*action:create-make*|\
			md5:*action:xdelta-copy*|\
			md5:*action:xdelta-make*)

				# loop through new file array and look if member already included.
				local LOCAL__file
				for LOCAL__file in "${LOCAL__files[@]##*target:}" ; do

					# check if member is already included.
					[ "${LOCAL__file}" == "${LOCAL__line##*target:}" ] && {

						# continue outer loop, because member is already included.
						continue 2
					}
				done

				# add file member to new array.
				LOCAL__files[${#LOCAL__files[@]}]="${LOCAL__line}"
			;;
			*)

				# nothing to do.
				continue
			;;
		esac
	done

	# loop through all files and remove the selected files.
	local LOCAL__line
	for LOCAL__line in "${LOCAL__files[@]}" ; do

		# fetch target information.
		local LOCAL__target="${LOCAL__line##*target:}"

		# check if the file exist.
		[ -e "${2}/${LOCAL__target}" ] && {

			# show user what we do.
			babelize__printf "Removing file '${2}/${LOCAL__target}'"

			# remove old file.
			@RM@ "${2}/${LOCAL__target}"
		}
	done

	# if no error was found, return zero.
	return 0
}

# @_babelize__restore()
#
# @_${1}: language pack
# @_${2}: game directory
# @_${3}: cd directories
#
# this function restores a specific game.
function babelize__restore() {

	# first check if the archive exist.
	babelize__validate_langpack "${1}" || return 1

	# second check if the gameroot exist.
	babelize__validate_gameroot "${2}" || return 1

	# third check if babelize version is correct.
	babelize__validate_version || return 1

	# the array which stores the cd paths.
	declare -a LOCAL__directories=()

	# loop through all cd paths and build the array.
	while [ "${#LOCAL__directories[@]}" == "0" ] || [ "${3##*,}" != "${LOCAL__directories[$((${#LOCAL__directories[@]} - 1))]}" ] ; do

		# check if it is the first loop.
		[ "${#LOCAL__directories[@]}" == "0" ] && {
			local LOCAL__directory="${3#*${LOCAL__directory}}"
			local LOCAL__directory="${LOCAL__directory%%,*}"
		} || {
			local LOCAL__directory="${3#*${LOCAL__directory},}"
			local LOCAL__directory="${LOCAL__directory%%,*}"
		}

		# add the directory to the array.
		declare -a LOCAL__directories[${#LOCAL__directories[@]}]="${LOCAL__directory}"
	done

	# first check if the cdpath exist.
	babelize__validate_cdpath "${LOCAL__directories[@]}" || return 1

	# loop through all files and build new file array without duplicates.
	declare -a LOCAL__files=()
	local LOCAL__line
	for LOCAL__line in "${BABELIZE_FILES[@]}" ; do

		# loop through new file array and look if member already included.
		local LOCAL__file
		for LOCAL__file in "${LOCAL__files[@]##*target:}" ; do

			# check if member is already included.
			[ "${LOCAL__file}" == "${LOCAL__line##*target:}" ] && {

				# continue outer loop, because member is already included.
				continue 2
			}
		done

		# add file member to new array.
		LOCAL__files[${#LOCAL__files[@]}]="${LOCAL__line}"
	done

	# declare an empty array for the cd files.
	declare -a LOCAL__cds=()

	# loop through all files and build new array (files).
	local LOCAL__line
	local LOCAL__count
	for LOCAL__line in "${LOCAL__files[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:*cd:0*)

				# media zero is a special case, file is created first with an official game update.
				continue
			;;
			md5:*action:create-make*|\
			md5:*action:xdelta-copy*|\
			md5:*source:archive:*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# check if the array element is unassigned.
				[ -z "${LOCAL__cds[$((${LOCAL__cd} - 1))]}" ] && {

					# create empty array element.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]=""
				}
			;;
			*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# create new array.
				[ "${#LOCAL__cds[@]}" -lt "${LOCAL__cd}" ] && {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[${#LOCAL__cds[@]}]="$((${LOCAL__count} - 1))"
				} || {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]="${LOCAL__cds[$((${LOCAL__cd} - 1))]} $((${LOCAL__count} - 1))"
				}
			;;
		esac
	done

	# unset used variables.
	unset LOCAL__line
	unset LOCAL__count

	# show user what we do.
	babelize__printf "Copying files..."

	# loop through all media.
	local LOCAL__cd
	local LOCAL__count
	for LOCAL__cd in "${LOCAL__cds[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"
		local LOCAL__media="${LOCAL__count}"

		# check if we should copy something from that media.
		[ -n "${LOCAL__cd}" ] && {

			# show user what we do.
			babelize__printf "Processing media '${LOCAL__count}'"

			# loop through the media references.
			local LOCAL__index
			for LOCAL__index in ${LOCAL__cd} ; do

				# fetch line from index.
				local LOCAL__line="${LOCAL__files[${LOCAL__index}]}"

				# fetch source information.
				local LOCAL__source="${LOCAL__line##*source:}"
				local LOCAL__source="${LOCAL__source%%  *}"

				# fetch permission information.
				local LOCAL__mode="${LOCAL__line##*mode:}"
				local LOCAL__mode="${LOCAL__mode%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# loop until user breaks execution or right media was found.
				while [ true ] ; do

					# check if file exist.
					[ -r "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}" ] || {

						# check if we are on a media index which is higher than the maximum number of media specified on command line.
						[ "${LOCAL__count}" -gt "${#LOCAL__directories[@]}" ] && local LOCAL__count="$((${LOCAL__count} - 1))"

						# interactive mode.
						echo -n "Please insert cd/dvd '${LOCAL__media}' to '${LOCAL__directories[$((${LOCAL__count} - 1))]}' continue (Y/n) "
						read

						# check answer.
						case "${REPLY}" in
							n|N)

								# user requested abort.
								return 1
							;;
							*)

								# continue loop and check if right media was inserted on next loop.
								continue
							;;
						esac
					}

					# break execution, because file was found.
					break
				done

				# show user what we do.
				babelize__printf "Copying original file '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}' -> '${2}/${LOCAL__target}'"

				# check if destination directory exist.
				[ -d "${2}/$(@DIRNAME@ "${LOCAL__target}")" ] || {

					# create directory for destination files.
					@MKDIR@ -p "${2}/$(@DIRNAME@ "${LOCAL__target}")"
				}

				# copy the file from cd.
				@CP@ "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The file '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}' could not be copied, maybe a file permission problem?"

					# break execution, if file is corrupt.
					return 1
				}

				# change file permissions.
				@CHMOD@ "${LOCAL__mode}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The permissions of file '${2}/${LOCAL__target}' could not be changed, maybe a strange problem?"

					# break execution, if file is corrupt.
					return 1
				}
			done
		}
	done

	# unset used variables.
	unset LOCAL__cd
	unset LOCAL__count

	# declare an empty array for the cd files.
	declare -a LOCAL__cds=()

	# loop through all files and build new array (archives).
	local LOCAL__line
	local LOCAL__count
	for LOCAL__line in "${LOCAL__files[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:*cd:0*)

				# media zero is a special case, file is created first with an official game update.
				continue
			;;
			md5:*action:create-make*|\
			md5:*action:xdelta-copy*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# check if the array element is unassigned.
				[ -z "${LOCAL__cds[$((${LOCAL__cd} - 1))]}" ] && {

					# create empty array element.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]=""
				}
			;;
			md5:*source:archive:*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# create new array.
				[ "${#LOCAL__cds[@]}" -lt "${LOCAL__cd}" ] && {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[${#LOCAL__cds[@]}]="$((${LOCAL__count} - 1))"
				} || {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]="${LOCAL__cds[$((${LOCAL__cd} - 1))]} $((${LOCAL__count} - 1))"
				}
			;;
		esac
	done

	# unset used variables.
	unset LOCAL__line
	unset LOCAL__count

	# show user what we do.
	babelize__printf "Extracting files..."

	# loop through all media.
	local LOCAL__cd
	local LOCAL__count
	for LOCAL__cd in "${LOCAL__cds[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"
		local LOCAL__media="${LOCAL__count}"

		# check if we should extract something from that media.
		[ -n "${LOCAL__cd}" ] && {

			# declare an empty array for the archives.
			declare -a LOCAL__archives=()

			# show user what we do.
			babelize__printf "Processing media '${LOCAL__count}'"

			# loop through the media references.
			local LOCAL__index
			for LOCAL__index in ${LOCAL__cd} ; do

				# fetch line from index.
				local LOCAL__line="${LOCAL__files[${LOCAL__index}]}"

				# fetch archive information.
				local LOCAL__archive="${LOCAL__line##*archive:}"
				local LOCAL__archive="${LOCAL__archive%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# check if it is the first element.
				[ "${LOCAL__archive[*]/${LOCAL__archive}/}" == "${LOCAL__archives[*]}" ] && {

					# build the archive filelist.
					declare -a LOCAL__archives[${#LOCAL__archives[@]}]="${LOCAL__archive} ${LOCAL__target}"
				} || {

					# build the archive filelist.
					declare -a LOCAL__archives=("${LOCAL__archives[@]/${LOCAL__archive}/${LOCAL__archive} ${LOCAL__target}}")
				}
			done

			# loop through all archives.
			local LOCAL__package
			for LOCAL__package in "${LOCAL__archives[@]}" ; do

				# fetch archive information.
				local LOCAL__archive="${LOCAL__package%% *}"

				# fetch file information.
				local LOCAL__filelist="${LOCAL__package#* }"

				# loop until user breaks execution or right media was found.
				while [ true ] ; do

					# check if archive exist.
					[ -r "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__archive}" ] || {

						# check if we are on a media index which is higher than the maximum number of media specified on command line.
						[ "${LOCAL__count}" -gt "${#LOCAL__directories[@]}" ] && local LOCAL__count="$((${LOCAL__count} - 1))"

						# interactive mode.
						echo -n "Please insert cd/dvd '${LOCAL__media}' to '${LOCAL__directories[$((${LOCAL__count} - 1))]}' continue (Y/n) "
						read

						# check answer.
						case "${REPLY}" in
							n|N)

								# user requested abort.
								return 1
							;;
							*)

								# continue loop and check if right media was inserted on next loop.
								continue
							;;
						esac
					}

					# break execution, because file was found.
					break
				done

				# show user what we do.
				babelize__printf "Extracting from file '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__archive}'"

				# check what compression was used.
				case "${LOCAL__archive}" in
					*.tar.gz)

						# extract the file from the archive.
						@TAR@ xzf "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__archive}" -v -C "${2}" ${LOCAL__filelist}
					;;
					*)

						# unknown compression method.
						babelize__printf "The compression method for archive '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__archive}' is unknown."

						# return with error.
						return 1
					;;
				esac

				# set right permission on extracted files.
				local LOCAL__file
				for LOCAL__file in ${LOCAL__filelist} ; do

					# fetch permission information.
					local LOCAL__mode="${LOCAL__line##*mode:}"
					local LOCAL__mode="${LOCAL__mode%%  *}"

					# change file permissions.
					@CHMOD@ "${LOCAL__mode}" "${2}/${LOCAL__file}" || {

						# show user what we do.
						babelize__printf "The permissions of file '${2}/${LOCAL__file}' could not be changed, maybe a strange problem?"

						# break execution, if file is corrupt.
						return 1
					}
				done
			done
		}
	done

	# unset used variables.
	unset LOCAL__cd
	unset LOCAL__count

	# if no error was found, return zero.
	return 0
}

# @_babelize__extra()
#
# @_${1}: language pack
# @_${2}: game directory
# @_${3}: cd directories
#
# this function copies extra files for a specific game.
function babelize__extra() {

	# first check if the archive exist.
	babelize__validate_langpack "${1}" || return 1

	# second check if the gameroot exist.
	babelize__validate_gameroot "${2}" || return 1

	# third check if babelize version is correct.
	babelize__validate_version || return 1

	# the array which stores the cd paths.
	declare -a LOCAL__directories=()

	# loop through all cd paths and build the array.
	while [ "${#LOCAL__directories[@]}" == "0" ] || [ "${3##*,}" != "${LOCAL__directories[$((${#LOCAL__directories[@]} - 1))]}" ] ; do

		# check if it is the first loop.
		[ "${#LOCAL__directories[@]}" == "0" ] && {
			local LOCAL__directory="${3#*${LOCAL__directory}}"
			local LOCAL__directory="${LOCAL__directory%%,*}"
		} || {
			local LOCAL__directory="${3#*${LOCAL__directory},}"
			local LOCAL__directory="${LOCAL__directory%%,*}"
		}

		# add the directory to the array.
		declare -a LOCAL__directories[${#LOCAL__directories[@]}]="${LOCAL__directory}"
	done

	# first check if the cdpath exist.
	babelize__validate_cdpath "${LOCAL__directories[@]}" || return 1

	# loop through all files and build new file array without duplicates.
	declare -a LOCAL__files=()
	local LOCAL__line
	for LOCAL__line in "${BABELIZE_FILES[@]}" ; do

		# loop through new file array and look if member already included.
		local LOCAL__file
		for LOCAL__file in "${LOCAL__files[@]##*target:}" ; do

			# check if member is already included.
			[ "${LOCAL__file}" == "${LOCAL__line##*target:}" ] && {

				# continue outer loop, because member is already included.
				continue 2
			}
		done

		# add file member to new array.
		LOCAL__files[${#LOCAL__files[@]}]="${LOCAL__line}"
	done

	# declare an empty array for the cd files.
	declare -a LOCAL__cds=()

	# loop through all files and build new array (files).
	local LOCAL__line
	local LOCAL__count
	for LOCAL__line in "${LOCAL__files[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:*cd:0*)

				# media zero is a special case, file is created first with an official game update.
				continue
			;;
			md5:*action:create-make*|\
			md5:*action:xdelta-make*|\
			md5:*source:archive:*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# check if the array element is unassigned.
				[ -z "${LOCAL__cds[$((${LOCAL__cd} - 1))]}" ] && {

					# create empty array element.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]=""
				}
			;;
			*)

				# fetch cd information.
				local LOCAL__cd="${LOCAL__line##*cd:}"
				local LOCAL__cd="${LOCAL__cd%%  *}"

				# create new array.
				[ "${#LOCAL__cds[@]}" -lt "${LOCAL__cd}" ] && {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[${#LOCAL__cds[@]}]="$((${LOCAL__count} - 1))"
				} || {

					# build the filelist based on cd number.
					declare -a LOCAL__cds[$((${LOCAL__cd} - 1))]="${LOCAL__cds[$((${LOCAL__cd} - 1))]} $((${LOCAL__count} - 1))"
				}
			;;
		esac
	done

	# unset used variables.
	unset LOCAL__line
	unset LOCAL__count

	# show user what we do.
	babelize__printf "Copying files..."

	# loop through all media.
	local LOCAL__cd
	local LOCAL__count
	for LOCAL__cd in "${LOCAL__cds[@]}" ; do

		# increase array index counter.
		local LOCAL__count="$((${LOCAL__count} + 1))"
		local LOCAL__media="${LOCAL__count}"

		# check if we should copy something from that media.
		[ -n "${LOCAL__cd}" ] && {

			# show user what we do.
			babelize__printf "Processing media '${LOCAL__count}'"

			# loop through the media references.
			local LOCAL__index
			for LOCAL__index in ${LOCAL__cd} ; do

				# fetch line from index.
				local LOCAL__line="${LOCAL__files[${LOCAL__index}]}"

				# fetch source information.
				local LOCAL__source="${LOCAL__line##*source:}"
				local LOCAL__source="${LOCAL__source%%  *}"

				# fetch permission information.
				local LOCAL__mode="${LOCAL__line##*mode:}"
				local LOCAL__mode="${LOCAL__mode%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# loop until user breaks execution or right media was found.
				while [ true ] ; do

					# check if file exist.
					[ -r "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}" ] || {

						# check if we are on a media index which is higher than the maximum number of media specified on command line.
						[ "${LOCAL__count}" -gt "${#LOCAL__directories[@]}" ] && local LOCAL__count="$((${LOCAL__count} - 1))"

						# interactive mode.
						echo -n "Please insert cd/dvd '${LOCAL__media}' to '${LOCAL__directories[$((${LOCAL__count} - 1))]}' continue (Y/n) "
						read

						# check answer.
						case "${REPLY}" in
							n|N)

								# user requested abort.
								return 1
							;;
							*)

								# continue loop and check if right media was inserted on next loop.
								continue
							;;
						esac
					}

					# break execution, because file was found.
					break
				done

				# show user what we do.
				babelize__printf "Copying original file '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}' -> '${2}/${LOCAL__target}'"

				# check if destination directory exist.
				[ -d "${2}/$(@DIRNAME@ "${LOCAL__target}")" ] || {

					# create directory for destination files.
					@MKDIR@ -p "${2}/$(@DIRNAME@ "${LOCAL__target}")"
				}

				# copy the file from cd.
				@CP@ "${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The file '${LOCAL__directories[$((${LOCAL__count} - 1))]}/${LOCAL__source}' could not be copied, maybe a file permission problem?"

					# break execution, if file is corrupt.
					return 1
				}

				# change file permissions.
				@CHMOD@ "${LOCAL__mode}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The permissions of file '${2}/${LOCAL__target}' could not be changed, maybe a strange problem?"

					# break execution, if file is corrupt.
					return 1
				}
			done
		}
	done

	# unset used variables.
	unset LOCAL__cd
	unset LOCAL__count

	# if no error was found, return zero.
	return 0
}

# @_babelize__localize()
#
# @_${1}: language pack
# @_${2}: game directory
#
# this function localizes a specific game.
function babelize__localize() {

	# first check if the archive exist.
	babelize__validate_langpack "${1}" || return 1

	# secod check if the gameroot exist.
	babelize__validate_gameroot "${2}" || return 1

	# third check if enough free space is available.
	babelize__validate_diskspace "${1}" || return 1

	# fourth check if babelize version is correct.
	babelize__validate_version || return 1

	# show user the number of files to process.
	babelize__printf "Number of files (verify): '${#BABELIZE_FILES[@]}'"

	# set working directory to ${2} required for md5sum.
	cd "${2}"

	# first check if the files matches the md5sum.
	declare -a LOCAL__files=()
	local LOCAL__count
	local LOCAL__line
	for LOCAL__line in "${BABELIZE_FILES[@]}" ; do

		# increase counter.
		let LOCAL__count++

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:00000000000000000000000000000000*)

				# special md5sum, so continue without checking.
				continue
			;;
			md5:*)

				# fetch md5 information.
				local LOCAL__md5="${LOCAL__line##*md5:}"
				local LOCAL__md5="${LOCAL__md5%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# check if previously version was checked successfully.
				[ "${LOCAL__files[*]%target:${LOCAL__target}}" != "${LOCAL__files[*]}" ] && {

					# continue to next file.
					continue
				}

				# check file only if it wasn't processed already.
				[ "${LOCAL__files[*]%target:${LOCAL__target}}" == "${LOCAL__files[*]}" ] && {

					# fetch version information.
					local LOCAL__version="${LOCAL__line##*version:}"
					local LOCAL__version="${LOCAL__version%%  *}"

					# fetch source information.
					local LOCAL__cd="${LOCAL__line##*cd:}"
					local LOCAL__cd="${LOCAL__cd%%  *}"

					# check if file exist.
					[ -r "${2}/${LOCAL__target}" ] && {

						# check the md5sum of the source file.
						echo "${LOCAL__md5}  ${LOCAL__target}" | @MD5SUM@ --check --status && {

							# show user what we do.
							babelize__printf "Checking md5sum of '${2}/${LOCAL__target}'"

							# add file member to new array.
							LOCAL__files[${#LOCAL__files[@]}]="${LOCAL__line}"
						} || {

							# store temporary array values for comparison.
							local LOCAL__temp="${BABELIZE_FILES[@]:${LOCAL__count}}"

							# check if there is another version of that file to verify.
							[ "${LOCAL__temp%target:${LOCAL__target}*}" == "${LOCAL__temp}" ] && {

								# show user what we do.
								babelize__printf "Checking md5sum of '${2}/${LOCAL__target}'"

								# show user what we do.
								babelize__printf "The file '${2}/${LOCAL__target}' seems to be corrupt, maybe a previously applied localization problem?"

								# break execution, if file is corrupt.
								return 1
							}
						}
					}

					# check if file exist.
					[ ! -r "${2}/${LOCAL__target}" ] && [ "${LOCAL__cd}" -gt "0" ] && {

						# show user what we do.
						babelize__printf "The file '${2}/${LOCAL__target}' does not exist, maybe this is no full game installation?"

						# break execution, if file is missing.
						return 1
					}
				}
			;;
			*)

				# nothing to do.
				continue
			;;
		esac
	done

	# cleaning up /tmp.
	[ -d "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}" ] && @RM@ -R "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}"

	# show user what we do.
	babelize__printf "Extracting '${1}'"

	# create directory for extraction and extract langpack there.
	@MKDIR@ "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}"
	@TAR@ xzf "${LANGPACK_DIR:-/usr/local/share/babelize/langpacks}/${1}" -C "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}"

	# show user the number of files to process.
	babelize__printf "Number of files (create): '${#LOCAL__files[@]}'"

	# second loop for the language pack.
	local LOCAL__line
	for LOCAL__line in "${LOCAL__files[@]}" ; do

		# check if we are using the right file format.
		case "${LOCAL__line}" in
			md5:*action:xdelta-make*|\
			md5:*action:xdelta-copy*|\
			md5:*action:xdelta-next*)

				# fetch version information.
				local LOCAL__version="${LOCAL__line##*version:}"
				local LOCAL__version="${LOCAL__version%%  *}"

				# fetch permission information.
				local LOCAL__mode="${LOCAL__line##*mode:}"
				local LOCAL__mode="${LOCAL__mode%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# show user what we do.
				babelize__printf "Applying xdelta of '${2}/${LOCAL__target}'"

				# patch files.
				@XDELTA@ patch "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}/${BABELIZE_LANGPACK_LOCALE}/${LOCAL__target}.${LOCAL__version}.xdelta" "${2}/${LOCAL__target}" "${2}/${LOCAL__target}.xdp" || {

					# show user what we do.
					babelize__printf "The file '${2}/${LOCAL__target}' could not be patched."

					# break execution, if patching failed.
					return 1
				}

				# overwrite old files with newly created one.
				@MV@ "${2}/${LOCAL__target}.xdp" "${2}/${LOCAL__target}"

				# change file permissions.
				@CHMOD@ "${LOCAL__mode}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The permissions of file '${2}/${LOCAL__target}' could not be changed, maybe a strange problem?"

					# break execution, if file is corrupt.
					return 1
				}
			;;
			md5:*action:create-make*)

				# fetch version information.
				local LOCAL__version="${LOCAL__line##*version:}"
				local LOCAL__version="${LOCAL__version%%  *}"

				# fetch permission information.
				local LOCAL__mode="${LOCAL__line##*mode:}"
				local LOCAL__mode="${LOCAL__mode%%  *}"

				# fetch target information.
				local LOCAL__target="${LOCAL__line##*target:}"

				# show user what we do.
				babelize__printf "Creating file '${2}/${LOCAL__target}'"

				# copy file.
				@CP@ "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}/${BABELIZE_LANGPACK_LOCALE}/${LOCAL__target}.${LOCAL__version}.create" "${2}/${LOCAL__target}"

				# change file permissions.
				@CHMOD@ "${LOCAL__mode}" "${2}/${LOCAL__target}" || {

					# show user what we do.
					babelize__printf "The permissions of file '${2}/${LOCAL__target}' could not be changed, maybe a strange problem?"

					# break execution, if file is corrupt.
					return 1
				}
			;;
			*)

				# nothing to do.
				continue
			;;
		esac
	done

	# removing temporary files
	@RM@ -R "${LANGPACK_EXTRACT_DIR:-/tmp}/${BABELIZE_LANGPACK_REFERENCE}"

	# we have finished successfully. :)
	babelize__printf ""
	babelize__printf "The game '${BABELIZE_GAME_NAME}' is now localized with language '${BABELIZE_LANGPACK_LANGUAGE}'"

	# if no error was found, return zero.
	return 0
}
