
declare -A CMDS

cmd-list() {
	declare desc="Lists available commands"
	declare ns="$1"
	cmd-list-keys "$ns" | sed "s/$ns://"
}

cmd-list-keys() {
	declare ns="$1"
	for k in "${!CMDS[@]}"; do
		echo "$k"
	done | grep "^$ns:" | sort
}

cmd-list-ns() {
	for k in "${!CMDS[@]}"; do
		echo "$k"
	done | grep -v : | sort
}

cmd-export() {
	declare desc="Exports a function as a command"
	declare fn="$1" as="${2:-$1}"
	local ns=""
	for n in $(cmd-list-ns); do
		echo "$fn" | grep "^$n-" &> /dev/null && ns="$n"
	done
	CMDS["$ns:${as/#$ns-/}"]="$fn"
}

cmd-export-ns() {
	declare ns="$1" desc="$2"
	eval "$1() {
		declare desc=\"$desc\"
		cmd-ns $1 \"\$@\";
	}"
	cmd-export "$1"
	CMDS["$1"]="$1"
}

cmd-ns() {
	local ns="$1"; shift
	local cmd="$1"; shift || true
	local status=0
	if cmd-list "$ns" | grep ^"$cmd"\$ &> /dev/null; then
		${CMDS["$ns:$cmd"]} "$@"
	else
		if [[ "$cmd" ]]; then
			echo "No such command: $cmd"
			status=2
		elif [[ "$ns" ]]; then
			fn-desc "$ns"
		fi
		echo
		echo "Available commands:"
		for cmd in $(cmd-list "$ns"); do
			printf "  %-24s %s\n" "$cmd" "$(fn-desc "${CMDS["$ns:$cmd"]}")"
			for subcmd in $(cmd-list "$cmd"); do
				printf "    %-24s %s\n" "$subcmd" "$(fn-desc "${CMDS["$cmd:$subcmd"]}")"
			done
		done
		echo
		exit $status
	fi
}

cmd-help() {
	declare desc="Shows help information for a command"
	declare args="$*"
	if [[ "$args" ]]; then
    	for cmd; do true; done # last arg
    	local ns="${args/%$cmd/}"; ns="${ns/% /}"; ns="${ns/ /-}"
    	local fn="${CMDS["$ns:$cmd"]}"
    	fn-info "$fn" 1
	else
		cmd-ns ""
	fi
}
cmd-export cmd-help help
