#!/bin/bash
# This is the main CLI interface to autopackage

###
#
# 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-2005 Mike Hearn (mike@plan99.net)
#
###

# setup XDG configuration variables scoped for autopackage
#
#   AUTOPACKAGE_CONFIG_HOME     User configuration directory
#   AUTOPACKAGE_CONFIG_DIRS     System configuration directories
#   AUTOPACKAGE_CONFIG_DIR      Determined system configuration directory for autopackage

if [ -z "$AUTOPACKAGE_CONFIG_HOME" ]; then
    export AUTOPACKAGE_CONFIG_HOME
    if [ -z "$XDG_CONFIG_HOME" ]; then
        AUTOPACKAGE_CONFIG_HOME="$HOME/.config"
    else
        AUTOPACKAGE_CONFIG_HOME="$XDG_CONFIG_HOME"
    fi
fi

if [ -z "$AUTOPACKAGE_CONFIG_DIRS" ]; then
    export AUTOPACKAGE_CONFIG_DIRS
    if [ -z "$XDG_CONFIG_DIRS" ]; then
        AUTOPACKAGE_CONFIG_DIRS="/etc/xdg"
    else
        AUTOPACKAGE_CONFIG_DIRS="$XDG_CONFIG_DIRS"
    fi
fi

if [ -z "$AUTOPACKAGE_CONFIG_DIR" ]; then
    export AUTOPACKAGE_CONFIG_DIR
    _AUTOPACKAGE_CONFIG_DIRS=$( echo "$AUTOPACKAGE_CONFIG_DIRS" | tr ':' ' ' )
    for _CONFIGURATION_DIR in $_AUTOPACKAGE_CONFIG_DIRS; do
        if [ -e "$_CONFIGURATION_DIR/autopackage/config" ]; then
            AUTOPACKAGE_CONFIG_DIR="$_CONFIGURATION_DIR"
            break
        fi
    done
    unset _AUTOPACKAGE_CONFIG_DIRS
fi

# set defaults that might not be loaded from system configurations
export autopackage_deny_user=false

# load system configurations
[ -e /etc/autopackage/config ] && source /etc/autopackage/config;
[ -e "$AUTOPACKAGE_CONFIG_DIR/autopackage/config" ] && source "$AUTOPACKAGE_CONFIG_DIR/autopackage/config";

# load user configuration if allowed from system configuration
if ! $autopackage_deny_user; then
    [ -e "$AUTOPACKAGE_CONFIG_HOME/autopackage/config" ] && source "$AUTOPACKAGE_CONFIG_HOME/autopackage/config";
fi

if [ -e "$autopackage_prefix/share/autopackage/apkg-funclib" ]; then
	source "$autopackage_prefix/share/autopackage/apkg-funclib"
else
	# do not use support functions as they are probably not available
	echo; echo "The support code could not find its installation directory.

Remove the support code files from these possible locations and re-install.
       file: /usr/bin/package
       file: ~/.local/bin/package
       file: /usr/bin/makeinstaller
       file: ~/.local/bin/makeinstaller
  directory: /usr/share/autopackage/
  directory: ~/.local/share/autopackage/
  directory: /usr/libexec/autopackage/
  directory: ~/.local/libexec/autopackage/
  directory: /etc/autopackage
  directory: ~/.config/autopackage
"
	exit 1
fi

[ ! checkConfigVersion ] && exit 1;

# initialize variables
_initializeAutopackage

# allow packages to be directly executed
# other entrances are through _retrieveLocalPackage and _retrieveFromNet
export _autopackage_execute_package=1


##
# _systemInfo
#
# Prints out system configuration information about host machine to file and to
# screen. Use with trace output file to debug efficiently. File output is to the
# respective packages location. Trace output is in packages/logs.
function _systemInfo() {
	locateCommand kde-config "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand bash "-version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand gnome-config "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand pkg-config "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand gnome-panel "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand info "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand gettext "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand wc "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand grep "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand perl "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand awk "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	locateCommand sed "--version"
	_systemInfo "$lc_command" "$lc_location" "$lc_output"

	_systemInfo "glibc" "/lib/libc.so.6" "`/lib/libc.so.6`"

	echo "System configuration information saved to file: $AUTOPACKAGE_DEBUG_LOGFILE"
	echo "System configuration information saved to file: $AUTOPACKAGE_DEBUG_LOGFILE" >> "$AUTOPACKAGE_DEBUG_LOGFILE"

	return 0
}

