#!/usr/bin/env runawk

# Copyright (c) 2009-2013 Aleksey Cheusov <vle@gmx.net>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#env "LC_ALL=C"

#use "alt_assert.awk"
#use "init_getopt.awk"
#use "tmpfile.awk"
#use "xsystem.awk"

############################################################
#.begin-str help
# paexec_reorder - takes output of 'paexec -le' or 'paexec -gle' on
#     input and outputs ordered results, that is without "slicing".
# usage: paexec_reorder [OPTIONS]
# OPTIONS:
#    -h              display this help
#    -g              expects output of "paexec -gle",
#                    by default -- "paexec -le".
#    -S              remove leading space
#    -l              prepand output line with the task number
#                    given on input
#    -x              synonym for -y
#    -y              output of "paexec -le [g] -y" is expected on input
#    =M <method>     method of resorting result line, where method is
#       m               in-memory sort (the default)
#       s               use sort(1) command
#       f               use multiple temporary files
#    =m s=<success>  set alternative string for 'success', 'failure',
#       f=<failure>  'fatal' and '' (end of task).
#       F=<fatal>
#       t=<eot>
#
# In -g -Mm and -g -Mf modes, portions of the result followed
# by "fatal" marker are automatically cut off.
#.end-str
############################################################

BEGIN {
	method = "m"

	msg_success = "success"
	msg_failure = "failure"
	msg_fatal   = "fatal"
	msg_eot     = ENVIRON ["PAEXEC_EOT"]

	while (getopt(short_opts)){
		if (optopt == "h"){
			print_help()
			exitnow(0)
		}else if (optopt == "g"){
			graph_mode = 1
		}else if (optopt == "S"){
			remove_spc = 1
		}else if (optopt == "l"){
			output_task = 1
		}else if (optopt == "M"){
			method = optarg
		}else if (optopt == "m"){
			if (optarg ~ /^s=/){
				msg_success = substr(optarg, 3)
			}else if (optarg ~ /^f=/){
				msg_failure = substr(optarg, 3)
			}else if (optarg ~ /^F=/){
				msg_fatal = substr(optarg, 3)
			}else if (optarg ~ /^t=/){
				msg_eot = substr(optarg, 3)
			}else{
				abort("bad argument for -m")
			}
		}else if (optopt == "y" || optopt == "x"){
			msg_eot = "HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5"
		}else{
			abort()
		}
	}

	bad_input_msg = "bad input, did you run paexec -sle?"

	# -Ms
	if (output_task)
		sort_cmd = "sort -k2n -k1n -t ' ' | cut -f 2- -d ' '"
	else
		sort_cmd = "sort -k2n -k1n -t ' ' | cut -f 3- -d ' '"
}

# -Mm
function print_results (task,        cnt,i){
	if (graph_mode && !(task in pline))
		return

	if (!graph_mode || pline [task] == msg_success || ppline [task] == msg_failure){
		cnt = count [task]
		for (i=1; i <= cnt; ++i){
			if (output_task)
				printf "%s ", task
			print line [task, i]
			delete line [task, i]
		}

		count [task] = 0
	}else if (pline [task] == msg_fatal){
		count [task] = 0
	}else{
		abort(bad_input_msg)
	}
}

# common code
{
	assert(NF > 0 && $0 ~ /^[0-9]+ /, bad_input_msg)
	if (task > task_max)
		task_max = task
}

# -Ms
method == "s" {
	if (! (match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot)){
		if (remove_spc){
			num = $1
			sub(/^[0-9]+  ?/, "", $0)
			print NR, num, $0 | sort_cmd
		}else{
			print NR, $0 | sort_cmd
		}
	}

	next
}

# -Mf
function print_results_file (task,      cmd,fn){
	if (task in count){
		fn = runawk_tmpdir "/" task
		xclose(fn)
		cmd = sprintf("cat '%s' && rm '%s'", fn, fn)
		xsystem(cmd)
		delete count [task]
	}
}

method == "f" {
	if (match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot){
		if (!graph_mode || pline [$1] != msg_fatal){
			print_results_file(task)
		}else{
			fn = runawk_tmpdir "/" task
			xclose(fn)
			xsystem("rm '" fn "'")
			delete count [task]
		}
	}else{
		if (graph_mode){
			ppline [$1] = pline [$1]
			pline [$1] = $2
		}

		task = $1
		count [task] = 1

		if (remove_spc)
			sub(/^[0-9]+  ?/, "")
		else
			sub(/^[0-9]+ /, "")

		fn = runawk_tmpdir "/" task
		if (output_task)
			print task, $0 > fn
		else
			print $0 > fn
	}

	next
}

# -Mm
match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot {
	print_results($1)
	next
}

{
	if (graph_mode){
		ppline [$1] = pline [$1]
		pline [$1] = $2
	}

	task = $1
	sub(/^[0-9]+ /, "", $0)
	cnt = ++count [task]

	if (remove_spc)
		sub(/^ /, "", $0)
	line [task, cnt] = $0
}

END {
	# output of "paexec -l" (without -e) is also allowed, obviously
	# this requires more memory for reordering results, so applying
	# option -e is strongly recomended.
	if (method == "m"){
		# -Mm
		for (i=1; i <= task_max; ++i){
			print_results(i)
		}
	}else if (method == "f"){
		# -Mf
		for (i=1; i <= task_max; ++i){
			print_results_file(i)
		}
	}
}
