#!/bin/awk -f
BEGIN {
	FS="\t"
	SUBSEP="."
	state = 0
	# 0 read normal variables
	# 1 seen start of field list, read titles
	# 2 reading list values
	# ident_re = /[a-zA-Z_][a-zA-Z0-9_]*/
	ident_re = "[a-zA-Z_][a-zA-Z0-9_]*"
}

$0 == "]" && state == 2 {
	# end of field list
	state = 0
	next
}

state == 2 {
	V[varname,++V[varname,"rows"]] = $0
	next
}

state == 1 {
	if((varname, "fields") in V) {
		if(V[varname,"fields"] != $0) {
			print "data.awk: differing field definition for '"varname"'" >"/dev/stderr"
			print "previous: '"V[varname,"fields"]"'" >"/dev/stderr"
			print "current:  '"$0"'" >"/dev/stderr"
			exit 1
		}
	}
	V[varname,"fields"] = $0
	state = 2
	next
}

/^del[ \t].*[a-zA-Z_][a-zA-Z0-9_.]$/ {
	del_pattern = substr($0, 5)
	for(varname in V) {
		if (match(varname, del_pattern)) {
			delete V[varname]
		}
	}
}

/^[a-zA-Z_][a-zA-Z0-9_.]*=\[$/ {
	# start of field list
	state = 1
	m = match($0, ident_re)
	varname = substr($0, m, RLENGTH)
	next
}

/^[a-zA-Z_][a-zA-Z0-9_.]*=/ {
	m = match($0, ident_re)
	varname = substr($0, m, RLENGTH)
	V[varname] = substr($0, m+1+RLENGTH)
	if(DEBUG) printf "got scalar: %s = %s (%d)\n", varname, V[varname], m >"/dev/stderr"
	next
}

/^\t/ {
	V[varname] = V[varname] "\n" substr($0, 1)
	next
}

/^#/ { next }
/^$/ { next }

{
	# TODO posix compliance
	print "data.awk: unparseable line: '"$0"'" >"/dev/stderr"
	exit 1
}

function data_not_found_error(varname, type) {
	if(ENVIRON["DATA_AWK_EMPTY_GET"]) {
		if(DEBUG) {
			print type" not found: " varname >"/dev/stderr"
		}
	} else {
		print "error: undefined "type" '"varname"'" >"/dev/stderr"
		exit 1
	}
}

function loop_start(varname, prefix,    depth) {
	if(!((varname, "fields") in V)) {
		data_not_found_error(varname, "table")
	}
	depth = ++loop_stack["depth"]
	loop_stack[depth,"row"] = 0
	loop_stack[depth,"var"] = varname
	loop_stack[depth,"pre"] = prefix
	return depth
}

function loop_iter(depth) {
	loop_stack[depth,"row"]++
	return (loop_stack[depth,"var"], loop_stack[depth,"row"]) in V
}

function loop_end() {
	delete loop_stack[loop_stack["depth"], "row"]
	delete loop_stack[loop_stack["depth"], "var"]
	delete loop_stack[loop_stack["depth"], "pre"]
	loop_stack["depth"]--
}

function find(varname,   i, n, names, values, loopvar, looprow, prefix) {
	for(i=loop_stack["depth"]; i>0; i--) {
		prefix = loop_stack[i, "pre"]
		if(prefix)
			if(substr(varname, 1, length(prefix)) != prefix)
				continue
		loopvar = loop_stack[i, "var"]
		looprow = loop_stack[i, "row"]
		if(varname == prefix"_index") {
			found = looprow
			return 1
		}
		if(varname == prefix"_index0") {
			found = looprow - 1
			return 1
		}
		if(varname == prefix"_revindex") {
			found = V[loopvar, "rows"] - looprow + 1
			return 1
		}
		if(varname == prefix"_revindex0") {
			found = V[loopvar, "rows"] - looprow
			return 1
		}
		if(varname == prefix"_first") {
			found = looprow == 1
			return 1
		}
		if(varname == prefix"_last") {
			found = looprow == V[loopvar, "rows"]
			return 1
		}
		if(varname == prefix"_length") {
			found = V[loopvar, "rows"]
			return 1
		}
		split(V[loopvar, "fields"], names)
		for(n in names) {
			if(varname == (prefix names[n])) {
				split(V[loopvar, looprow], values)
				found = values[n]
				return 1
			}
		}
	}
	if(!(varname in V)) {
		return 0
	}
	found = V[varname]
	return 1
}

function get(varname) {
	if(!find(varname)) {
		data_not_found_error(varname, "scalar")
		found = ""
	}
	if(DEBUG) {
		print "get →" varname "← = →"found"←" >"/dev/stderr"
	}
	return found
}

function or_(a, b) {
	return a ? a : b
}

END {
	if(DEBUG) {
		print "--- loaded keys ---" >"/dev/stderr"
		for(key in V) {
			printf("%s\t→%s←\n", key, V[key]) >"/dev/stderr"
			printf(">> %d →%s←\n", find(key), found) >"/dev/stderr"
		}
		print "-------------------" >"/dev/stderr"
	}
}