# init the frontend then run the given command within it
function _runWithFE()
{
	export run_arg="$@"
	trace run_arg="$run_arg"
	export autopackage_pipe="${TMP}/apkg-fifo$$"
	rm -f "$autopackage_pipe" # in case we get an old crashed pid
	mkfifo "$autopackage_pipe"
	(
	    waitForHELLO
	    $run_arg
            r=$?
	    terminateFE
            exit $r
	) &

        local pid=$!

	_launchFE "$autopackage_pipe"
        rm "$autopackage_pipe"

        # must be last statement
        wait $pid
}

function _verify()
{
	for arg in $@; do
	        trace verifying $arg
		identify "$arg" "0" "verify"
		result=`verifyPackage "$arg"`
		r=$?
		if [[ $r -eq 2 ]]; then
			## what gives this result?!?
			outputFail "$intl_PACKAGE_BROKEN"
			#out "$result" ## CONVERT TO SUMMARY VIEW
			err "self repair goes here ;)"
		elif [[ $r -eq 0 ]]; then
			_output "DISPLAY-SUMMARY
verify
success

"
		fi
	done
}

function _uninstall() {
    _processPackageOptions "$@"

    # move beyond option arguments
    count_shift=0
    while (( count_shift < shift_count )); do
        shift
        (( count_shift++ ))
    done

    trace package arguments are $@

    # check that any package arguments exist
    if [[ "$@" == "" ]] && [ -z "$option_filename" ]; then _packageReturnCode "7"; return "$?"; fi;

    # process the package names from text lines in declared file
    if [ -n "$option_filename" ]; then
        if [ ! -r "$option_filename" ]; then
            _packageReturnCode "10" "$option_filename"
            return "$?";
        fi

        # remove qtfe and gtkfe first
        if [ -n "$_remove_qtfe" ]; then
        uninstallPackage $_remove_qtfe
            local r=$?
            [[ "$r" != "0" ]] && return $r
            unset _remove_qtfe
        fi
        if [ -n "$_remove_gtkfe" ]; then
        uninstallPackage $_remove_gtkfe
            local r=$?
            [[ "$r" != "0" ]] && return $r
            unset _remove_gtkfe
        fi

        while read; do
            local line=`echo "$REPLY"`
            # do not remove qtfe, gtkfe or support code directly
            # qtfe and gtkfe are removed as first in session with autopackage being last
            if [[ "$line" != "autopackage-qt" ]] && [[ "$line" != "autopackage-gtk" ]] && [[ "$line" != "autopackage" ]]; then
                uninstallPackage "$line"
                local r=$?
                [[ "$r" != "0" ]] && return $r
            fi
        done <"$option_filename"

        if [[ "$?" != "0" ]]; then
            return $?
        fi

        # remove autopackage last
        if [ -n "$_remove_apkg" ]; then
            if ! uninstallPackage "$_remove_apkg"; then
                return $?
            fi
            unset _remove_apkg
        fi

    # process the command line package names
    else

        # remove qtfe and gtkfe first
        if [ -n "$_remove_qtfe" ]; then
            uninstallPackage "$_remove_qtfe"
            local r=$?
            [[ "$r" != "0" ]] && return $r
            unset _remove_qtfe
        fi
        if [ -n "$_remove_gtkfe" ]; then
            uninstallPackage "$_remove_gtkfe"
            local r=$?
            [[ "$r" != "0" ]] && return $r
            unset _remove_gtkfe
        fi

        declare -a args
        args=("$@")
        local count=${#args[@]}
        local curpkg=0
        while (( curpkg < count )); do
            # do not remove qtfe, gtkfe or support code directly
            # qtfe and gtkfe are removed as first in session with autopackage being last
            if [[ "${args[$curpkg]}" != "autopackage-qt" ]] && [[ "${args[$curpkg]}" != "autopackage-gtk" ]] && [[ "${args[$curpkg]}" != "autopackage" ]]; then
                uninstallPackage "${args[$curpkg]}"
                local r=$?
                [[ "$r" != "0" ]] && return $r
            fi
            (( curpkg++ ))
        done

        # remove autopackage last
        if [ -n "$_remove_apkg" ]; then
            uninstallPackage "$_remove_apkg"
            local r=$?
            [[ "$r" != "0" ]] && return $r
            unset _remove_apkg
        fi
    fi
}


function _processPackageOptions() {
    # process the CLI arguments
    trace called with $@
    export shift_count
    force="false" # default
    while [[ "$1" != "" ]]; do
        case `echo $1 | sed 's/=.*//'` in
            "-p" | "--prefix")
                export PREFIX=$( chewArgument $1 $2 );
                if [[ ${PREFIX:0:1} != "/" ]]; then
                    PREFIX="`pwd`/${PREFIX}"
                fi
                trace forcing PREFIX=$PREFIX

                # if $1 contains '=' then shift once
                # because it is a combined argument
                if echo "$1" | grep '=' >/dev/null; then
                    shift
                    (( shift_count++ ))
                else
                    shift; shift;
                    (( shift_count++ )); (( shift_count++ ));
                fi

                if [[ "$PREFIX" == "" ]]; then red; outn "$intl_FAIL"; normal; out "$intl_PREFIX_NOT_SPECIFIED"; exit 1; fi;

                # mark where prefix was set
                export _prefix=commandline
                trace _prefix=$_prefix
                ;;

            "-f" | "--force")
                shift
                (( shift_count++ ));
                force="true"
                trace forcing force=$force
                ;;

            "-F")
                export option_filename=$( chewArgument $1 $2 );
                if [[ ${option_filename:0:1} != "/" ]]; then
                    option_filename="`pwd`/${option_filename}"
                fi

                # if $1 contains '=' then shift once
                # because it is a combined argument
                if echo "$1" | grep '=' >/dev/null; then
                    shift
                    (( shift_count++ ))
                else
                    shift; shift;
                    (( shift_count++ )); (( shift_count++ ));
                fi
                trace forcing option_filename=$option_filename
                ;;

            "-g" | "--gtkfe")
                shift
                (( shift_count++ ))
                export AUTOPACKAGE_FRONTEND="autopackage-frontend-gtk"
                trace forcing AUTOPACKAGE_FRONTEND=$AUTOPACKAGE_FRONTEND
                ;;

            "-h" | "--help")
                shift
                (( shift_count++ ))
                out "$intl_INSTALLER_HELP"
                _installerFinish
                exit 0
                ;;

            "-u" | "--user")
                shift
                (( shift_count++ ))
                export user_mode="--user"
                trace forcing user_mode=$user_mode
                ;;

            "-t" | "--ttyfe")
                shift
                (( shift_count++ ))
                export AUTOPACKAGE_FRONTEND="apkg-ttyfe"
                trace forcing AUTOPACKAGE_FRONTEND=$AUTOPACKAGE_FRONTEND
                ;;

            -*)
                red; outn "$intl_FAIL"; normal; out "$intl_UNKNOWN_OPTION" "$1";
                _installerFinish 1
                ;;

            *)
                return 0
                ;;
        esac

    done

}

