#!/usr/bin/env bash
#
#   dvdwizard_common 
#     - functions for dvdwizard for creating a DVD image from 
#       mpeg stream(s) with chapters and menus without further
#       user interaction.
#
#   Copyright (C) 2004-2008 W. Wershofen <itconsult at wershofen.de>
#   Copyright (C) 2010-2011 Markus Kohm <kohm at uses.sf.net>
#   Copyright (C) 2009-2012 Joo Martin <joomart2009 at users.sf.net>
#
#   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 3 of the License, or
#   (at your option) any later version.
#
#   This package 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, see <http://www.gnu.org/licenses/>.
#
# -------------------------------------------------------------------------
#
# NOTE: While this file is something like a library for all dvdwizard
#       applications, it should be placed at the library path.  But
#       unfortunatly bash scripts cannot load bash library scripts via
#       e.g. ldconfig.  Because of this, this is simply a binary like
#       all dvdwizard applications.  So it should simply be installed
#       at PATH and may be loaded via PATH like all other loads.
#
# -------------------------------------------------------------------------
#
# Changes:
# 
#   2010-06-21  Markus Kohm
#               * renamed dvdwizardrc into dvdwizard_common
#               * usage of gettext features for multilanguage ui
#                 - COPYLINE1 + COPYLINE2 --> COPYLINE
#                 - several `echo' replaced by `printf'
#               * DW_VERSION, DW_PATCHLEVEL, DW_DATE will be set by 
#                 Makefile
#   2010-08-04  Markus Kohm
#               * new functions split_formatstring, create_formatstring,
#                 and normalize_formatstring
#   2010-08-17  Markus Kohm
#               * new functions is_integer and is_real
#   2010-09-29  Joo Martin
#               * relaced `-ab 224kb' by `-ab 224000' at ffmpeg calls
#   2010-09-29  Markus Kohm
#               * check_tools for ${thisscript} == sh does not longer check 
#                 for the DVDwizard tools
#   2011-06-30  Markus Kohm
#               * workaround for ffmpeg 0.8 floating point exception
#   2012-03-18  Joo Martin
#               * user config file always in $HOME/.config/dvdwizard/
#                 but search first at older place of user config file
#               * try update of user config file to current version
#
# -------------------------------------------------------------------------

#
# i18n
#
export TEXTDOMAIN=dvdwizard
export TEXTDOMAINDIR="@LOCALEDIR@"

#
# What version of dvdwizard are we running?
#
DW_NAME="DVDwizard"
DW_VERSION="@VERSION@"
DW_PATCHLEVEL="@PATCHLEVEL@"
DW_DATE="(@DATE@)"
GPLVERS="GPL-3"
HOMEADDR="http://sf.net/projects/dvdwizard"
BUGADDR="<dvdwizard-users@lists.sourceforge.net>"
COPYNAME="(c) 2004-2008 Wolfgang Wershofen
          (c) 2010-2011 Markus Kohm
          (c) 2009-2012 Joo Martin"
COPYLINE=$"This program comes with ABSOLUTELY NO WARRANTY. This is free software and
you are welcome to redistribute it under certain conditions (see ${GPLVERS})."
DW_strict=true

DW_VERSIONX="${DW_VERSION}"
[ -n "${DW_PATCHLEVEL}" ] && DW_VERSIONX="${DW_VERSION}.${DW_PATCHLEVEL}"

#
# Set decimal delimiter to '.' instead of ',' - otherwise
# chapters will only be accurate to seconds and not to frames
#
export LC_NUMERIC="C"

#
# Determine version of Image-Magick
#
export IM_VERSION4=$(convert -version | grep ^Version: | cut -d' ' -f3)
export IM_VERSION3=$(echo "$IM_VERSION4" | cut -d'-' -f1)
export IM_VERSION2=$(echo "$IM_VERSION3" | cut -d. -f1-2)

#
# The scriptname
#
thisscript=$(basename $0)

# ----------------------------------------------------------------------------
#
# Show version and copyright
#
show_version()
{
    echo "${thisscript} - ${DW_NAME} - version ${DW_VERSIONX}  ${DW_DATE}"
    printf $"Send bugs to %s\n" "${BUGADDR}"
    echo "Copyright ${COPYNAME}"
    echo "${COPYLINE}"
}

# ----------------------------------------------------------------------------
#
# Test for -h, --help, -v or --version and show version or usage
#
test_versionhelp() {
    while [ $# -gt 0 -a "$1" != "--" ]; do
	case $1 in
	    -v|--version)
		show_version
		exit 0
		;;
	    -h|--help)
		show_version
		echo "${usagetext}"
		exit 0 # not needed but safty first
		;;
	esac
	shift
    done
}

# ----------------------------------------------------------------------------
#
# If something goes wrong....  Default Error-Handling
#
error_out()
{
    echo "$thisscript" $"error:" \
$"The last command exited with non-zero return code $?.
So I guess it's better to stop here and let you analyze the situation.
Hope you'll find the error. ;-)"
    if [ -e "$LOGFILE" ]; then
	echo $"Here are the last 10 lines of the log ($LOGFILE):"
	echo '------------------------------------------------------------'
	tail -n 10 "$LOGFILE"
    fi
	
    exit 1
} >&2

error_help()
{
    echo -n "${thisscript}" $"error:" "" 
    printf "$@"
    echo
    echo $"See ${thisscript} -h for more infos."
    exit 1
} >&2

error_nohelp()
{
    echo -n "${thisscript}" $"error:" ""
    printf "$@"
    echo
    exit 1
} >&2

print_warn()
{
    printf $"*** Warning: "
    printf "$@"
    echo
}

