#!/bin/sh

readonly LANG=C
readonly PKGNAME=$(make -V PKGNAME 2>/dev/null)
readonly PREFIX=$(make -V PREFIX 2>/dev/null)
plist_file=$1

if [ ! "$PKGNAME" -o ! "$PREFIX" ]; then
	echo "===> This is not port directory" >&2
	exit 1
fi

[ "$plist_file" ] || plist_file=$(make -V PLIST)
if [ ! -f "$plist_file" ]; then
	echo "===> Plist file was not found: $plist_file" >&2
	exit 1
fi

options_subs="PORTDOCS PORTEXAMPLES"
for sub in $(make -V PLIST_SUB); do
	case $sub in *@comment*)
		case $sub in NO_*) sub=${sub##NO_}; esac
		options_subs="$options_subs ${sub%%=*}"
	esac
done

awk -v prefix="$PREFIX/" -v plist_subs="$(make -V PLIST_SUB)" \
	-v options_subs="$options_subs" '
BEGIN {
	separator="###";

	n = split(options_subs, s_array, " ");
	for (i=1; i<=n; i++)
		opt_subs[s_array[i]] = s_array[i];

	n = split(plist_subs, array, " ");
	for (pair=1; pair<=n; pair++) {
		if (split(array[pair], p_array, "=") != 2)
			continue;
		if (p_array[1] in opt_subs)
			continue;
		gsub("\"", "", p_array[2]);
		if (p_array[2] && p_array[2] != "@comment")
			subs[p_array[1]] = p_array[2];
	}
}

function store_pathname(path, tokens) {
	is_dir = match(tokens, "@dir");

	if (match(path, "^/")) # nonprefix items
		(is_dir) ? dirs_np[path] = tokens : files_np[path] = tokens;
	else
		(is_dir) ? dirs[path] = tokens : files[path] = tokens;
}

function str_replace(string, pattern, new_pattern) {
	str="";

	if ((sr_fields = split(string, sr_array, pattern)) == 1)
		return string;
	for (sr_index=1; sr_index <= sr_fields; sr_index++) {
		if (sr_index != sr_fields)
			str = str sr_array[sr_index] new_pattern;
		else
			str = str sr_array[sr_index];
	}
	return str;
}

function plist_split(string, out) {
	pos = index(string, " ");
	out[1] = substr(string,1, pos-1);
	out[2] = substr(string, pos+1);
}

function keyword_line_tokenize(line, keyword) {
	path = chunks = "";
	# little hack to get depth first sorting order
	# suffix is removed after sort in untokenize function
	suffix = (keyword == "dir") ? "zzz" : "";

	if ((n = split(line, array, "%%")) == 1) {
		plist_split(array[1], p);
		store_pathname(p[2], p[2] suffix separator p[1]);
		return;
	}
	for (i=1; i <= n; i++) {
		if (match(array[i], "^@" keyword)) {
			plist_split(array[i], p);
			path = p[2];
			chunks = chunks separator p[1];
			continue;
		}
		if (array[i] in opt_subs) {
			chunks = chunks separator array[i];
			continue;
		}
		if (array[i] in subs) {
			path = path subs[array[i]];
			chunks = chunks separator array[i];
		} else
			path = path array[i];
	}
	store_pathname(path, path suffix chunks);
}

function keyword_line_untokenize(line, keyword) {
	cmd=""

	if ((n = split(line, p, separator)) == 2) {
		if (keyword == "dir")
			sub(/zzz$/, "", p[1]);
		printf("%s %s\n", p[2], p[1]);
		return;
	}
	path = p[1];
	for (i=2; i <= n; i++) {
		if (match(p[i], "^@" keyword)) {
			cmd = cmd p[i];
			continue;
		}
		if (cmd == "")
			cmd = "%%" p[i] "%%";
		else if (p[i] in subs)
			path = str_replace(path, subs[p[i]], "%%" p[i] "%%");
	}
	if (keyword == "dir")
		sub(/zzz$/, "", path);
	printf("%s %s\n", cmd, path);
}

function sort_to_file(array, file) {
	for (i in array) print array[i] | ("sort -u >" file);
	close("sort -u >" file);
}

function truncate_file(file) {
	close(file);
	system("cat /dev/null>" file);
}

function print_files(array, file) {
	sort_to_file(array, file);

	while((getline line < file) > 0) {
		if (match(line, "@\\(.*\\)")) {
			keyword_line_untokenize(line, "");
			continue;
		}
		if (match(line, "@sample")) {
			keyword_line_untokenize(line, "sample");
			continue;
		}
		if ((n = split(line, p, separator)) == 1) {
			print p[1];
			continue;
		}
		path = p[1];
		for (i=2; i<=n; i++) {
			if (p[i] in opt_subs) {
				path = "%%" p[i] "%%" path;
				continue;
			}
			if (p[i] in subs) {
				path = str_replace(path, subs[p[i]], "%%" p[i] "%%");
				continue;
			}
			path = p[i] path;
		}
		print path;
	}
	truncate_file(file);
}

function print_dirs(array, file) {
	sort_to_file(array, file);
	while((getline line < tmpfile) > 0)
		keyword_line_untokenize(line, "dir");
	truncate_file(file);
}

/^(%%[0-9A-Z_]*%%)*([a-z]|\/)+/ { # files
	path = chunks = "";

	if ((n = split($0, array, "%%")) == 1) {
		store_pathname(array[1], array[1]);
		next;
	}
	for (i=1; i <= n; i++) {
		if (array[i] in opt_subs) {
			chunks = chunks separator array[i];
			continue;
		}
		if (array[i] in subs) {
			path = path subs[array[i]];
			chunks = chunks separator array[i];
		} else
			path = path array[i];
	}
	store_pathname(path, path chunks);
}

/^(%%[0-9A-Z_]*%%)*@dir/ { # dirs
	keyword_line_tokenize($0, "dir");
}

/^(%%[0-9A-Z_]*%%)*@sample/ {
	keyword_line_tokenize($0, "sample");
}

/^(%%[0-9A-Z_]*%%)*@\(.*\)/ {
	keyword_line_tokenize($0, "");
}

/^(%%[0-9A-Z_]*%%)*@/ { # other commands, @exec, @unexec etc
	if (match($0, "@(dir|sample)") || match($0, "@\\(.*\\)"))
		next;
	cmds[++n_cmds] = $0;
}

END {
	"mktemp -t plist-sort" | getline tmpfile;
	close("mktemp -t plist-sort");

	print_files(files, tmpfile);
	print_files(files_np, tmpfile);
	print_dirs(dirs, tmpfile);
	print_dirs(dirs_np, tmpfile);
	system("rm " tmpfile);

	for (i in cmds)
		print cmds[i];
}' "$plist_file"
