package org.objectstyle.wolips.eomodeler.core.model;

import java.util.LinkedList;
import java.util.List;

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.objectstyle.wolips.eomodeler.core.Activator;

/**
 * An EOClassLoaderFactory is responsible for constructing a ClassLoader that
 * can be used to execute code from EOF.
 * 
 * @author mschrag
 */
public interface IEOClassLoaderFactory {
	/**
	 * Returns a ClassLoader that contains all the EOF classes in it.
	 * 
	 * @param model
	 *            the EOModel to use as the basis for the the ClassLoader
	 * @return an EOF ClassLoader
	 */
	public ClassLoader createClassLoaderForModel(EOModel model) throws EOModelException;

	public class Utility {
		public static ClassLoader createClassLoader(EOModel model) throws EOModelException {
			List<IEOClassLoaderFactory> classLoaderFactories = new LinkedList<IEOClassLoaderFactory>();
			IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint("org.objectstyle.wolips.eomodeler.eoclassLoaderFactory");
			IExtension[] extensions = extensionPoint.getExtensions();
			ClassLoader finalClassLoader = null;
			for (IExtension extension : extensions) {
				IConfigurationElement[] configurationElements = extension.getConfigurationElements();
				for (IConfigurationElement configurationElement : configurationElements) {
					try {
						IEOClassLoaderFactory classLoaderFactory = (IEOClassLoaderFactory) configurationElement.createExecutableExtension("class");
						ClassLoader classLoader = classLoaderFactory.createClassLoaderForModel(model);
						if (classLoader != null) {
							if (finalClassLoader == null) {
								finalClassLoader = classLoader;
							}
							else {
								Activator.getDefault().log("There was more than one valid EOF ClassLoader factory defined. The ClassLoader generated by the first one will be used.");
							}
						}
						classLoaderFactories.add(classLoaderFactory);
					} catch (CoreException e) {
						Activator.getDefault().log("Could not create EOClassLoader factory from configuration element: " + configurationElement, e);
					}
				}
			}
			if (finalClassLoader == null) {
				throw new EOModelException("There was no valid EOF ClassLoader factory defined.");
			}
			return finalClassLoader;
		}
	}
}
