/*
 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.eclipse.jgit.pgm;

import static org.eclipse.jgit.lib.Constants.CHARSET;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

/**
 * List of all commands known by jgit's command line tools.
 * <p>
 * Commands are implementations of {@link org.eclipse.jgit.pgm.TextBuiltin},
 * with an optional {@link org.eclipse.jgit.pgm.Command} class annotation to
 * insert additional documentation or override the default command name (which
 * is guessed from the class name).
 * <p>
 * Commands may be registered by adding them to a services file in the same JAR
 * (or classes directory) as the command implementation. The service file name
 * is <code>META-INF/services/org.eclipse.jgit.pgm.TextBuiltin</code> and it
 * contains one concrete implementation class name per line.
 * <p>
 * Command registration is identical to Java 6's services, however the catalog
 * uses a lightweight wrapper to delay creating a command instance as much as
 * possible. This avoids initializing the AWT or SWT GUI toolkits even if the
 * command's constructor might require them.
 */
public class CommandCatalog {
	private static final CommandCatalog INSTANCE = new CommandCatalog();

	/**
	 * Locate a single command by its user friendly name.
	 *
	 * @param name
	 *            name of the command. Typically in dash-lower-case-form, which
	 *            was derived from the DashLowerCaseForm class name.
	 * @return the command instance; null if no command exists by that name.
	 */
	public static CommandRef get(String name) {
		return INSTANCE.commands.get(name);
	}

	/**
	 * Get all commands sorted by their name
	 *
	 * @return all known commands, sorted by command name.
	 */
	public static CommandRef[] all() {
		return toSortedArray(INSTANCE.commands.values());
	}

	/**
	 * Get all common commands sorted by their name
	 *
	 * @return all common commands, sorted by command name.
	 */
	public static CommandRef[] common() {
		final ArrayList<CommandRef> common = new ArrayList<>();
		for (CommandRef c : INSTANCE.commands.values())
			if (c.isCommon())
				common.add(c);
		return toSortedArray(common);
	}

	private static CommandRef[] toSortedArray(Collection<CommandRef> c) {
		final CommandRef[] r = c.toArray(new CommandRef[c.size()]);
		Arrays.sort(r, new Comparator<CommandRef>() {
			@Override
			public int compare(CommandRef o1, CommandRef o2) {
				return o1.getName().compareTo(o2.getName());
			}
		});
		return r;
	}

	private final ClassLoader ldr;

	private final Map<String, CommandRef> commands;

	private CommandCatalog() {
		ldr = Thread.currentThread().getContextClassLoader();
		commands = new HashMap<>();

		final Enumeration<URL> catalogs = catalogs();
		while (catalogs.hasMoreElements())
			scan(catalogs.nextElement());
	}

	private Enumeration<URL> catalogs() {
		try {
			final String pfx = "META-INF/services/"; //$NON-NLS-1$
			return ldr.getResources(pfx + TextBuiltin.class.getName());
		} catch (IOException err) {
			return new Vector<URL>().elements();
		}
	}

	private void scan(URL cUrl) {
		try (BufferedReader cIn = new BufferedReader(
				new InputStreamReader(cUrl.openStream(), CHARSET))) {
			String line;
			while ((line = cIn.readLine()) != null) {
				if (line.length() > 0 && !line.startsWith("#")) //$NON-NLS-1$
					load(line);
			}
		} catch (IOException e) {
			// Ignore errors
		}
	}

	private void load(String cn) {
		final Class<? extends TextBuiltin> clazz;
		try {
			clazz = Class.forName(cn, false, ldr).asSubclass(TextBuiltin.class);
		} catch (ClassNotFoundException notBuiltin) {
			// Doesn't exist, even though the service entry is present.
			//
			return;
		} catch (ClassCastException notBuiltin) {
			// Isn't really a builtin, even though its listed as such.
			//
			return;
		}

		final CommandRef cr;
		final Command a = clazz.getAnnotation(Command.class);
		if (a != null)
			cr = new CommandRef(clazz, a);
		else
			cr = new CommandRef(clazz);

		commands.put(cr.getName(), cr);
	}
}