function _install() {

    _processPackageOptions "$@"

    # move beyond option arguments
    count_shift=0
    while (( count_shift < shift_count )); do
        shift
        (( count_shift++ ))
    done

    trace package arguments are $@

    # check that any package arguments exist
    if [[ "$@" == "" ]] && [ -z "$option_filename" ]; then _packageReturnCode "7"; return "$?"; fi;

    # process the package names from text lines in declared file
    if [ -n "$option_filename" ]; then
        if [ ! -r "$option_filename" ]; then
            _packageReturnCode "10" "$option_filename"
            return "$?";
        fi
        while read; do
            line=`echo "$REPLY"`
            bash $line
        done <"$option_filename"

    # process the command line package names
    else
        declare -a args
        args=("$@")
        local count="${#args[@]}"
        i=0
        while (( i < count )); do
            if [ -e "${args[$i]}" ]; then

                if [ ! -r "${args[$i]}" ]; then
                    _packageReturnCode "10" "${args[$i]}";
                    return 10
                fi

                # verify autopackage package file
                if ! head -n 3 "${args[$i]}" | grep --text -q '# autopackage '; then
                    _packageReturnCode "4" "${args[$i]}";
                    return 4
                fi

                trace executing "${args[$i]}"
                ( bash "${args[$i]}" )
                local r=$?
                [[ "$r" != "0" ]] && return $r

            else
                _packageReturnCode "1" "${args[$i]}";
                return 1
            fi
            (( i++ ))
        done
    fi
    return 0
}


