/
area/
classes/net/sourceforge/pain/logic/
classes/net/sourceforge/pain/logic/event/
classes/net/sourceforge/pain/logic/fn/util/
classes/net/sourceforge/pain/network/console/
classes/net/sourceforge/pain/plugin/
classes/net/sourceforge/pain/plugin/reset/
classes/net/sourceforge/pain/plugin/shutdown/
classes/net/sourceforge/pain/plugin/social/
classest/net/sourceforge/pain/db/data/
doc/
doc/paindb/resources/
src/net/sourceforge/pain/logic/
src/net/sourceforge/pain/logic/event/
src/net/sourceforge/pain/logic/fn/util/
src/net/sourceforge/pain/network/console/
src/net/sourceforge/pain/network/console/telnet/
src/net/sourceforge/pain/plugin/
src/net/sourceforge/pain/plugin/command/
src/net/sourceforge/pain/plugin/reset/
src/net/sourceforge/pain/plugin/shutdown/
src/net/sourceforge/pain/plugin/social/
src/net/sourceforge/pain/util/
tests/
tests/net/sourceforge/pain/db/data/
package net.sourceforge.pain.plugin.command;


import net.sourceforge.pain.util.*;

import java.util.*;

public class CommandRegistry {

	private final HashMap prefixMapping = new HashMap(1024);
	final HashMap exactMapping = new HashMap(1024);
	private final HashMap commandNamesByClassName = new HashMap(1024);

	CommandRegistry() {
	}

	public LinkedHashMap findCommandsByPrefix(String prefix) {
		prefix = prefix.toLowerCase();
		PrefixEntry entry = (PrefixEntry) prefixMapping.get(prefix);
		if (entry == null) {
			return null;
		}
		return entry.commands;
	}

	public void registerCommand(TextCommand command) {
		final String name = command.name;
		if (exactMapping.containsKey(name)) {
			throw new IllegalArgumentException("command with this name already registered:" + name);
		}
		for (int i = 0; i < name.length(); i++) {
			String prefix = name.substring(0, i + 1);
			PrefixEntry entry = (PrefixEntry) prefixMapping.get(prefix);
			if (entry == null) {
				entry = new PrefixEntry();
				prefixMapping.put(prefix, entry);
			}
			entry.commands.put(name, command);
		}
		exactMapping.put(name, command);
		addToClassNameMapping(command);
	}

	private void addToClassNameMapping(TextCommand command) {
		HashSet commandNames = (HashSet) commandNamesByClassName.get(command.commandClassName);
		if (commandNames == null) {
			commandNames = new HashSet();
			commandNamesByClassName.put(command.commandClassName, commandNames);
		}
		commandNames.add(command.name);
	}

	public void unregisterCommand(String name) {
		name = name.toLowerCase();
		TextCommand command = (TextCommand) exactMapping.remove(name);
		if (command == null) {
			return;
		}
		for (int i = name.length(); i > 0; i--) {
			String prefix = name.substring(0, i);
			PrefixEntry entry = (PrefixEntry) prefixMapping.get(prefix);
			if (entry == null) {
				return;
			}
			entry.commands.remove(name);
			if (entry.commands.isEmpty()) {
				prefixMapping.remove(prefix);
			}
		}
		removeFromClassNameMapping(command);
	}

	private void removeFromClassNameMapping(TextCommand command) {
		HashSet commandNames = (HashSet) commandNamesByClassName.get(command.commandClassName);
		if (commandNames == null) {
			Log.warn("BUG:removeFromClassNameMapping: commandsNames is null");
			return;
		}
		commandNames.remove(command.name);
		if (commandNames.isEmpty()) {
			commandNamesByClassName.remove(command.commandClassName);
		}
	}


	public TextCommand findCommandByPrefix(String prefix) {
		LinkedHashMap commandsByPrefix = findCommandsByPrefix(prefix);
		if (commandsByPrefix == null || commandsByPrefix.isEmpty()) {
			return null;
		}
		return (TextCommand) commandsByPrefix.values().iterator().next();
	}

	public Set getAllCommandsForClassName(String className) {
		return (Set) commandNamesByClassName.get(className);
	}

	private static class PrefixEntry {
		LinkedHashMap commands = new LinkedHashMap();
	}

}