/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * 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:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.core.layout.custom;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.DynaProperty;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.Platform;

import org.maskat.core.MaskatCorePlugin;

public class ComponentRegistry {

	private static Map registry = new HashMap();

	private static Map propertyTypes;
	
	static {
		propertyTypes = new HashMap();
		propertyTypes.put("boolean", java.lang.Boolean.class);
		propertyTypes.put("int", java.lang.Integer.class);
		propertyTypes.put("float", java.lang.Float.class);
		propertyTypes.put("string", java.lang.String.class);
		
		IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(
				MaskatCorePlugin.PLUGIN_ID, "components");
		IExtension[] extensions = point.getExtensions();
		for (int i = 0; i < extensions.length; i++) {
			registerLibraries(extensions[i].getConfigurationElements());
		}
	}

	private static void registerLibraries(IConfigurationElement[] elements) {
		ComponentLibrary library = null;
		for (int i = 0; i < elements.length; i++) {
			IConfigurationElement element = elements[i];
			if (!"library".equals(element.getName())) {
				continue;
			}
			String prefix = element.getAttribute("prefix");
			String namespaceURI = element.getAttribute("namespaceURI");

			try {
				if (element.getAttribute("class") != null) {
					library = (ComponentLibrary) element
							.createExecutableExtension("class");
				} else {
					library = new ComponentLibrary(prefix, namespaceURI);
					registerComponentTypes(library, element
							.getChildren("component"));
				}
				registry.put(namespaceURI, library);
			} catch (CoreException e) {
				MaskatCorePlugin.log(e.getStatus());
			}
		}
	}
	
	private static void registerComponentTypes(ComponentLibrary library,
			IConfigurationElement[] elements) {
		DynaComponentClass type = null;
		for (int i = 0; i < elements.length; i++) {
			IConfigurationElement element = elements[i];
			type = new DynaComponentClass(library, element.getAttribute("name"),
					collectDynaProperties(element.getChildren("property")),
					collectEventTypes(element.getChildren("event")),
					collectFlags(element));
			library.registerComponentType(type.getName(), type);
		}
	}

	private static int collectFlags(IConfigurationElement element) {
		int flag = DynaComponentClass.NONE;
		if (Boolean.valueOf(element.getAttribute("container")).booleanValue()) {
			flag |= DynaComponentClass.CONTAINER;
		}
		if (!Boolean.valueOf(element.getAttribute("tabFocus")).booleanValue()) {
			flag |= DynaComponentClass.NO_FOCUS;
		}
		if ("width".equals(element.getAttribute("size"))) {
			flag |= DynaComponentClass.RESIZABLE_WIDTH;
		} else if ("height".equals(element.getAttribute("size"))) {
			flag |= DynaComponentClass.RESIZABLE_HEIGHT;
		} else if ("both".equals(element.getAttribute("size"))) {
			flag |= DynaComponentClass.RESIZABLE_BOTH;
		}
		return flag;
	}
	
	private static DynaProperty[] collectDynaProperties(IConfigurationElement[] elements) {
		List result = new ArrayList();

		for (int i = 0; i < elements.length; i++) {
			IConfigurationElement element = elements[i];
			if (!"property".equals(element.getName())) {
				continue;
			}

			String name = element.getAttribute("name");
			Class type = (Class) propertyTypes
					.get(element.getAttribute("type"));
			result.add(new DynaProperty(name, type));
		}
		return (DynaProperty[]) result.toArray(new DynaProperty[result.size()]);
	}

	private static String[] collectEventTypes(IConfigurationElement[] elements) {
		List result = new ArrayList();

		for (int i = 0; i < elements.length; i++) {
			IConfigurationElement element = elements[i];
			if (!"event".equals(element.getName())) {
				continue;
			}
			result.add(element.getAttribute("type"));
		}
		return (String[]) result.toArray(new String[result.size()]);
	}

	public static Object getComponentType(String namespaceURI, String name)
			/*throws UnknownComponentException*/ {
		if (namespaceURI == null || !registry.containsKey(namespaceURI)) {
			ComponentLibrary[] libraries = getLibraries();
			for (int i = 0; i < libraries.length; i++) {
				ComponentLibrary library = libraries[i];
				if (library.containsComponent(name)) {
					return library.getComponentType(name);
				}
			}
			return null;
		}
		return getLibrary(namespaceURI).getComponentType(name);
	}

	public static ComponentLibrary getLibrary(String namespaceURI)
			/*throws UnknownComponentException*/ {
		if (!registry.containsKey(namespaceURI)) {
//			throw new UnknownComponentException("Component library for namespace \""
//					+ namespaceURI + "\" is not found.");
			return null;
		}
		return (ComponentLibrary) registry.get(namespaceURI);
	}

	public static ComponentLibrary[] getLibraries() {
		return (ComponentLibrary[]) registry.values().toArray(
				new ComponentLibrary[registry.size()]);
	}
	
	public static boolean isCustomizeComponent(String namespaceURI, String name) {
		if (namespaceURI == null || !registry.containsKey(namespaceURI)) {
			ComponentLibrary[] libraries = getLibraries();
			for (int i = 0; i < libraries.length; i++) {
				ComponentLibrary library = libraries[i];
				if (library.containsComponent(name)) {
					return true;
				}
			}
		}
		return ((ComponentLibrary) registry.get(namespaceURI)).containsComponent(name);
	}
	
	private ComponentRegistry() {
		super();
	}

}