log_warn()
{
    print_warn "$@" >&2
    [ -n "$LOGFILE" ] && print_warn "$@" >> "$LOGFILE"
}

print_log()
{
    printf "$@"
    [ -n "$LOGFILE" ] && printf "$@" >> "$LOGFILE"
}

# ----------------------------------------------------------------------------
#
# Check for needed tools in each script
#
check_tools()
{
#
# We need at least ImageMagick 6.3.5 (June 2007)
#
    if [ "$IM_VERSION3" \< "6.3.5" ]; then
	error_help $"dvdwizard NEEDS at least ImageMagick Version %s or higher"! "6.3.5"
    fi >&2

    commonTools="awk basename cat convert cp cut date dirname dvdauthor grep identify ln mkdir mktemp mplex mv ppmtoy4m rm sed seq tail tee tr wc"
    dvdwizard="chaptercheck dvdcpics dvdtguess ffmpeg mk_vmgm mk_vtsm mk_vtsm_info mk_vtsm_lang mpgprobe nice"
    mk_vmgm="composite ffmpeg montage mpeg2enc spumux"
    mk_vtsm="$mk_vmgm mogrify"
    chaptercheck="bc"
    dvdcpics="display tcprobe transcode"
    dvdtguess=""      
    mpgprobe="ffmpeg"
    txt2png="mogrify"
    mk_vtsm_lang="$mk_vtsm"
    mk_vtsm_info="$mk_vtsm txt2png"
    dvdwizard_test="bc sox"
    sh="ffmpeg nice ${mk_vmgm} ${mk_vtsm} ${chaptercheck} ${dvdcpics} ${dvdtguess} ${mpgprobe} ${mogrify} ${txt2png} ${mk_vtsm_lang} ${dvdwizard_test}"
    eval tools="\${$thisscript}"
    tools="$commonTools $tools"

    for tool in $tools; do
	type -p "$tool" > /dev/null 2>&1
	if [ $? -ne 0 ]; then
	    error_help $"The program \`%s' is needed, but could not be located"! "$tool"
	fi
    done
	
    return 0
}

# ----------------------------------------------------------------------------
#
# Three procedures for update_config()
#
create_header()
{
cat  <<EOF  >"$tempFile"
#
# Configuration for dvdwizard $DW_VERSIONX
#
CONFVER=$DW_VERSION

#
# Some directories
#
EOF
}
create_body()
{
    # cut lines from BASEDIR= until MENU=
    awk 'BEGIN {xx=0;} /^BASEDIR/ {xx=1;} {if (xx==1) print $0} /^MENU=/ {xx=0;}' \
        "$1"  >>"$tempFile"
}
create_lang()
{
    # cut lines from MENU= until TXT_OVERLAY_INFO_2_CS=
    awk 'BEGIN {xx=0;} {if (xx==1) print $0} /^MENU=/ {xx=1;}' "$1" |\
        sed 's/AUDIOVI_SV\=\"pro/AUDIOVI_CS\=\"pro/g'  >>"$tempFile"
        # fix typo in TXT_VTSM_AUDIOVI_CS of version 0.7.0
}

# ----------------------------------------------------------------------------
#
# Update the user configuration to current CONFVER value
#
update_config()
{
    # system config file of version 0.7.0 (checking bug) is good enough
    [ $(grep -c ^TXT_VTSM_AUDIOVI_SV "$system_dfltconfFile") -eq 2 ] && IsConfVer=2
    
    if [ "$IsConfVer" -gt 0 ]; then
        # update to current version using system config file
        create_header
        create_body "$user_dfltconfFile"
        create_lang "$system_dfltconfFile"
        if [ -n "$tempFile" ]; then
            mv "$user_dfltconfFile" "$user_dfltconfFile"_old
            mv "$tempFile" "$user_dfltconfFile"  2>/dev/null
            printf $"User config in file '%s' successful updated""\n" "$user_dfltconfFile"
        fi
    fi
}

