# -*-shell-script-*-

# UI abstraction protocol code

###
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright 2002-2004 Mike Hearn (mike@navi.cx)
#
###

# remember to modify this in the ttyfe and gtkfe!
PROTOCOL_VERSION=7

function _output() {
    local a="$1"
    shift
    local b="$@"
    cat <<EOF > "$autopackage_pipe"
$a
$b
EOF

    fe_result=`<"$autopackage_pipe"`  # wait for feedback signal
    if [[ "$fe_result" == "OK" ]]; then
	return 0;
    elif [[ "$fe_result" == "ABORT" ]]; then
	return 1;
    fi
}

##
# outputStatus <STATUS>
# STATUS: A status message.
#
# Show the current status of the installation.
#
# Match against __outputStatus_status variable if it exists. If the variable is different from
# the current call then display status message.
#
# Example:
# outputStatus "Installing plugin for foobar..."
# copyFiles libplugin.so /usr/lib/foobar/plugins
function outputStatus() {
   # check for function status variable to possibly reduce ui output
   if [[ "$__outputStatus_status" == "$__outputStatus_history" ]] && [[ "$__outputStatus_status" != "" ]]; then
       # copy to history to keep for next call and clear current
       __outputStatus_history="$__outputStatus_status"
       unset __outputStatus_status
       return 0
   else
       if [ ! -e "$autopackage_pipe" ]; then
           # if using functions from console like a library, check for pipe existence
           out "`echo \"$@\"`"
           return
       fi
       # copy to history to keep for next call and clear current
       __outputStatus_history="$__outputStatus_status"
       unset __outputStatus_status
       _output "STATUS" "`echo \"$@\"`"
       return $?
   fi
}


##
# outputTest <WHAT>
# WHAT: A short description of the test currently being performed.
#
# Tells the user that the installation is currently testing for something.
#
# This function is designed to be used within package prep scripts. It will be called for you by require()
# when using the skeletons framework, so should be rarely used explicitly, but you can also use it in your own scripts.
# It will indicate to the user that their system is currently being tested. It should be followed by a call
# to either outputTestFail, outputTestPass or outputTestRecommend.
#
# The output will be of the form "Checking for $1.... " - ie you should not provide the preamble, instead you should
# provide a succint description of what is being tested. For instance, a good string to use would be "ability to play
# Ogg Vorbis files", and bad string to use would be "Can we play Ogg files?". Remember: don't phrase it as a question,
# instead as a description.
#
# Also remember to try and keep the description simple. Don't use jargon unless it's really necessary. That way,
# if a test fails and the system cannot fix the problem itself, the users will find it easier to do so themselves.
#
# See also: outputTestPass() and outputTestFail().
#
# Example:
# outputTest "GTK User Interface toolkit"
# outputTest "Ogg Vorbis playback capabilities"
# outputTest "ability to connect to the internet"
function outputTest() {
    _output "TEST" "$1"
    return $?
}


##
# outputTestFail
#
# Tells the user that the last test failed.
# See also: outputTest() and outputTestPass().
#
# Example:
# outputTest "foobar"		# Frontend displays: "Checking for foobar..."
# if [[ ! -f /usr/bin/foobar ]]; then
# 	outputTestFail		# -> "Checking for foobar... FAILED"
# else
# 	outputTestPass		# -> "Checking for foobar... PASSED"
# fi
function outputTestFail() {
    _output "FAILTEST"
    return $?
}

##
# outputTestPass
#
# Tells the user that the last test passed.
# See also: outputTest() and outputTestFail().
#
# Example:
# outputTest "foobar"		# Frontend displays: "Checking for foobar..."
# if [[ ! -f /usr/bin/foobar ]]; then
# 	outputTestFail		# -> "Checking for foobar... FAILED"
# else
# 	outputTestPass		# -> "Checking for foobar... PASSED"
# fi
function outputTestPass() {
    _output "PASSTEST"
    return $?
}

function outputTestSearching() {
    _output "SEARCHING"
    return $?
}

function outputTestRecommend() {
    _output "RECOMMEND" "$1"
    return $?
}


##
# outputFail <MESSAGE>
# MESSAGE: A short message describing the problem.
#
# Tells the frontend that a fatal error has occurred. The
# frontend will tell the user that the installation has failed
# after the install script has exited.
#
# Please note that you should to call outputTestFail() before
# calling this function, if you've just called outputTest().
#
# Example:
# outputTest "a working installation of foobar"
# if [[ -f /var/broken ]]; then
# 	# The installation of foobar on this system is broken!!!
# 	outputTestFail
# 	outputFail "Foobar is broken!"
# 	false  # This aborts the installation by setting the return value to non-zero
# else
# 	outputTestPass
# fi
function outputFail() {
    _output "FAIL" "$@"
    return $?
}

# ignored for 1.0 compatibility
function switchGroup() {
    true;
}

# $1 = display name
# $2 = short name
# $3 = package manager (autopackage, rpm, dpkg, ...)
function _outputUninstalling() {
    _output "UNINSTALLING" "$1
$2
$3"
}

function _outputUninstallDone() {
    _output "UNINSTALL-DONE"
}

# $1 = textual description of reason
function _outputUninstallFail() {
    _output "UNINSTALL-FAIL" "$@"
}

# $1 = displayname
# $2 = series id
# $3 = context
function identify() {
    _output "IDENTIFY" "$1
$2
$3"
}

# $1 = MAX
function startSeries() {
    _output "SERIES" "$1"
}

