#!/bin/sh

echo_error() # private
{
	printf %s\\n "${0##*/}: $*" >&2
}

array_count() # private
{
	local name="$1"
	eval set -- "\$$2"
	eval "$name=$#"
}

define() # private
{
	eval "$1_$2=\"\$3\""
}

define_array() # private
{
	array_count n "ARRAY_$1_$2"
	eval "$1_$2_$n=\"\$3\"; ARRAY_$1_$2=\"\$ARRAY_$1_$2 $1_$2_$n\""
}

lookup() # private
{
	eval "$1=\"\$$2_$3\""
}

lookup_array() # private
{
	eval "$1=\"\$ARRAY_$2_$3\""
}

validate() # private
{
	printf %s "$1" | grep -q '^[a-z0-9_]*$'
}

NAME_LIST=
register() # private
{
	eval "test -z \"\$REGISTERED_$1\"" || return
	define REGISTERED "$1" yes
	[ -z "$NAME_LIST" ] && NAME_LIST="$1" || NAME_LIST="$NAME_LIST $1"
}

new_fmode()
{
	register "$1"
	define NAME_TO_FMODE "$1" "$2"
	define NAME_TO_OWNER "$1" "$3:$4"
	define FMODE_OWNER_TO_NAME "$2_$3_$4" "$1"
}

new_subst()
{
	register "$1"
	define_array NAME_TO_REGEX "$1" "$2"
	define_array NAME_TO_SUBST "$1" "$3"
}

new_help()
{
	register "$1"
	define HELP_TO "$1" "$2"
}

new_summary()
{
	local arg="$1"
	if [ -z "${arg##*
*}" ]; then
		arg="$(printf %s "$arg" |tr -s '[:space:]' ' ')"
	fi
	define SUMMARY FOR "$arg"
}

stat_file() # private
{
	local PATHNAME="$1"
	[ -z "${PATHNAME##/*}" ] || return 1
	find "$PATHNAME" -maxdepth 0 -path "$PATHNAME" -printf '%m_%u_%g'
}

control_list()
{
	printf %s\\n "$NAME_LIST"
}

control_help()
{
  	local NAME VALUE SEARCH_LIST

	if [ -n "$1" ]; then
		SEARCH_LIST="$*"
	else
		SEARCH_LIST="$NAME_LIST"
	fi

	for NAME in $SEARCH_LIST; do
		printf %s "$NAME: "
		lookup VALUE HELP_TO "$NAME"
		printf %s\\n "$VALUE"
	done
}

control_fmode_status() # private
{
	local FILE="$1" STAT NAME=

	STAT="$(stat_file "$FILE")"
	if validate "$STAT"; then
		lookup NAME FMODE_OWNER_TO_NAME "$STAT"
	fi
	if [ -n "$NAME" ]; then
		printf %s\\n "$NAME"
	else
		echo "unknown"
	fi
}

control_fmode()
{
	local FILE="$1" REQUEST="$2" FMODE= OWNER=

	case "$REQUEST" in
	help|'help '*)
		control_help "${REQUEST#help}"
		;;
	list)
		control_list
		;;
	status)
		control_fmode_status "$FILE"
		;;
	summary)
		control_summary
		;;
	*)
		if validate "$REQUEST"; then
			lookup FMODE NAME_TO_FMODE "$REQUEST"
			lookup OWNER NAME_TO_OWNER "$REQUEST"
		fi
		if [ -z "$FMODE" -o -z "$OWNER" ]; then
			echo_error "Invalid mode: $REQUEST"
			return 1
		fi
		if [ "$(control_fmode_status "$FILE")" = "$REQUEST" ]; then
			return
		fi
		chown "$OWNER" "$FILE" && chmod "$FMODE" "$FILE" || return 1
		;;
	esac
}

control_subst_status() # private
{
	local FILE="$1" ARRAY ELEM FOUND NAME REGEX

	for NAME in $NAME_LIST; do
		FOUND=
		lookup_array ARRAY NAME_TO_REGEX "$NAME"
		for ELEM in $ARRAY; do
			eval "REGEX=\"\$$ELEM\""
			[ -n "$REGEX" ] || continue
			grep -Eq "$REGEX" "$FILE" &&
				FOUND=1 ||
				{ FOUND=; break; }
		done
		if [ -n "$FOUND" ]; then
			printf %s\\n "$NAME"
			return
		fi
	done
	echo "unknown"
}

control_subst()
{
	local FILE="$1" REQUEST="$2" ARRAY= ELEM SUBST=

	case "$REQUEST" in
	help|'help '*)
		control_help "${REQUEST#help}"
		;;
	list)
		control_list
		;;
	status)
		control_subst_status "$FILE"
		;;
	summary)
		control_summary
		;;
	*)
		if validate "$REQUEST"; then
			lookup_array ARRAY NAME_TO_SUBST "$REQUEST"
		fi
		if [ -z "$ARRAY" ]; then
			echo_error "Invalid mode: $REQUEST"
			return 1
		fi
		for ELEM in $ARRAY; do
			eval "SUBST=\"\$$ELEM\""
			if [ -z "$SUBST" ]; then
				echo_error "Invalid mode: $REQUEST"
				return 1
			fi
			[ "$(control_subst_status "$FILE")" != "$REQUEST" ] || continue
			sed -i --follow-symlinks -e "$SUBST" -- "$FILE" || return 1
		done
		;;
	esac
}

control_summary()
{
	printf %s\\n "$SUMMARY_FOR"
}

is_builtin_mode()
{
	case "$1" in
	''|help|'help '*|list|status|summary)
		return 0
		;;
	esac
	return 1
}

[ -n "$*" ] || set - status