# ----------------------------------------------------------------------------
#
# Set default processing options - either from config-File or from built-in
#
set_defaults()
{
    system_dfltconfFile="/etc/dvdwizard.conf"
    user_oldconfDir="$HOME/.dvdwizard"
    user_oldconfFile="$HOME/.dvdwizard/dvdwizard.conf"
    user_dfltconfDir="$HOME/.config/dvdwizard"
    user_dfltconfFile="$HOME/.config/dvdwizard/dvdwizard.conf"
    confFile=""
    tempFile=/tmp/dwc
    IsConfVer=0
    
    #
    # Search CLI-Parms for Config-File Specification
    #
    i=0
    while [  $i -lt $# ]; do
    let "i+=1"
    eval passed_arg=\${$i}
    if [ "$passed_arg" = "-C" -o "$passed_arg" = "--config-file" ]; then
        let "i+=1"
        eval confFile=\${$i}
        if [ -f "$confFile" -a -r "$confFile" ]; then
            :
        else
            error_nohelp $"Specified config-file '%s' not found or had no read permission"! "${confFile}"
        fi
        break 2
    fi
    done
    
    #
    # Check, if config file parm is given. If not, try, if default
    # config-file exists. If it does not exist, use built-in defaults.
    # User-Config takes precedence over system-wide config.
    #
    if [ -z "$confFile" ]; then
        # check whether system config file exists; select as initial config
        if [ -f "$system_dfltconfFile" -a -r "$system_dfltconfFile" ]; then
            confFile="$system_dfltconfFile"
            # check for the new variable CONFVER
            [ `grep -c ^CONFVER "$system_dfltconfFile"` -eq 1 ] && IsConfVer=1
        else
            error_nohelp $"Systemwide config file '%s' not found or had no read permission"! "${system_dfltconfFile}"
        fi
        # check and create the user config directory
        [ ! -d "$user_dfltconfDir" ] && mkdir "$user_dfltconfDir"
        # if user config file exists at old place, try to move file to new place
        if [ -f "$user_oldconfFile" -a -r "$user_oldconfFile" ]; then
            cp -p "$user_oldconfFile" "$user_dfltconfFile"
            mv "$user_oldconfFile" "$user_oldconfFile"_old
            # set information in old directory
            touch "$user_oldconfDir"/THIS_OLD_DIRECTORY_CAN_BE_DELETED
            printf $"User config moved into file '%s'""\n" "$user_dfltconfFile"
        # otherwise make a copy of system config file
        elif [ ! -f "$user_dfltconfFile" ]; then
            cp "$system_dfltconfFile" "$user_dfltconfFile"
        fi
        if [ `grep -c ^CONFVER "$user_dfltconfFile"` -eq 0 ]; then
            # try to update user config file to current CONFVER
            update_config
        fi
        printf "\n"
        # check whether user config file exists; select as final config
        [ -f "$user_dfltconfFile" -a -r "$user_dfltconfFile" ] && confFile="$user_dfltconfFile"
    fi
    
    #
    # Ok, set process options
    #
    if [ -z "$confFile" ]; then
    error_nohelp $"No config file dvdwizard.conf found!
DVDwizard needs a config file to run. Use one of the following options:
  - Create a system-wide config named /etc/dvdwizard.conf
  - Create a user config named $HOME/.config/dvdwizard/dvdwizard.conf
  - Supply a valid config file with the -C option on the command line
Look at dvdwizard.conf.sample for more information."
    fi
    
    #
    # Check, if config file is valid (at least some lines with assignments to
    # Uppercase-Variables
    #
    if [ $(grep -cE "^\ *[[:upper:]]+=" "$confFile") -eq 0 ]; then
        error_nohelp $"Config file \`%s' is not valid.
It does not contain any assignment to uppercase variable names." "${confFile}"
        exit 1
    fi

    #
    # Ok, set process options
    #
    . "$confFile"
    
    #
    # if config is incomplete, set defaults for mandatory variables
    #
    [ -z "$BASEDIR" ] && BASEDIR="$(pwd)"
    if [ -z "$TVNORM" ]; then
	if [ -n "${VIDEO_FORMAT}" ]; then
	    TVNORM="${VIDEO_FORMAT}"
	elif [ -f "~/.config/video_format" ]; then
	    TVNORM="$(head -1 ~/.config/video_format)"
	else
	    TVNORM="PAL"
	fi
    fi
    [ -z "$TVSIZE" ] && TVSIZE="660x530"
    [ -z "$BGRATIO" ] && BGRATIO="4:3"
    [ -z "$MENU_CANVAS" ] && MENU_CANVAS="gradient:white-black"
    [ -z "$DUMMY_CANVAS" ] && DUMMY_CANVAS="xc:none"
    [ -z "$MENU" ] && MENU="EN"
    [ -z "$TMPDIR" ] && export TMPDIR="/tmp" || export TMPDIR="$TMPDIR"
    [ -z "$NICE" ] && NICE="+0"
    [ -z "$VTSTITLE" ] && VTSTITLE="auto"
    [ -z "$THUMBBORDER" ] && THUMBBORDER=3
    [ -z "$THUMBSPACE" ] && THUMBSPACE=5
    [ -z "$CHAPTERSPERROW" ] && CHAPTERSPERROW=3
    [ -z "$PAUSE" ] && PAUSE=2
    [ -z "$LOOP" ] && LOOP=0
	
    #
    # Init and Check Colors
    #
    colorlist="$(convert -list color | sed 1,/^-/d | cut -d' ' -f1)"
    transparent="transparent"		#'rgba(128,192,255,255)'
    shadow="black"
    [ -z "$TRANSLUCENT" ] && TRANSLUCENT='#FFFFFF80'
    [ -z "$TITLECOLOR" ] && TITLECOLOR="white"
    [ -z "$HEADCOLOR" ] && HEADCOLOR="white"
    [ -z "$TEXTCOLOR" ] && TEXTCOLOR="white"
    [ -z "$NORMCOLOR" ] && NORMCOLOR="white"
    [ -z "$HICOLOR" ] && HICOLOR="orange"
    [ -z "$SELCOLOR" ] && SELCOLOR="green"
    [ -z "$ACTCOLOR" ] && ACTCOLOR="green1"
    for c in $TRANSLUCENT $TITLECOLOR $HEADCOLOR $TEXTCOLOR $NORMCOLOR $HICOLOR $SELCOLOR $ACTCOLOR; do
	if [ "${c:0:1}" == "#" -o "${c:0:3}" == "rgb" ]; then
	    :
	else
	    echo "$colorlist" | grep ^"${c}"$ >/dev/null
	    if [ $? -ne 0 ]; then
		error_nohelp $"Invalid color \`%s' specified. Please check config file." "$c"
	    fi
	fi 
    done >&2
    hiColor=( "$NORMCOLOR" "$HICOLOR" "$SELCOLOR" )

    #
    # Check, if we need "-list type" or "-list font" to get the list of known 
    # fonts in IM
    #
    convert -list font > /dev/null 2>&1 && listkey="font" || listkey="type"

    #
    # Init and Check Fonts
    #
    if [ "$IM_VERSION3" \< "6.4.4" ]; then
	fontlist="$(convert -list $listkey | cut -d' ' -f1 | sed 1,/^-/d | sed -e /^$/,/^-/d | sort)"
    else
	fontlist="$(convert -list font | grep ' Font: ' | sed 's!^\ \ Font\:\ \(.*$\)!\1!g' | sort)"
    fi
    maxfl=0
    for t in $(echo $fontlist); do
	[ ${#t} -gt $maxfl ] && maxfl=${#t}
    done
    [ -z "$TFONTSIZE" ] && TFONTSIZE=48
    [ -z "$HFONTSIZE" ] && HFONTSIZE=24
    [ -z "$MFONTSIZE" ] && MFONTSIZE=20
    [ -z "$BFONTSIZE" ] && BFONTSIZE=20
    [ -z "$OFONTSIZE1" ] && OFONTSIZE1=18
    [ -z "$OFONTSIZE2" ] && OFONTSIZE2=40
    for fontvar in TFONTTYPE HFONTTYPE MFONTTYPE BFONTTYPE OFONTTYPE1 OFONTTYPE2; do
	eval t=\$$fontvar
	fontparm=$(echo $fontvar | sed -e s/TYPE//g)
	if [ -z "$t" ]; then
	    eval $fontparm=\"\"
	else
	    [ ${#t} -gt $maxfl ] && t=${t:0:$maxfl}
	    echo "$fontlist" | grep ^"${t}"$ >/dev/null
	    if [ $? -ne 0 ]; then
		error_nohelp $"Invalid font type %s specified. Please check config file." "$t"
	    fi
	    eval $fontparm=\"-font $t\"
	fi 
    done >&2

    #
    # Create temporary directory for storing all non-permanent work files
    #
    if [ -z "$DVDWIZARD_TMPDIR" ]; then
        # Remove previously created temporary directories where we are owner
	for d in "$TMPDIR/$thisscript"_*; do
	    # joo: remove only directories
	    if [ -d "$d" ]; then
		[ -O "$d" ] && rm -R "$d"
	    fi
	done
	export DVDWIZARD_TMPDIR=$(mktemp -dt "$thisscript"_XXXXXX) || \
	    error_nohelp $"Could not create temporary directory.
Please check your TMPDIR settings and permissions on your temporary directory." 

	#
	# Create subdirectory for common objects (get reused in various scripts)
	#
	mkdir "$DVDWIZARD_TMPDIR"/common_objects
    fi
    export TMPDIR="$DVDWIZARD_TMPDIR"
	
    return 0
}

# ----------------------------------------------------------------------------
#
# Check and create Directory if not already present and called with the 
# "New"-Parm
#
mk_check_dir()
{
    chkdir="$1"
    chkmode="$2"
    chkdescr="$3"
	
    if [ -z "$chkdir" ]; then
	error_help $"Directory not specified (%s)"! "${chkdescr}, ${chkmode}"
    fi
	
    if [ -e "$chkdir" ]; then
	if [ ! -d "$chkdir" ]; then
	    error_help $"Specified directory \`%s' (%s) isn't a directory." "${chkdir}" "${chkdescr}"
	fi
	if [ -r "$chkdir" -a -x "$chkdir" ]; then
	    :
	else
	    error_help $"Insufficient access rights on directory \`%s' (%s), must have at least rx." "${chkdir}" "${chkdescr}"
	fi
	if [ "$chkmode" == "NEW" ]; then
	    dCount=$(ls -1 "$chkdir"/* 2>/dev/null | wc -l)
            # Ask for permission to recreate an existing, non-empty directory
            # if user has not specified -y|--yes on the command line
	    if [ $dCount -ne 0 -a "$permission" != "Yes" ]; then
		printf $"Directory \`%s' (%s) exists and is not empty
All files in this directory will be deleted. Okay? [yN]\n" "${chkdir}" "${chkdescr}"
		permit=""
		until [ ! -z "$permit" ]; do
		    read ANSWER
		    case "$ANSWER" in
			""|$"n"|$"N" )
			    permit="N"
			    ;;
			$"y"|$"Y" )
			    permit="Y"
			    ;;
			* )
			    printf $"Wrong reply. Please answer with a single 'y' or 'n'.
All files in \`%s' will be deleted. Okay? [yN]\n" "${chkdir}"
			    ;;
		    esac
		done
		if [ "$permit" == "N" ]; then
		    error_nohelp $"Sorry, can't work with a non-empty destination directory.
Please clean up \`%s' manually or specify another directory (%s).\n" "${chkdir}" "${chkdescr}"
		fi
	    fi
	    if rm -R "$chkdir"; then
		if mkdir -p "$chkdir"; then
	    	    :
	 	else
		    error_help $"Could not re-create directory \`%s' (%s)." "${chkdir}" "${chkdescr}"
		fi
	    else
		error_help $"Could not clean up destination directory \`%s' (%s). Check your permissions"! "${chkdir}" "${chkdescr}"
	    fi
	fi
    else
	if [ "$chkmode" == "NEW" ]; then
	    if mkdir -p "$chkdir"; then
	    	:
	    else
		error_help $"Could not create directory \`%s' (%s)." "${chkdir}" "${chkdescr}"
	    fi
	else
	    error_help $"Specified input directory \`%s' (%s) not found." "${chkdir}" "${chkdescr}"
	fi
    fi
	
    if [ "$chkmode" == "NEW" -a ! -w "$chkdir" ]; then
	error_help $"No write permission in directory \`%s' (%s)." "${chkdir}" "${chkdescr}"
    fi
	
    return 0
}

# ----------------------------------------------------------------------------
#
# Check and create file if not already present and called with "New"
#
mk_check_file()
{
    chkfile="$1"
    chkmode=$2
    chkdescr="$3"
	
    if [ -z "$chkfile" ]; then
	error_help $"Filename not specified (%s)." "${chkdescr}, ${chkmode}"
    fi
	
    if [ -e "$chkfile" ]; then
	if [ -d "$chkfile" ]; then
	    error_help $"Specified file \`%s' (%s) is a directory." "${chkfile}" "${chkdescr}"
	fi
	if [ -r "$chkfile" ]; then
	    :
	else
	    error_help $"Insufficient access rights on file \`%s' (%s), must have at least read permission." "${chkfile}" "${chkdescr}"
	fi
	if [ -w "$chkfile" -o "$chkmode" != "NEW" ]; then
	    :
	else
	    error_help $"Insufficient access rights on file \`%s' (%s), must have write permission." "${chkfile}" "${chkdescr}"
	fi
    else
	if [ "$chkmode" == "NEW" ]; then
	    if touch "$chkfile"; then
	    	:
	    else
		error_help $"Could not create file \`%s' (%s)." "${chkfile}" "${chkdescr}"
	    fi
	else
	    error_help $"Specified input file \`%s' (%s) not found." "${chkfile}" "${chkdescr}"
	fi
    fi >&2
	
    if [ "$chkmode" == "NEW" -a ! -w "$chkfile" ]; then
	error_help $"No write permission on file \`%s' (%s)." "${chkfile}" "${chkdescr}"
    fi
	
    return 0
}
# ----------------------------------------------------------------------------
#
# Set all values for the specific TV norm.
# PAL and NTSC differ in audiosamples per videoframe and frame rates.
# So the appropriate value $samples is set for 10 video frames.
#
# PAL  analog  format is:   788x576 (for 4:3)   1050x576 (for 16:9)
# NTSC analog  format is:   664x486 (for 4:3)    886x486 (for 16:9)
#
set_format()
{
    # default: PAL
    encNorm="p"                        # PAL digital
    encFrameRate="25:1"                # 25.00 fps
    pixAspect="59:54"                  # PAR
    normX=720;   normY=576
    densityX=75; densityY=80
    samples=19200  
    
    if [ "$TVNORM" == "NTSC" ]; then
	encNorm="n"                    # NTSC digital
	encFrameRate="30000:1001"      # 29.97 fps
	pixAspect="10:11"              # PAR
	normX=720;   normY=480
	densityX=81; densityY=72
	samples=16016 
    fi

    normSize="${normX}x${normY}"
    normDensity="${densityX}x${densityY}"
    TVWidth=$(echo "$TVSIZE" | cut -d'x' -f 1)
    TVHeight=$(echo "$TVSIZE" | cut -d'x' -f 2)
    let offsetTVX="($normX-$TVWidth)/2"
    let offsetTVY="($normY-$TVHeight)/2"
    
    let maxpH="$TVHeight-20"
    let maxpW="$TVWidth-20"
    scaleXY="${maxpW}x${maxpH}"
    normXY="${normX}x${normY}!"
    # additional offsets for menu background image
    offARX=20                     # old 50
    offARY=10                     # old 10
    # mpeg2enc always for 4:3 menu background image
    mpgAspect=2

    if [ "$BGRATIO" == "16:9" ]; then
	# kind of letterbox ... 16:9 inside 4:3
	# factor 3/4 =788/1050 (PAL) or =664/886 (NTSC)
	let maxpH="($maxpW * 3/4) * $normY/$normX"
	# take maxpW to compute maxpH
	let maxpW="$TVWidth-20"
	scaleXY="${maxpW}x${maxpH}!"
	normXY="${normX}x${normY}!"
	# additional offsets for menu background image
	offARX=20                              # old 50
	let offARY="($TVHeight-$maxpH)/2"      # old 70
    fi

    printf $"Scaling to %s for background aspect ratio %s ...""\n" "${scaleXY}" "${BGRATIO}"

    return 0
}

# ----------------------------------------------------------------------------
#
#  Create common objects needed in various scripts and locations
#
create_common_objects()
{

    #
    # Create empty audio track if not already existing
    #
    silence="$TMPDIR/common_objects/silence.ac3"
    if [ ! -e "$silence" ]; then
	#
	# Create audio track
	#
	echo -n $"Creating empty AC3 Audio-Track..."
	ffmpeg -ar 48000 -f s16le -i /dev/zero -ab 224000 -ar 48000 -ac 2 -t 1 "$silence" 1>/dev/null 2>&1 || error_out
	echo $"done."
    fi
	
    #
    # Create dummy mpeg stream for menus
    #
    emptympg="$TMPDIR/common_objects/empty.mpg"
    if [ ! -e "$emptympg" ]; then
	echo -n $"Creating dummy MPEG-Stream..."
	#
	# Create dummy mpeg Stream for first dummy menu in vmgm/vtsm
	#
	convert -size "$normSize" xc:transparent -depth 8 ppm:- |\
            ppmtoy4m -S 420mpeg2 -n 1 -F "$encFrameRate" -r /dev/stdin | \
	    mpeg2enc -a "$mpgAspect" -n "$encNorm" -f 8 -o /dev/stdout | \
	    mplex -f 8 -o /dev/stdout /dev/stdin "$silence" > "$emptympg" || error_out
	echo $"done."
    fi
	
    return 0
}

# ----------------------------------------------------------------------------
#
# Prepare the background picture for the menus
#
prepare_bg()
{
    actvts=$1
    bgPic="$2"
    workbg="$TMPDIR/common_objects/menubg_$actvts".png
    workfr="$TMPDIR/common_objects/menufr_$actvts".png
    #
    # If picture already exists, no op
    #
    [ -e "$workbg" ] && return 0 
    echo -n $"Preparing Background-Picture for titleset" "${actvts}..."

    #
    # If no background picture specified, create one
    #
    if [ -z "$bgPic" ]; then
	bgPic="$DUMMY_CANVAS"
    fi	
    #
    # Ok, create Background picture
    #
    faktor="pi"
    convert \
	"$bgPic" -scale "${scaleXY}" \
	\( +clone -fx 'cos('$faktor'*(i/w-.5))*cos('$faktor'*(j/h-.5))' \
	   -bordercolor black -border 10 -alpha Off \
	\) \
	-compose copyopacity -composite \
	png:"$workfr" || error_out
	
    convert \
	-size ${normSize} $MENU_CANVAS -scale "${normXY}" \
	\( "$workfr" -gravity NorthEast \
	   -geometry +"$(( $offsetTVX + $offARX ))"+"$(( $offsetTVY + $offARY ))" \
	\) \
	-composite -depth 8 -density $normDensity -units PixelsPerInch \
	png:"$workbg" || error_out

    echo $"done."

    return 0
}

# ----------------------------------------------------------------------------
#
# Create overlay container with logo or descriptive text
#	$1 - Identifying part of the name of the text elements from config file
#	     Elements: TXT_OVERLAY_$1_1_$lang - small, opaque text
#	     Elements: TXT_OVERLAY_$1_2_$lang - big, bevelled, translucent text
#	Name and path of resulting image is stored in variable $logoPic
#
create_overlay()
{
    eval text1=\"\$TXT_OVERLAY_${1}_1_${MENU}\"
    if ${DW_strict} && [ "${1}" == "VMGM" ]
    then text2="${DW_NAME} ${DW_VERSION}"
    else eval text2=\"\$TXT_OVERLAY_${1}_2_${MENU}\"
    fi

    echo $"Selected $1 strings: \"$text1\" & \"$text2\""
    echo ""
    logoPic="$(mktemp -t png.XXXXXXXXXX)"
    fontsize1=45
    fontsize2=18

    #
    # Ok, create overlay picture
    #
    echo -n $"Creating Overlay-Picture..."
    convert \
	-size $normSize xc:none \
	\( -size $TVSIZE xc:none \
	   $OFONT2 -pointsize $OFONTSIZE2 -gravity center \
	   -fill '#00000080' -annotate +2-2 "$text2" \
   	   -fill '#FFFFFF80' -annotate +6+2 "$text2" \
	   -fill gray -annotate +4+0 "$text2" \
	   -transparent gray -trim +repage -bordercolor transparent -border 10 \
	   $OFONT1 -pointsize $OFONTSIZE1 -gravity northwest \
	   -fill black -annotate +0-4 "$text1" \
	   -fill white -annotate +2-2 "$text1" \
	   -rotate 270 -border 10 \
	\) \
	-gravity SouthEast -geometry +"$(( $offsetTVX+5 ))"+"$(( $offsetTVY+5 ))" \
	-composite -depth 8 -density $normDensity -units PixelsPerInch \
	png:"$logoPic" || error_out

    echo $"done."

    return 0
}

# ------------------------------------------
# Create Button Pictograms for Menus
#	Buttons are: Play, Chapter, Audio, Subtitle, Info, Previous and Next
#   Each button exists for all three states: normal, hilight, selected
#
mk_picts()
{
    #
    # Init phrases according to language setting 
    # determine longest string and corresponding button width
    #
    echo -n $"Creating button pictograms..."
    maxLen=0
    for i in PLAY CHAPTER AUDIO SUBS INFO; do
	eval txt_$i=\"\$TXT_VMGM_${i}_${MENU}\"
	eval txtLen=\${#txt_$i}
	if [ $txtLen -gt $maxLen ]; then
	    maxLen=$txtLen
	    eval maxtxt=\"\$txt_$i\"
	fi
    done

    # Size of button including descriptive text
    tWidth=$(convert -size $TVSIZE xc:black -fill red \
	       $BFONT -pointsize $BFONTSIZE \
	       -draw 'gravity center text 0,0 "--'"$maxtxt"'--"' -trim png:- | \
	       identify -format %w -)

    # Sizes for button pictograms
    pictSize=45x45	
    pictFontsize=34
    circleDef="22,22 22,4"
    polygonDef="14,11 36,22 14,33"
    pictWidth=$(echo $pictSize | cut -d'x' -f1)
    pictHeight=$(echo $pictSize | cut -d'x' -f2)
    let bWidth="$tWidth+$pictWidth+10"
    pictBase="$(mktemp -t png.XXXXXXXXXX)"

    #
    # For every button state, we need one pictogram for each button
    #
    for s in 0 1; do
	pictPlay[s]="$TMPDIR/common_objects/pictPlay_$s.png"
	pictInfo[s]="$TMPDIR/common_objects/pictInfo_$s.png"
	pictAudio[s]="$TMPDIR/common_objects/pictAudio_$s.png"
	pictMenu[s]="$TMPDIR/common_objects/pictMenu_$s.png"
	pictSubs[s]="$TMPDIR/common_objects/pictSubs_$s.png"
	pictPrev[s]="$TMPDIR/common_objects/pictPrev_$s.png"
	pictNext[s]="$TMPDIR/common_objects/pictNext_$s.png"
	pictArrow[s]="$(mktemp -t png.XXXXXXXXXX)"
	fillcolor="${hiColor[s]}"
	
	# Prevent Antialiasing for Highlight and Selected modes
	if [ $s -eq 0 ]; then
	    antialias=""
	else
	    antialias="+antialias"
	fi
	
	# Create pictogam-background (a circle!)
	convert $antialias -size $pictSize xc:"$transparent" -fill "$transparent" \
	    -strokewidth 2 -stroke "$fillcolor" -draw 'circle '"$circleDef"'' \
	    png:"$pictBase" || error_out

	#  Create an arrow pictogram
	convert $antialias -fill "$fillcolor" -draw 'polygon '"$polygonDef"'' \
	    "$pictBase" png:"${pictArrow[s]}" || error_out
	
	# Draw Play-Button with TXT_VMGM_PLAY
	if [ ! -e "${pictPlay[s]}" ]; then
	    if [ $s -eq 0 ]; then
		cp "${pictArrow[s]}" "${pictPlay[s]}" 
	    else
	        # Add text to highlight and selected buttons
		convert $antialias \
		    \(	-size ${bWidth}x${pictHeight} xc:"$TRANSLUCENT" \
		        $BFONT -pointsize $BFONTSIZE \
		        -fill "$fillcolor" -gravity west \
		        -annotate +$(( $pictWidth+5 ))+0 "$txt_PLAY" \
		    \) \
		    "${pictArrow[s]}" \
		    -compose over -gravity west -composite \
		    png:"${pictPlay[s]}" || error_out
	    fi
	fi
	
	# Draw Next-Button 
	if [ ! -e "${pictNext[s]}" ]; then
	    cp "${pictArrow[s]}" "${pictNext[s]}" 
	fi
	
	# Draw Previous-Button 
	if [ ! -e "${pictPrev[s]}" ]; then
	    convert "${pictArrow[s]}" -flop "${pictPrev[s]}" 
	fi
	
	# Draw the rest of the buttons
	for btnState in "${pictAudio[s]}@a@AUDIO" \
			"${pictMenu[s]}@x@CHAPTER" \
			"${pictSubs[s]}@s@SUBS" \
			"${pictInfo[s]}@i@INFO"; do
	    thisPic="$(echo "$btnState" | cut -d'@' -f1)"
	    thisChar="$(echo "$btnState" | cut -d'@' -f2)"
	    thisText="$(echo "$btnState" | cut -d'@' -f3)"

	    [ "$thisChar" == "x" ] && thisChar="?"
	    eval thisTxt=\"\$txt_$thisText\"
            
	    if [ ! -e "$thisPic" ]; then
		convert $antialias $BFONT -pointsize "$pictFontsize" \
		    -fill "$fillcolor" -gravity center \
		    -annotate +0+0 "$thisChar" \
		    "$pictBase" png:"$thisPic" || error_out
		if [ $s -ne 0 ]; then
		    convert $antialias \
			\(  -size ${bWidth}x${pictHeight} xc:"$TRANSLUCENT" \
			    $BFONT -pointsize $BFONTSIZE \
			    -fill "$fillcolor" -gravity west \
			    -annotate +$(( $pictWidth+5 ))+0 "$thisTxt" \
			\) \
			"$thisPic" \
			-compose over -gravity west -composite \
			png:"$thisPic" || error_out
		fi
	    fi
	done
    done
	
    echo $"done."
    return 0
}

# ----------------------------------------------------------------------------
#
# mk_nav_buttons - Create Buttons for Intra-Menu-Navigation
#
mk_nav_buttons()
{
    targets="$*"
    for tgt in $targets $txt_RETURN; do
	if [ ! -e "$TMPDIR/common_objects/navbtn_${tgt}_0.png" ]; then
	    btnDim=$(convert \
		-size $TVSIZE xc:transparent \
		$BFONT -pointsize $BFONTSIZE -gravity center \
		-fill black -undercolor black -annotate +0+0 " $tgt " \
		-trim +repage png:- | \
		identify -format %wx%h -)
	    fpat="$TMPDIR/common_objects/navbtn_${tgt}_@.png"
	    blankpng="$(echo "$fpat" | tr '@' 3)"
	    convert \
		-size $btnDim xc:transparent -bordercolor transparent -border 5 \
		png:"$blankpng" || error_out
	    fg=( ${hiColor[0]} ${hiColor[1]} $ACTCOLOR )
	    bg=( none $TRANSLUCENT none )
	    aa=( -antialias +antialias -antialias )
	    for i in 0 1 2; do
		tgtpng="$(echo "$fpat" | tr '@' $i)"
		convert -size $btnDim xc:${bg[i]} ${aa[i]} \
		    $BFONT -pointsize $BFONTSIZE -gravity center \
		    -fill ${fg[i]} -annotate +0+0 " $tgt " \
		    -bordercolor transparent -border 5 \
		    png:"$tgtpng" || error_out
	    done
	fi
    done

    return 0			
}

# ----------------------------------------------------------------------------
#
# mk_tmpdvd - Create a temporary DVD-structure without menus but with chapters
#
mk_tmpdvd()
{
    #
    # Do some file and directory preparation
    #
    [ -e "$DESTDIR" ] && rm -R "$DESTDIR"
    mkdir -p "$DESTDIR"
    tmpxml="$(mktemp -t xml.XXXXXXXXXX)"
    cat "$XMLFILE" > "$tmpxml"
    echo -e "\t<vmgm>\n\t</vmgm>" >> "$tmpxml"

    #
    # Create a Titleset for each defined title
    #
    for i in $(seq 1 $vts); do
	{
	    echo -e "\t<titleset>"
	    echo -e "\t\t<titles>"
	    echo -e "\t\t\t<video format=\"$TVNORM\" />"
	    echo -e "\t\t\t<pgc pause=\"0\">" 
	} >> "$tmpxml"
	eval files=\"\$VTSM_"$i"_FILES\"
	eval cspec=\"\$CHAPTERSPEC_$i\"
	for j in $(seq 1 $files); do
	    eval vtstitle=\"\$VTSM_"$i"_FILE_$j\"
	    duration=$(ffmpeg -i "$vtstitle" 2>&1 | grep Duration |\
		         sed 's/.*ation:.\(.*\), start.*/\1/' | cut -d'.' -f1)
	    if [ "$duration" == "N/A" ]; then
		printf $"Error: invalid duration value: N/A\nCheck duration time of \`%s'.\n" "$vtstitle" >> "$LOGFILE"
		error_out
	    fi
	    durHH=$(echo $duration | cut -d':' -f1)
	    durMM=$(echo $duration | cut -d':' -f2)
	    durSS=$(echo $duration | cut -d':' -f3)
	    mpglen=$(echo "$durHH*3600+$durMM*60+$durSS+1" | bc)
	    chapters=$(nice -n $NICE chaptercheck -N $TVNORM -L $mpglen $cspec) || error_out
	    eval VTSM_"$i"_CHAPTERS_$j=\"\$chapters\"
	    echo -e "\t\t\t\t<vob file=\"$vtstitle\""
	    echo -e "\t\t\t\t chapters=\"$chapters\""
	    echo -e "\t\t\t\t pause=\"0\" />"
	done >> "$tmpxml"
	{
	    echo -e "\t\t\t</pgc>"
	    echo -e "\t\t</titles>"
	    echo -e "\t</titleset>"
	} >> "$tmpxml"
    done

    echo "</dvdauthor>" >> "$tmpxml"
	
    #
    # Now author the temporary DVD
    #
    VIDEO_FORMAT="$TVNORM" nice -n $NICE dvdauthor -x "$tmpxml" || error_out
	
    rm "$tmpxml"

    return 0
}

# ----------------------------------------------------------------------------
#
# split_formatstring - Cut a string: <format>+<channels>+<language>+<special>
#                      into the 4 variables $str_format, $n_channels, 
#                      $str_language, $flag_special
# create_formatstring - Echo string: <language>[+MP2|AC3|DTS][+HI|VI][+1|2]
#                       from the 4 variables $str_format, $n_channels, 
#                       $str_language, $flag_special
# normalize_formatstring - normalize <format>+<channels>+<language>+<special>
#
split_formatstring() 
{
    local len part str ind
    str_format=""
    n_channels=0
    str_language=""
    flag_special=0
    str=$(echo "$1" | tr [:lower:] [:upper:])
    len=0
    ind=1

    while [ ${len} -lt ${#str} ]; do
	part=$(echo $str | cut -d'+' -f${ind} )
	: $((len += ${#part} + 1))
	: $((ind++))
	case ${part} in
	    MP2|AC3|DTS)
		str_format=$part
		;;
	    HI)
		flag_special=1
		;;
	    VI)
		flag_special=2
		;;
	    1|M)
		n_channels=1
		;;
	    2|S)
		n_channels=2
		;;
	    *)
		str_language="${part}"
		;;
	esac
   done
}

create_formatstring()
{
    local str
    str="${str_language}"
    [ -n "${str_format}" ] && str="${str}+${str_format}"
    [ ${flag_special} -eq 1 ] && str="${str}+VI"
    [ ${flag_special} -eq 2 ] && str="${str}+HI"
    [ ${n_channels} -ne 0 ] && str="${str}+${n_channels}"
    echo $str
}

normalize_formatstring()
{
    local str_language str_format n_channels flag_special
    split_formatstring "$1"
    create_formatstring
}

# ----------------------------------------------------------------------------
#
# is_integer - check, if the parameter is an interger number
# is_real    - check, if the parameter is a real number
#
# return: 1 = not numeric; 0 = numeric
#
is_integer()
{
    [ -z "$1" -o -n "$(echo $1 | tr -d [:digit:])" ] && return 1;
    return 0;
}

is_real()
{
    local result
    result=$(echo "$1+0" | bc 2>/dev/null)
    [ "$1" == "$result" ] && return 0;
    return 1;
}


# ----------------------------------------------------------------------------
#
# trim_title - Cut long title strings down to fit into the title container
#
trim_title()
{
    maxlen=$1
    ft=$2
    fs=$3
    trimText=$4
    [ ! -z "$ft" ] && ft="-font $ft"
    thislen=$(convert -size $normSize xc:black -fill white \
	          $ft -pointsize $fs -gravity west \
	          -annotate +0+0 "$trimText" -trim +repage miff:- | identify -format %w -)
    while [ $thislen -gt $maxlen ]; do
	twords=$(echo $trimText | wc -w)
	if [ $twords -gt 1 ]; then
	    trimText="$(echo $trimText | cut -d' ' -f1-$(( $twords-1 )))..."
	else
	    trimText=${trimText%%'...'}
	    trimText="${trimText:0:$(( ${#trimText}-1 ))}..."
	fi
	thislen=$(convert -size $normSize xc:black -fill white \
	    $ft -pointsize $fs -gravity west \
	    -annotate +0+0 "$trimText" -trim +repage miff:- | identify -format %w -)
    done
	
    return 0
}

# ----------------------------------------------------------------------------
#
# cleanup_tmpdir - Remove scripts temporary directory
#
cleanup_tmpdir()
{
    # Get the basename of the temporary directory and the length of the 
    # scriptname
    #
    dirbasename="$(basename "$DVDWIZARD_TMPDIR")"
    scriptnamelen=${#thisscript}
    
    # Extract scriptname from temporare directory
    #
    scriptname="${dirbasename:0:$scriptnamelen}"
	
    # Remove directory if it was created within this script
    #
    [ "$scriptname" == "$thisscript" ] && rm -R "$DVDWIZARD_TMPDIR"
	
    return 0
}

#
#  End of dvdwizard script functions
#