##
# progressBar <CURRENT> <MAX> <LABEL> [COMPRESS = 0]
# CURRENT: A number specifying the current value of the progress. This must be greater than 0.
# MAX: A number specifying the maximum value of the progress. This must be greater than 0.
# LABEL: A label associated to this progress.
# COMPRESS: Whether to compress the progress bar. 1 = compress, 0 = don't compress. See description.
#
# Display a progress bar. If CURRENT is equal to MAX, then that means the progress has finished.
#
# If MAX is a very big value (> 100), and your progress bar changes very fast, pass 1 to the COMPRESS argument.
# This will reduce the number of calls to the frontend, which reduces CPU usage. You normally shouldn't have to
# care about this argument, and should only use it in exceptional cases. The progress bar that's shown when
# extracting files is such a case.
#
# Example:
# progressBar 1 10 "Copying files"     # 10% [=>       ] Copying files
# progressBar 5 10 "Copying files"     # 50% [====>    ] Copying files
# progressBar 10 10 "We're done"       # 100%[=========] We're done
function progressBar()
{
	local show=1 marker=$1 boundary=$2
	if [[ "$4" == "1" ]]; then
		(( _progress_bar_skip++ ));
		if [[ "$_progress_bar_skip" != "1" ]] && (( $marker != $boundary )); then
			if (( _progress_bar_skip >= ($boundary / 10) )); then  # the 10 here is the progress bar resolution. increasing it will make it smoother, but slower (as more protocol requests will be sent to the frontend)
				export _progress_bar_skip=0;
			else
				show=0
			fi
		fi
	fi

    if (( $marker > $boundary )); then
        # warn if marker is out of bounds then force to 100% to save gtkfe
        warn $marker is higher than $boundary - adjusting marker
        marker="$boundary"
    fi

	if [[ "$show" == "1" ]]; then
		_output "PROGRESSBAR" "$boundary
$marker
$3"
	fi
}


###############################################


##
# waitForHELLO <NAME>
# NAME: The name of the package (just used to label the frontend with).
#
# Establish communication with the frontend.
function waitForHELLO() {
    # this will block until something reads from it
    echo "HELLO $PROTOCOL_VERSION
$1" >"$autopackage_pipe"
    read <"$autopackage_pipe"

    if echo "$REPLY" | grep "LETS GO" >/dev/null; then
	return 0
    elif echo "$REPLY" | grep "UHOH" >/dev/null; then
	# something went wrong - return the error code
	error_message="$REPLY"
	return 1
    fi
    return 2; ## wtf? we couldn't understand the answer at all
}


##
# terminateFE
#
# Terminates the frontend.
function terminateFE() {
    _output "TERMINATE"
}

##
# _launchFE
#
# Launch a frontend. This function checks whether X and/or a console is available.
# It launches the terminal frontend or the GUI frontend, depending on the results
# of the those checks.
#
# If the environment variable $AUTOPACKAGE_FRONTEND is set, then that will be used
# as frontend instead. X/console availability will not be checked.
function _launchFE()
{
        trace launching frontend
	local xerr

	# try to find xdpyinfo - if not found guess and add path
	locateCommand -l xdpyinfo &>/dev/null
	if [[ "$lc_location" == "" ]]; then
		# Slackware not in path
		[ -e "/usr/X11R6/bin/xdpyinfo" ] && lc_location="/usr/X11R6/bin/xdpyinfo"
	fi

	if [[ "$AUTOPACKAGE_FRONTEND" != "" ]]; then
		if ! "$AUTOPACKAGE_FRONTEND" "$@"; then
		    red; outn "$intl_FAIL"; normal; out "$intl_FE_TERMINATED_ABNORMALLY";
		fi
	elif [[ "$DISPLAY" != "" ]] && xerr=`LANG=C LC_ALL=C $lc_location &>/dev/null`; then
		# we have X, so let's use our spiffy gui FE
		if locateCommand autopackage-frontend-qt; then
			# Use the QT frontend when available
			trace booting qtfe
			autopackage-frontend-qt "$@"
		elif locateCommand autopackage-frontend-gtk; then
			# Use the GTK+ frontend when available
			trace booting gtkfe
			autopackage-frontend-gtk "$@"
		elif tty -s; then
		        # we have a terminal, but no GTK front end, so let's just fall back to the terminal
			trace no gtkfe, booting ttyfe
		        "$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
		else
			# no terminal, but we do have X, so try to launch ttyfe in a new terminal.
			trace no gtkfe, no terminal, do have X: attempting to open ttyfe in new terminal
			launchInTerminal --title "Installing software..." /bin/bash -c "\"$autopackage_prefix/share/autopackage/apkg-ttyfe\" \"$@\"; echo 'Press ENTER to exit.'; read" 2>/dev/null
			# If that didn't work...
			[[ $? != 0 ]] && "$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
		fi
	else
		if [[ "$xerr" != "" ]]; then
			# $DISPLAY is not empty, but we can't launch xdpyinfo.
			red
			echo -n "WARNING: "
			normal

			if echo "$xerr" | grep -q 'not authorized'; then
				echo -n "you (`whoami`) do not have authorization to conenct to the X display server. "
			else
				echo -n "unable to connect to the X display server. "
			fi
			echo "The graphical frontend will not be launched, and the console frontend will be used instead."
		fi

		# no X, let's use the terminal
		"$autopackage_prefix/share/autopackage/apkg-ttyfe" "$@"
	fi
}