function _search() {
    # process the package names from text lines in declared file
    if [[ "$1" == "-f" ]]; then
        force="true"
        shift
    else
        force="false"
    fi
    if [[ "$1" == "-F" ]]; then
        shift;
        install_filename="$1"
        if [ ! -r "$install_filename" ]; then
            _packageReturnCode "10" "$install_filename"
            exit "$?";
        fi
        while read; do
            line=`echo "$REPLY"`
            _searchPackage $line
        done <"$install_filename"
    fi

    # process the command line package names
    if [ ! "$install_filename" ]; then
        args=("$@")
        count="${#args[@]}"
        i=0
        while (( $i < count )); do
            _searchPackage "${args[$i]}"
            (( i++ ))
        done
    fi
}


function _update() {

    # determine user mode
    if [[ "$1" == "--user" ]]; then
        user_mode="--user"
    fi

    # process the package names from text lines in declared file
    if [[ "$1" == "-f" ]]; then
        force="true"
        shift
    else
        force="false"
    fi
    if [[ "$1" == "-F" ]]; then
        shift;
        update_filename="$1"
        if [ ! -r "$update_filename" ]; then
            _packageReturnCode "10" "$update_filename"
            exit "$?";
        fi
        while read; do
            line=`echo "$REPLY"`
            _updatePackage $user_mode $line
        done <"$update_filename"
    fi

    # process the command line package names
    if [ ! "$update_filename" ]; then
        args=("$@")
        count="${#args[@]}"
        i=0
        while (( $i < count )); do
            _updatePackage $user_mode "${args[$i]}"
            (( i++ ))
        done
    fi
}


function _package_display_help() {
	out "$intl_PACKAGE_HELP_1"
	out
	out "$intl_PACKAGE_HELP_2"
	out
	out "$intl_PACKAGE_HELP_3"
	out
	out "$intl_PACKAGE_HELP_4"
	out
	out "$intl_PACKAGE_HELP_5"
	out
	out "$intl_PACKAGE_HELP_6"
}
# do we have any arguments at all?
if [ $# -eq "0" ]; then
    _package_display_help;
    _installerFinish "1"
fi


case "$1" in
    "-h" | "--help" | "help") # help mode
        _package_display_help
        _installerFinish "0"
        ;;

    "-v" | "--version" | "version") # version mode
        out "$intl_PACKAGE_VERSION" "$autopackage_version"
        _installerFinish "0"
        ;;

    "-s" | "--system" | "system") # system mode
        _systemInfo
        _installerFinish "0"
        ;;

    "-l" | "--list" | "list") # list mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # list package database (user first, then global)
        _listPackages $user_mode
        _installerFinish $?
        ;;

    "-f" | "--files" | "files") # filelist mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # check that any package arguments exist
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; _installerFinish "$?"; fi;

        # we currently only support querying the package database & package files
        # query the package database (user first, then global)
        if _loadPackage $user_mode "$1"; then
                _listPackageFiles "$1"
        # the specified package isn't installed
        else
                _packageReturnCode "1" "$1"
        fi
        _installerFinish $?
        ;;

    "-g" | "--log" | "log") # log mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # check that any package arguments exist
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; _installerFinish "$?"; fi;

        # we currently only support querying the package database & package files
        # query the package database (user first, then global)
        if _loadPackage $user_mode "$1"; then
            _listPackageLog "$1"
        # the specified package isn't installed
        else
            _packageReturnCode "1" "$1"
        fi
        _installerFinish "0"
        ;;

    "-o" | "--owner" | "owner") # package owner of file mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # check that any package arguments exist
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; _installerFinish "$?"; fi;

        _listFilePackage "$@"
        _installerFinish "0"
        ;;

    "info") # info mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # check that any package arguments exist
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; _installerFinish "$?"; fi;

        # we currently only support querying the package database & package files
        # query the package database (user first, then global)
        if _loadPackage $user_mode "$1"; then
            _packageInfo "$1"
        # the specified package isn't installed
        else
            _packageReturnCode "1" "$1"
        fi
        _installerFinish "0"
        ;;

    "search") # search mode
        shift;
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; exit "$?"; fi;
        _search "$@"
        _installerFinish "0"
        ;;

#     "update") # update mode
#         shift;
#         if [[ "$@" == "" ]]; then _packageReturnCode "7"; exit "$?"; fi;
#         _update "$@"
#         _installerFinish "0"
#         ;;

    "remove" | "uninstall") # remove mode
        shift
        _processPackageOptions "$@"

        # move beyond option arguments
        count_shift=0
        while (( count_shift < shift_count )); do
            shift
            (( count_shift++ ))
        done

        trace package arguments are $@

        # check that any package arguments exist
        if [[ "$@" == "" ]] && [ -z "$option_filename" ]; then _packageReturnCode "7"; _installerFinish "$?"; fi;

        # if autopackage-qt, autopackage-gtk or support code is a listed package name
        # switch frontend to ttyfe, remove qtfe and gtkfe as first packages and autopackage as last

        # check in filelisting package names
        if [ -n "$option_filename" ]; then
            if [ -r "$option_filename" ]; then
                while read; do
                    if [[ "$REPLY" == "autopackage-qt" ]]; then
                        export _remove_qtfe="autopackage-qt"
                    elif [[ "$REPLY" == "autopackage-gtk" ]]; then
                        export _remove_gtkfe="autopackage-gtk"
                    elif [[ "$REPLY" == "autopackage" ]]; then
                        export _remove_apkg="autopackage"
                    fi
                done <"$option_filename"
            fi

        # check command line package names
        else
            declare -a args
            args=("$@")
            count="${#args[@]}"
            i=0
            while (( i < count )); do
                if [[ "${args[$i]}" == "autopackage-qt" ]]; then
                    export _remove_qtfe="autopackage-qt"
                elif [[ "${args[$i]}" == "autopackage-gtk" ]]; then
                    export _remove_gtkfe="autopackage-gtk"
                elif [[ "${args[$i]}" == "autopackage" ]]; then
                    export _remove_apkg="autopackage"
                fi
                # # check that the package names are valid - a later check will determine if it can be removed
                # if [[ "${args[$i]}" != "autopackage" ]] && ! _resolveName "${args[$i]}" >/dev/null; then
                # 	_packageReturnCode "1" "${args[$i]}"
                # 	exit "$?"
                # fi
                (( i++ ))
            done
        fi

        # set apkg-ttyfe here before the frontend is initialized
        if [ -n "$_remove_qtfe" ] || [ -n "$_remove_gtkfe" ]; then
            export AUTOPACKAGE_FRONTEND="apkg-ttyfe"
        fi
        _runWithFE _uninstall $@
        _installerFinish $?
        ;;

    "install") # install mode
        shift;
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; exit "$?"; fi;
        _install "$@"
        _installerFinish $?
        ;;

    "verify") # verify mode
        shift;
        if [[ "$@" == "" ]]; then _packageReturnCode "7"; exit "$?"; fi;
        export _context="verify"
        _runWithFE _verify $@
        _installerFinish $?
        ;;

    *) # default mode [ALL]
        _packageReturnCode "15" "$1"
        _installerFinish $?
        ;;

esac
