/**
 * File:    EMFBasedMultiExtensionHelper.java
 * Created: 26.02.2009
 *
 *
/*******************************************************************************
 * Copyright (c) 2009  Open Wide (www.openwide.fr)
 *
 * 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:
 *    Mickael Istria, Open Wide, Lyon, France
 *      - creation and implementation
 *******************************************************************************/

package org.eclipse.jwt.transformations.properties.extension;

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

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jwt.we.misc.logging.Logger;
import org.eclipse.ui.WorkbenchException;

public class EMFBasedMultiExtensionHelper<T> {
	
	public static final String PACKAGE_NAME = "packageName"; //$NON-NLS-1$
	public static final String CLASS_NAME = "className"; //$NON-NLS-1$
	public static final String FEATURE_NAME = "featureName"; //$NON-NLS-1$

	private static Logger log = Logger.getLogger(EMFBasedMultiExtensionHelper.class);

	private boolean initialized = false;
	private String extensionPoint;
	private ProxyFactory<T> proxyFactory;
	
	public EMFBasedMultiExtensionHelper(String extensionPointId, ProxyFactory<T> proxyFactory) {
		this.extensionPoint = extensionPointId;
		this.proxyFactory = proxyFactory;
	}
	
	// Contains the entries of the extension point
	private Map<FeatureFullDescription, T> extensionPointEntries = new HashMap<FeatureFullDescription, T>();
	// Contains the objects associated to a feature (with inheritance resolved)
	private Map<FeatureFullDescription, List<T>> extensionObjects = new HashMap<FeatureFullDescription, List<T>>();

	/**
	 * Process the extension point ie adds all entries of extension point into
	 * the map Fills extensionPointEntries
	 * 
	 * @throws WorkbenchException
	 */
	private void processExtensionPoint() throws WorkbenchException {
		log.debug("Processing extension point " + extensionPoint); //$NON-NLS-1$

		IConfigurationElement[] confElements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPoint);

		// For each service:
		for (int m = 0; m < confElements.length; m++) {
			IConfigurationElement member = confElements[m];
			String featureName = member.getAttribute(FEATURE_NAME);
			String className = member.getAttribute(CLASS_NAME);
			String packageName = member.getAttribute(PACKAGE_NAME);

			// create log entry
			log.info("JWT Extension - found PropertyDescriptor at " + extensionPoint //$NON-NLS-1$
					+ ": {" + packageName + "}" + className + "/" + featureName); //$NON-NLS-1$  //$NON-NLS-2$ //$NON-NLS-3$

			T proxy = proxyFactory.createProxy(member);
			extensionPointEntries.put(new FeatureFullDescription(featureName, className, packageName), proxy);
		}
	}
	

	private synchronized void init() {
		if (!initialized) {
			try {
				processExtensionPoint();
			} catch (WorkbenchException ex) {
				Logger.getLogger(EMFBasedMultiExtensionHelper.class).severe("Could not process extension point for custom PropertyDescriptor"); //$NON-NLS-1$
			}
			initialized = true;
		}
	}
	
	/**
	 * Computes the propertyDescrptor for specified feature and adds the
	 * association Feature->PropertyDescriptor to map
	 * 
	 * @param currentFeature
	 */
	private void computeExtensionsFor(FeatureFullDescription currentFeature) {
		init();
		List<T> res = new ArrayList<T>();
		for (FeatureFullDescription availableFeature : extensionPointEntries.keySet()) {
			if (currentFeature.isFeatureFromSuperclass(availableFeature)) {
				res.add(extensionPointEntries.get(availableFeature));
			}
		}
		extensionObjects.put(currentFeature, res);
	}

	public List<T> getObject(FeatureFullDescription feature) {
		if (!extensionObjects.containsKey(feature))
			computeExtensionsFor(feature);
		return extensionObjects.get(feature);
	}

}