content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  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:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.eclipse.ide.internal.core;
  
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.runtime.IConfigurationElement;
  import org.eclipse.core.runtime.IExtensionDelta;
  import org.eclipse.core.runtime.IExtensionRegistry;
  import org.eclipse.core.runtime.IRegistryChangeEvent;
  import org.eclipse.core.runtime.IRegistryChangeListener;
  import org.eclipse.core.runtime.Platform;
  
  import tern.eclipse.ide.core.ITernServerPreferencesListener;
  import tern.eclipse.ide.core.ITernServerType;
  import tern.eclipse.ide.core.ITernServerTypeManager;
  import tern.eclipse.ide.core.TernCorePlugin;
  
  /**
   * Manager of tern server type loaded by the extension point "ternServerTypes"
   *
   */
  public class TernServerTypeManager implements ITernServerTypeManager,
  		IRegistryChangeListener {
  
  	private static final String EXTENSION_TERN_SERVER_TYPES = "ternServerTypes";
  
  	private static final TernServerTypeManager INSTANCE = new TernServerTypeManager();
  
  	// cached copy of all tern server type
  	private List<ITernServerType> ternServerTypes;
  
  	private boolean registryListenerIntialized;
  
  	private final List<ITernServerPreferencesListener> listeners;
  
  	public static TernServerTypeManager getManager() {
  		return INSTANCE;
  	}
  
  	public TernServerTypeManager() {
  		this.registryListenerIntialized = false;
  		this.listeners = new ArrayList<ITernServerPreferencesListener>();
  	}
  
  	@Override
  	public void registryChanged(final IRegistryChangeEvent event) {
  		IExtensionDelta[] deltas = event.getExtensionDeltas(
  				TernCorePlugin.PLUGIN_ID, EXTENSION_TERN_SERVER_TYPES);
  		if (deltas != null) {
  			for (IExtensionDelta delta : deltas)
  				handleTernServerTypeDelta(delta);
  		}
  	}
  
  	@Override
  	public ITernServerType[] getTernServerTypes() {
  		if (ternServerTypes == null)
  			loadTernServerTypes();
  
  		ITernServerType[] st = new ITernServerType[ternServerTypes.size()];
  		ternServerTypes.toArray(st);
  		return st;
  	}
  
  	@Override
  	public ITernServerType findTernServerType(String id) {
  		if (id == null)
  			throw new IllegalArgumentException();
  
  		if (ternServerTypes == null)
  			loadTernServerTypes();
  
  		Iterator<ITernServerType> iterator = ternServerTypes.iterator();
  		while (iterator.hasNext()) {
  			ITernServerType serverType = (ITernServerType) iterator.next();
  			if (id.equals(serverType.getId()))
  				return serverType;
  		}
  		return null;
  	}
  
  	/**
  	 * Load the tern server types.
  	 */
  	private synchronized void loadTernServerTypes() {
  		if (ternServerTypes != null)
  			return;
  
  		Trace.trace(Trace.EXTENSION_POINT,
  				"->- Loading .ternServerTypes extension point ->-");
  
  		IExtensionRegistry registry = Platform.getExtensionRegistry();
  		IConfigurationElement[] cf = registry.getConfigurationElementsFor(
  				TernCorePlugin.PLUGIN_ID, EXTENSION_TERN_SERVER_TYPES);
  		List<ITernServerType> list = new ArrayList<ITernServerType>(cf.length);
  		addTernServerTypes(cf, list);
  		addRegistryListenerIfNeeded();
  		ternServerTypes = list;
  
  		Trace.trace(Trace.EXTENSION_POINT,
  				"-<- Done loading .ternServerTypes extension point -<-");
  	}
  
  	/**
  	 * Load the tern server types.
  	 */
  	private synchronized void addTernServerTypes(IConfigurationElement[] cf,
  			List<ITernServerType> list) {
  		for (IConfigurationElement ce : cf) {
  			try {
  				list.add(new TernServerType(ce));
  				Trace.trace(Trace.EXTENSION_POINT,
  						"  Loaded serverType: " + ce.getAttribute("id"));
  			} catch (Throwable t) {
  				Trace.trace(
  						Trace.SEVERE,
  						"  Could not load serverType: " + ce.getAttribute("id"),
  						t);
  			}
  		}
  	}
  
  	protected void handleTernServerTypeDelta(IExtensionDelta delta) {
  		if (ternServerTypes == null) // not loaded yet
  			return;
  
  		IConfigurationElement[] cf = delta.getExtension()
  				.getConfigurationElements();
  
  		List<ITernServerType> list = new ArrayList<ITernServerType>(
  				ternServerTypes);
  		if (delta.getKind() == IExtensionDelta.ADDED) {
  			addTernServerTypes(cf, list);
  		} else {
  			int size = list.size();
  			TernServerType[] st = new TernServerType[size];
  			list.toArray(st);
  			int size2 = cf.length;
  
  			for (int i = 0; i < size; i++) {
  				for (int j = 0; j < size2; j++) {
  					if (st[i].getId().equals(cf[j].getAttribute("id"))) {
  						st[i].dispose();
  						list.remove(st[i]);
  					}
  				}
  			}
  		}
  		ternServerTypes = list;
  	}
  
  	private void addRegistryListenerIfNeeded() {
  		if (registryListenerIntialized)
  			return;
  
  		IExtensionRegistry registry = Platform.getExtensionRegistry();
  		registry.addRegistryChangeListener(this, TernCorePlugin.PLUGIN_ID);
  		registryListenerIntialized = true;
  	}
  
  	public void initialize() {
  
  	}
  
  	public void destroy() {
  		if (ternServerTypes == null) // not loaded yet
  			return;
  		List<ITernServerType> types = new ArrayList<ITernServerType>(
  				ternServerTypes);
  		for (ITernServerType type : types) {
  			type.dispose();
  			ternServerTypes.remove(type);
  		}
  		Platform.getExtensionRegistry().removeRegistryChangeListener(this);
  	}
  
  	@Override
  	public void refresh() {
  		if (ternServerTypes == null) // not loaded yet
  			return;
  		for (ITernServerType type : ternServerTypes) {
  			type.dispose();
  		}
  	}
  
  	@Override
  	public void addServerPreferencesListener(
  			ITernServerPreferencesListener listener) {
  		synchronized (listener) {
  			listeners.add(listener);
  		}
  	}
  
  	@Override
  	public void removeServerPreferencesListener(
  			ITernServerPreferencesListener listener) {
  		synchronized (listeners) {
  			listeners.remove(listener);
  		}
  	}
  
  	@Override
  	public void fireServerPreferencesChanged(IProject project) {
  		synchronized (listeners) {
  			for (ITernServerPreferencesListener listener : listeners) {
  				listener.serverPreferencesChanged(project);
  			}
  		}
  	}
  }
  