
package raptor.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import raptor.Raptor;
import raptor.alias.AbbreviatedChannelTellAlias;
import raptor.alias.AbbreviatedPersonTellAlias;
import raptor.alias.ActivateScriptAlias;
import raptor.alias.AddExtendedCensorAlias;
import raptor.alias.AddTabAlias;
import raptor.alias.AddTagAlias;
import raptor.alias.AliasHelpAlias;
import raptor.alias.ChannelBotAlias;
import raptor.alias.ClearCensorAlias;
import raptor.alias.ClearChannelsAlias;
import raptor.alias.ClearExtendedCensorAlias;
import raptor.alias.ClearFingerNotesAlias;
import raptor.alias.ClearGNotifyAlias;
import raptor.alias.ClearMemosAlias;
import raptor.alias.ClearNoplayAlias;
import raptor.alias.ClearNotifyAlias;
import raptor.alias.ClearScreenAlias;
import raptor.alias.ClearTagsAlias;
import raptor.alias.ClearVariablesAlias;
import raptor.alias.DeactivateScriptAlias;
import raptor.alias.DumpGamesAlias;
import raptor.alias.GrantSpoofAlias;
import raptor.alias.ListScriptsAlias;
import raptor.alias.MemosAlias;
import raptor.alias.OpenBoardAlias;
import raptor.alias.OpenUrlAlias;
import raptor.alias.PerformanceRatingAlias;
import raptor.alias.RaptorAlias;
import raptor.alias.RaptorAliasResult;
import raptor.alias.RelayAlias;
import raptor.alias.RemoveExtendedCensorAlias;
import raptor.alias.RemoveTagAlias;
import raptor.alias.ScriptAlias;
import raptor.alias.SetConsoleTimeStampOnOffAlias;
import raptor.alias.SetDebugLevelAlias;
import raptor.alias.SetPremoveModeAlias;
import raptor.alias.SetSoundOnOfAlias;
import raptor.alias.ShowExtendedCensor;
import raptor.alias.ShowFenAlias;
import raptor.alias.ShowRegexAlias;
import raptor.alias.ShowScriptAlias;
import raptor.alias.ShowTagsAlias;
import raptor.alias.ShowTellsAlias;
import raptor.alias.TellAllInChannelAlias;
import raptor.alias.TellLastPersonWhoToldYouAlias;
import raptor.alias.TimedCommandAlias;
import raptor.swt.chat.ChatConsoleController;
import raptor.util.RaptorLogger;

@SuppressWarnings("deprecation")
public class AliasService {
	private static final RaptorLogger LOG = RaptorLogger.getLog(AliasService.class);
	public static boolean serviceCreated = false;
	private static Class<?>[] ALIASES = { AbbreviatedChannelTellAlias.class,
			AbbreviatedPersonTellAlias.class, ActivateScriptAlias.class,
			AddExtendedCensorAlias.class, AddTabAlias.class,AddTagAlias.class,
			AliasHelpAlias.class, ChannelBotAlias.class, ClearMemosAlias.class,
			ClearExtendedCensorAlias.class, ClearChannelsAlias.class,
			ClearCensorAlias.class, ClearFingerNotesAlias.class,
			ClearGNotifyAlias.class, ClearNoplayAlias.class,
			ClearNotifyAlias.class, ClearScreenAlias.class,
			ClearTagsAlias.class, ClearVariablesAlias.class,
			DeactivateScriptAlias.class, DumpGamesAlias.class,
			GrantSpoofAlias.class, ListScriptsAlias.class,
			OpenBoardAlias.class, OpenUrlAlias.class,
			PerformanceRatingAlias.class, RelayAlias.class,RemoveTagAlias.class,
			RemoveExtendedCensorAlias.class, ScriptAlias.class,
			SetConsoleTimeStampOnOffAlias.class, SetDebugLevelAlias.class,
			ShowExtendedCensor.class, SetPremoveModeAlias.class,
			MemosAlias.class, SetSoundOnOfAlias.class, ShowFenAlias.class,
			ShowRegexAlias.class, ShowTellsAlias.class, ShowTagsAlias.class,
			ShowScriptAlias.class, TellAllInChannelAlias.class,
			TellLastPersonWhoToldYouAlias.class, TimedCommandAlias.class };
	private static AliasService singletonInstance;

	public static AliasService getInstance() {
		if (singletonInstance != null)
			return singletonInstance;

		singletonInstance = new AliasService();
		return singletonInstance;
	}

	List<RaptorAlias> aliases = new ArrayList<RaptorAlias>(20);

	private AliasService() {
		try {
			long startTime = System.currentTimeMillis();
			for (Class<?> clazz : ALIASES) {
				aliases.add((RaptorAlias) clazz.newInstance());
			}
			Collections.sort(aliases);
			LOG
					.info("AliasService initialized " + aliases.size()
							+ " aliases in "
							+ (System.currentTimeMillis() - startTime));
		} catch (Throwable t) {
			Raptor.getInstance().onError("Error loading AliasService", t);
		}
		serviceCreated = true;
	}

	public void dispose() {
		aliases.clear();
	}

	/**
	 * Returns an alias by name. Returns null if the alias is not found.
	 * 
	 * @param name
	 *            The alias name.
	 * @return The alias, or null if the alias could not be found.
	 */
	public RaptorAlias getAlias(String name) {
		RaptorAlias result = null;
		for (RaptorAlias alias : aliases) {
			if (alias.getName().equalsIgnoreCase(name)) {
				result = alias;
				break;
			}
		}
		return result;
	}

	public RaptorAlias[] getAliases() {
		return aliases.toArray(new RaptorAlias[0]);
	}

	public String getAliasHtml() {
		StringBuilder builder = new StringBuilder(5000);
		builder.append("<html>\n<body>\n");
		builder.append("<h1>Raptor Aliases</h1>\n");
		builder
				.append("<p>Aliases are special commands you can type into a console. "
						+ "Some aliases are preprocessed by Raptor and then sent along to the server."
						+ "Other aliases are Raptor commands which are processed by Raptor and not sent "
						+ "along to the server.</p>\n");

		builder.append("<UL>\n");
		builder.append("<LH>Aliases:</LH>\n");
		for (RaptorAlias alias : getAliases()) {
			if (!alias.isHidden()) {
                builder.append("<LI><a href=\"#").append(alias.getName()).append("\">").append(alias.getName()).append("</a></LI>\n");
			}
		}
		builder.append("</UL>\n");
		builder.append("<br/>\n");

		for (RaptorAlias alias : getAliases()) {
			if (!alias.isHidden()) {
                builder.append("<a name=\"").append(alias.getName()).append("\"><h2>").append(alias.getName()).append("</h2></a>\n");
				builder.append("<h3>Description:</h3>\n");
                builder.append("<p>").append(alias.getDescription()).append("</p>\n");
				builder.append("<h3>Usage:</h3>\n");
                builder.append("<p>").append(alias.getUsage()).append("</p>\n");
				builder.append("<br/>\n");
				builder.append("<br/>\n");
			}
		}
		builder.append("</body></html>\n");
		return builder.toString();
	}

	/**
	 * If null is returned no alias was applied to the command. If a non-null
	 * value was returned an alias was applied.
	 * 
	 * @param command
	 *            The command.
	 * @return The command after applying aliases, or null if on action should
	 *         be taken.
	 */
	public RaptorAliasResult processAlias(ChatConsoleController controller,
			String command) {
		RaptorAliasResult result = null;
		for (RaptorAlias alias : aliases) {
			result = alias.apply(controller, command);
			if (result != null) {
				break;
			}
		}
		return result;
	}
}
