#!/bin/sh

po_domain="alterator-pkg"

cachedir="/var/cache/alterator"
ready_log="$cachedir/pkg-upgrade-ready.log"
progress_log="$cachedir/pkg-upgrade-progress.log"
full_log="$cachedir/pkg-upgrade-full.log"
out_log="$cachedir/pkg-upgrade-out.log"
error_log="$cachedir/pkg-upgrade-error.log"
state_log="$cachedir/pkg-upgrade-state.log"
inpipe="$cachedir/pkg-upgrade-in.pipe"

send_cmd="/usr/bin/alterator-mailbox-send"

set -f

. alterator-sh-functions

do_cleanup()
{
    rm -f "$inpipe"
    rm -f \
	"$ready_log" \
	"$out_log" \
	"$error_log" \
	"$progress_log" \
	"$state_log"
}

### process

process_make()
{
	local rc=0

	echo "pkg-upgrade:start"
	LANG=C "$1" || rc=$?
	echo "pkg-upgrade:finish:$rc"
}

process_test()
{
    pidof apt-get >/dev/null 2>/dev/null
}

process_start()
{
    if process_test ;then
	write_error "`_ "process already running"`"
	return 1
    else
	do_cleanup
	stdin_handler|process_make "$@" 2>"$error_log"|tee "$full_log"|stdout_handler &
	return 0
    fi
}

process_stop()
{
    echo "ready" >"$state_log"
    killall apt-get >/dev/null 2>/dev/null
    stdin_write "q"
}

### handlers

stdin_handler()
{
    [ -p "$inpipe" ] || (rm -rf "$inpipe"; mkfifo -m600 "$inpipe")

    while :; do
        [  -e "$inpipe" ] || break
    	while read n; do
	    if [ "$n" = "q" ]; then
		rm -f "$inpipe"
		break 2
	    fi
	    echo "$n"
	done < "$inpipe"
    done
    rm -f "$inpipe"
}

stdin_write()
{
    [ ! -p "$inpipe" ] || echo "$1" >"$inpipe"
}

title_printf()
{
    printf '\n%s:\n%s\n' "$1" "$2"
}

message_quote()
{
    echo "$1"|string_quote
}

stdout_handler()
{
    local line=
    local total=0
    local current=0

    while read -r line;do
	local state="ready"
	[ -s "$state_log" ] && state="$(cat "$state_log")"

	case "$line" in
	    #final report
	    pkg-upgrade:finish:*)
		if [ "$state" = "upgrade" -o "$state" = "check" ];then
		    if [ "${line##*:}" -eq 0 ];then
			if [ "$state"  = "check" ];then
			    if [ -s "$out_log" ];then
				mv -f "$out_log" "$ready_log"
			    else
				echo "`_ "No updates available"`" >"$ready_log"
			    fi
			else
			    echo "`_ "Upgrade is complete"`" >"$ready_log"
			fi
		    else
		    printf '%s:\n' "`_ "Fatal error"`" >"$ready_log"
		    cat "$error_log" >>"$ready_log"
		    fi
		fi
		process_stop
		;;
	    #cdrom change
	    apt-get:media-change:*)
		echo "waiting" >"$state_log"
		printf '%s: %s\n' \
		    "`_ "Please insert CDROM labeled as"`" \
		    "${line##*:}" >"$ready_log"
		;;
	    #collect packages
	    apt-get:install-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Packages to install"`" "${line##*:}" >>"$out_log"
		;;
	    apt-get:extra-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Additional packages to install"`" "${line##*:}" >>"$out_log"
		;;
	    apt-get:upgrade-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Packages to upgrade"`" "${line##*:}" >>"$out_log"
		;;
	    apt-get:remove-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Packages to REMOVE"`" "${line##*:}" >>"$out_log"
		;;
	    apt-get:replace-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Packages will be REPLACED"`" "${line##*:}" >>"$out_log"
		;;
	    apt-get:keep-list:*)
		[ "$state" = "check" ] &&
		    title_printf "`_ "Packages have been kept back"`" "${line##*:}" >>"$out_log"
		;;

	    #collect counter
	    apt-get:status:upgrade:*|apt-get:status:install:*)
		if [ "$state" = "upgrade" ];then
		    total=$(($total + ${line##*:}))
		fi
		;;
	    #progress
	    Preparing*)
		if [ "$state" = "upgrade" ];then
		    echo "`_ "Start packages installation..."`" > "$progress_log"
		    current=0
		fi
		;;
	    Get:[0-9]*)
		if [ "$state" = "upgrade" ];then
		    printf '%s:%s%%\n' "`_ "Acquiring packages"`" "$(( ($current * 100) / $total ))" >"$progress_log"
		    current=$(( $current + 1 ))
		elif [ "$state" = "check" ];then
		    printf '%s...\n' "`_ "Acquiring package database..."`" > "$progress_log"
		fi
		;;
	    *)
		if [ "$state" = "upgrade" ] && echo "$line"|egrep -qs "^([^[:blank:]#]+)[[:space:]]*#.+";then
		    printf '%s:%s%%\n' "`_ "Installing packages"`" "$(( ($current * 100) / $total ))" >"$progress_log"
		    current=$(( $current + 1 ))
		fi
		;;
	esac
	[ -x "$send_cmd" ] && "$send_cmd" "message \"$(message_quote "$line")\"" 2>/dev/null
    done
}


exit_handler()
{
    local rc=$?
    trap - EXIT

    process_stop
    do_cleanup

    exit $rc
}

trap exit_handler HUP INT QUIT TERM EXIT

### operations

do_check()
{
    echo "`_ "Checking for updates..."`">"$progress_log"
    echo "check" >"$state_log"
    apt-get update && echo 'n'| apt-get dist-upgrade --simple-output
    [ "$?" -lt 100 ]
}

do_upgrade()
{
    echo "`_ "Upgrade is starting..."`">"$progress_log"
    echo "upgrade" >"$state_log"
    apt-get -y dist-upgrade --simple-output
}

### main message loop

on_message()
{
    local state="ready"
    [ -s "$state_log" ] && state="$(cat "$state_log")"

	case "$in_action" in
		read)
		    echo '('
		    case "$in__objects" in
			log)
			    local msg=
			    
			    if [ -s "$full_log" ];then
				msg="$(string_quote "$full_log")"
			    else
				msg="`_ "No log available"`"
			    fi

			    printf 'msg "%s"' "$msg"
			    ;;
			*)
			    local msg=

			    if [ "$state" = "check" -o "$state" = "upgrade" ];then
				[ -s "$progress_log" ] && msg="$(string_quote "$progress_log")"
			    elif [ -s "$ready_log" ]; then
				msg="$(string_quote "$ready_log")"
			    else
				msg="`_ "No information available"`"
			    fi

			    printf 'state "%s"\n' "$state"
			    printf 'msg "%s"\n' "$msg"
			    ;;
		    esac
		    echo ')'
		    ;;
		write)
		    if [ -n "$in_check" -a "$state" = "ready" ];then
			process_start do_check || return
		    elif [ -n "$in_upgrade" -a "$state" = "ready" ];then
			process_start do_upgrade || return
		    elif [ -n "$in_continue" ];then
			echo "upgrade">"$state_log"
			stdin_write "y"
		    elif [ -n "$in_cancel" ];then
			process_stop
			do_cleanup
		    fi
		    write_nop
		    ;;
		*)
		    echo '#f'
		    ;;
	esac
}

do_cleanup
message_loop
