#!/usr/bin/bash
#
# The update command

scriptdir=$( dirname $(readlink -fn $0))
source $scriptdir/lpf-defs.bash


function update_package_close()
# Issue update complete message.
{
    local pkg=$1
    local state=$( get_state $pkg )

    if [ -n "$DISPLAY" ]; then
        local text="<tt>$( list_states )</tt>"
        zenity --info --title "Update complete" --text="$text"\
             --width=750  || :
    fi
    echo "$pkg: exiting" >&5
}


function update_package()
# Push package through FSM until state is in [OK, failed, not-approved].
{
    local pkg=$1
    local state="$( get_state $pkg )"

    [ "$state" = 'failed' ] && state='build-wait'
    [ "$state" = 'not-approved' ] && state='approve-wait'
    $scriptdir/lpf-pkgbuild 'set-state' $pkg $state
    until [[ 'OK failed not-approved' == *$state* ]]; do
        case $state in
            'approve-wait')
                 $scriptdir/lpf-approve $pkg || "$scriptdir/lpf-kill-pgroup"
                 ;;
            'build-wait')
                 LPF_UPDATE=1 $scriptdir/lpf-build $pkg || \
                     echo "$pkg: build errors"  >&5
                 ;;
            'install-wait')
                 $scriptdir/lpf-install $pkg
                 ;;
            'untriaged')
                 $scriptdir/lpf-pkgbuild 'scan' "$@"
                 ;;
        esac
        state=$( get_state $pkg )
    done
}


function confirm_update_arg()
{
    local pkg state version
    read pkg state version < <( list_states $@ ) || exit 1;
    if [[ 'failed approve-wait build-wait install-wait not-approved' \
           == *$state* ]]
    then
        echo "$pkg"
        return 0
    elif [ "$DISPLAY" ]; then
        text="$pkg is already in state $state and can't be updated."
    zenity --info --title "Update: info" --text="$text"
    else
        echo "$pkg: state $state can't be updated" >&6
        echo "$pkg: exiting" >&6
        exit 2
    fi
}


function cli_confirm_update()
# Check what packages to update with user (CLI)
{
    local to_install
    local states=$( list_states )

    [ -z "$states" ] && return
    set $( echo $states )
    while [ -n "$*" ]; do
         if [ "$2" = 'failed' ]; then
             local msg="Rebuild and install failed build for $1 ($3)"
             msg="$msg (yes/no) [y]? "
             echo -n $msg >&5
         elif [ "$2" != 'OK' ]; then
             echo -n "Build and install $1 ($3) (yes/no) [y]? " >&5
         else
             shift 3
             continue
         fi
         read
         [[ $REPLY = [yY]* ]] && to_install=( ${to_install[@]} $1 )
         shift 3
    done
    echo ${to_install[@]}
}


function gui_confirm_update()
# Check what packages to update with user (GUI).
{
    local update_states=' approve-wait | build-wait | failed | not-approved '
    local listdata=( \
        $( list_states | egrep "$update_states" | sed 's/^/True /'))
    zenity --list --title "Select packages to build and install" --checklist \
        --column Install --column Package --column State --column Version  \
        --width 700 --separator=' ' ${listdata[@]} \
            || $scriptdir/lpf-kill-pgroup
}


function get_to_update()
# Return list of packages to update.
{
    local pkg state lpf_vers curr_vers states
    declare -A states

    $scriptdir/lpf-pkgbuild 'scan' "$@"
    while read pkg state lpf_vers; do
        curr_vers=$( rpm -q $pkg 2>/dev/null ) || curr_vers='-'
        [[ 'approve-wait build-wait failed not-approved' == *$state* ]] && \
            states[$pkg]="$pkg $state $lpf_vers $curr_vers\n"
    done < <( list_states )

    if [ -z "${states[*]}" ]; then
        ( unset LPF_UPDATE || :
          info "Nothing to update" \
            "All lpf packages built and installed"
        )
        $scriptdir/lpf-kill-pgroup
    fi

    local to_update
    if (( $# == 1 && ${#states[@]} == 1 )); then
        to_update=( "$@" )
    elif [ -n "$*" ]; then
        to_update=$( confirm_update_arg "$@" ) || to_update=()
    elif [ -n "$DISPLAY" ]; then
        to_update=( $(gui_confirm_update "${states[@]}") )
    else
        to_update=( $(cli_confirm_update "${states[@]}") )
    fi
    echo "${to_update[@]}"
}


function update_packages()
{
    local pkg="$1"

    update_package $pkg
    local state=$( get_state $pkg )
    if [[ "$state" == 'failed' && -n "$DISPLAY" ]]; then
        local reply=$( $scriptdir/build_error )
        [ "$reply" = 'view_buildlog' ] && show_buildlog $pkg
    fi
    update_package_close $pkg
}


trap "do_trap 84" SIGINT ERR
exec 5<&1 6<&2
export LPF_UPDATE=1
$scriptdir/lpf-notify lock

to_update=$( get_to_update $@ )
for pkg in ${to_update[@]}; do
    if [ -n "$DISPLAY" ]; then
        update_packages $pkg  | "$scriptdir/update"
    else
        update_packages $pkg
    fi
done

$scriptdir/lpf-notify unlock


# vim: set expandtab ts=4 sw=4:
