//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.library;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.epf.library.internal.LibraryManagerElement;
import org.osgi.framework.Bundle;

/**
 * Manages the creation of Library Manager instances.
 * 
 * @author Kelvin Low
 * @since 1.0
 */
public class LibraryManagerFactory {

	/**
	 * The extension point namespace.
	 */
	public static final String EXTENSION_POINT_NAMESPACE = "org.eclipse.epf.library"; //$NON-NLS-1$

	/**
	 * The extension point name.
	 */
	public static final String EXTENSION_POINT_NAME = "libraryManagers"; //$NON-NLS-1$

	// The shared instance.
	private static LibraryManagerFactory instance = null;

	// A map of library manager configuration elements.
	private Map libraryManagerElements = new HashMap();

	/**
	 * Returns the shared instance.
	 */
	public static LibraryManagerFactory getInstance() {
		if (instance == null) {
			synchronized (LibraryManagerFactory.class) {
				if (instance == null) {
					instance = new LibraryManagerFactory();
				}
			}
		}
		return instance;
	}

	/**
	 * Creates a new instance.
	 */
	private LibraryManagerFactory() {
		init();
	}

	/**
	 * Performs the necessary initialization.
	 */
	protected void init() {
		// Process the "org.eclipse.epf.library.libraryManagers" extension point
		// contributors.
		IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
		IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(
				EXTENSION_POINT_NAMESPACE, EXTENSION_POINT_NAME);
		if (extensionPoint != null) {
			IExtension[] extensions = extensionPoint.getExtensions();
			for (int i = 0; i < extensions.length; i++) {
				IExtension extension = extensions[i];
				String pluginId = extension.getNamespaceIdentifier();
				Bundle bundle = Platform.getBundle(pluginId);
				IConfigurationElement[] configElements = extension
						.getConfigurationElements();
				for (int j = 0; j < configElements.length; j++) {
					IConfigurationElement configElement = configElements[j];
					try {
						String className = configElement.getAttribute("class"); //$NON-NLS-1$
						String typeId = configElement.getAttribute("type"); //$NON-NLS-1$
						String typeName = configElement
								.getAttribute("typeName"); //$NON-NLS-1$
						if (className != null && className.trim().length() > 0
								&& typeId != null && typeId.trim().length() > 0
								&& typeName != null
								&& typeName.trim().length() > 0) {
							if (!libraryManagerElements.containsKey(typeId)) {
								LibraryManagerElement provider = new LibraryManagerElement(
										bundle, className, typeId, typeName);
								libraryManagerElements.put(typeId, provider);
							}
						}
					} catch (Exception e) {
						LibraryPlugin.getDefault().getLogger().logError(e);
					}
				}
			}
		}
	}

	/**
	 * Creates a new library manager instance.
	 * 
	 * @param type
	 *            the method library type
	 * @return a library manager
	 * @throw <code>CreateLibraryManagerException</code> if an error occurs
	 *        while performing the operation
	 */
	public ILibraryManager createLibraryManager(String type)
			throws CreateLibraryManagerException {
		LibraryManagerElement provider = (LibraryManagerElement) libraryManagerElements
				.get(type);
		if (provider == null) {
			throw new CreateLibraryManagerException();
		}
		try {
			Class clazz = provider.getBundle().loadClass(
					provider.getClassName());
			return (ILibraryManager) clazz.newInstance();
		} catch (Exception e) {
			throw new CreateLibraryManagerException(e);
		}
	}

	/**
	 * Returns all the library types registered via the
	 * "org.eclipse.epf.library.libraryManagers" extension point.
	 * 
	 * @return a map of library types
	 */
	public Map getLibraryTypes() {
		Map types = new HashMap();
		for (Iterator it = libraryManagerElements.keySet().iterator(); it
				.hasNext();) {
			String typeId = (String) it.next();
			String typeName = ((LibraryManagerElement) libraryManagerElements
					.get(typeId)).getTypeName();
			types.put(typeId, typeName);
		}
		return types;
	}

}
