/**
 * File:    ResourceProvider.java
 * Created: 20.01.2009
 *
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany <www.ds-lab.org>
 *
 * 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:
 *    Christian Saad, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *******************************************************************************/

package org.eclipse.jwt.meta.providers;

import java.util.Collection;
import java.util.HashMap;

import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jwt.meta.Plugin;
import org.eclipse.jwt.meta.providers.interfaces.ICommandProvider;
import org.eclipse.jwt.meta.providers.interfaces.IImageProvider;
import org.eclipse.jwt.meta.providers.interfaces.IModelProvider;
import org.eclipse.jwt.meta.providers.interfaces.IVisibilityProvider;
import org.eclipse.jwt.meta.providers.standard.DefaultCommandProvider;
import org.eclipse.jwt.meta.providers.standard.DefaultImageProvider;
import org.eclipse.jwt.meta.providers.standard.DefaultModelProvider;
import org.eclipse.jwt.meta.providers.standard.DefaultVisibilityProvider;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;


/**
 * This class is used by the ItemProviders to access external resources like icons and the
 * information whether a model element should be visible. The corresponding resource
 * providers have to be registered in the editor. Also, the editor must set itself as
 * initializingEditor during startup when the active editor cannot be determined through
 * the workbench.
 * 
 * @version $Id: ResourceProviderRegistry.java,v 1.2 2009-11-26 15:16:45 chsaad Exp $
 * @author Christian Saad, Programming distributed Systems Lab, University of Augsburg,
 *         Germany, www.ds-lab.org
 */
public class ResourceProviderRegistry
{

	/**
	 * Singleton access.
	 */
	private static ResourceProviderRegistry myinstance;

	/**
	 * Provider registries.
	 */
	private HashMap<IEditorPart, IImageProvider> imageProviders;
	private HashMap<IEditorPart, IVisibilityProvider> visibilityProviders;
	private HashMap<IEditorPart, ICommandProvider> commandProviders;
	private HashMap<IEditorPart, IModelProvider> modelProviders;

	/**
	 * Default providers.
	 */
	private IVisibilityProvider defaultVisibilityProvider;
	private IImageProvider defaultImageProvider;
	private ICommandProvider defaultCommandProvider;
	private IModelProvider defaultModelProvider;

	/**
	 * Model Providers.
	 */
	private IEditorPart initializingEditor;


	/**
	 * Singleton accessor
	 * 
	 * @return The only instance of this class.
	 */
	public static ResourceProviderRegistry getInstance()
	{
		if (myinstance == null)
			myinstance = new ResourceProviderRegistry();
		return myinstance;
	}


	/**
	 * The constructor.
	 */
	public ResourceProviderRegistry()
	{
		// create the registries
		imageProviders = new HashMap<IEditorPart, IImageProvider>();
		visibilityProviders = new HashMap<IEditorPart, IVisibilityProvider>();
		commandProviders = new HashMap<IEditorPart, ICommandProvider>();
		modelProviders = new HashMap<IEditorPart, IModelProvider>();

		// the default providers
		defaultImageProvider = new DefaultImageProvider();
		defaultVisibilityProvider = new DefaultVisibilityProvider();
		defaultCommandProvider = new DefaultCommandProvider();
		defaultModelProvider = new DefaultModelProvider();
	}


	/**
	 * During startup of the workbench, the editors may not be available through the
	 * workbench. Each editor should call this method on initializing to provide a
	 * fallback editor instance of none can be acquired through the workbench.
	 * 
	 * @param initializingEditor
	 *            The initializingEditor to set.
	 */
	public void setInitializingEditor(IEditorPart initializingEditor)
	{
		this.initializingEditor = initializingEditor;
	}


	// ///////////////////////////////////////////////////////////////////////////
	// (DE)REGISTERING
	//

	/**
	 * Register an image provider.
	 * 
	 * @param imageProvider
	 *            the imageProvider to set
	 */
	public void registerImageProvider(IEditorPart editorpart, IImageProvider imageProvider)
	{
		imageProviders.put(editorpart, imageProvider);
	}


	/**
	 * Register a visibility provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 * @param visibilityProvider
	 *            the visibilityProvider to set
	 */
	public void registerVisibilityProvider(IEditorPart editorpart,
			IVisibilityProvider visibilityProvider)
	{
		visibilityProviders.put(editorpart, visibilityProvider);
	}


	/**
	 * Register a command provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 * @param commandProvider
	 *            the commandProvider to set
	 */
	public void registerCommandProvider(IEditorPart editorpart,
			ICommandProvider commandProvider)
	{
		commandProviders.put(editorpart, commandProvider);
	}


	/**
	 * Register a model provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 * @param modelProvider
	 *            the modelProvider to set
	 */
	public void registerModelProvider(IEditorPart editorpart, IModelProvider modelProvider)
	{
		modelProviders.put(editorpart, modelProvider);
	}


	/**
	 * Register an image provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 */
	public void deregisterImageProvider(IEditorPart editorpart)
	{
		if (imageProviders != null)
		{
			imageProviders.remove(editorpart);
		}
	}


	/**
	 * Deregister a visibility provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 */
	public void deregisterVisibilityProvider(IEditorPart editorpart)
	{
		if (visibilityProviders != null)
		{
			visibilityProviders.remove(editorpart);
		}
	}


	/**
	 * Deregister a command provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 */
	public void deregisterCommandProvider(IEditorPart editorpart)
	{
		if (commandProviders != null)
		{
			commandProviders.remove(editorpart);
		}
	}


	/**
	 * Deregister a model provider.
	 * 
	 * @param editorpart
	 *            the editor part
	 */
	public void deregisterModelProvider(IEditorPart editorpart)
	{
		if (modelProviders != null)
		{
			modelProviders.remove(editorpart);
		}
	}


	// ///////////////////////////////////////////////////////////////////////////
	// HELPER FUNCTIONS
	//

	/**
	 * Returns the active editor part.
	 * 
	 * @return The active editor part.
	 */
	public IEditorPart getActiveEditor()
	{
		// during the initialization of an editor, return it
		if (initializingEditor != null)
		{
			return initializingEditor;
		}

		// get the active workbench window
		IWorkbenchWindow workbenchwindow = Plugin.getInstance().getWorkbench()
				.getActiveWorkbenchWindow();
		if (workbenchwindow == null)
		{
			// during startup return initializing editor (not yet in workbench)
			return null;
		}

		// get the active page
		IWorkbenchPage activepage = workbenchwindow.getActivePage();
		if (activepage == null)
		{
			// during startup return initializing editor (not yet in workbench)
			return null;
		}

		// get the active editor of the active page
		return activepage.getActiveEditor();
	}

	
	// ///////////////////////////////////////////////////////////////////////////
	// PROVIDER: VISIBILITY
	//

	/**
	 * Determine if an object should be visible (default: true).
	 * 
	 * @param object
	 * @return Visibility status.
	 */
	public boolean displayObject(Object object)
	{
		IVisibilityProvider vp = visibilityProviders.get(getActiveEditor()) != null ? visibilityProviders
				.get(getActiveEditor())
				: defaultVisibilityProvider;

		return vp.displayObject(object);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// PROVIDER: IMAGE
	//

	/**
	 * Create an image descriptor for an object (default: null).
	 * 
	 * @param object
	 * @return The image descriptor.
	 */
	public ImageDescriptor createImageDescriptor(Object object)
	{
		IImageProvider ip = imageProviders.get(getActiveEditor()) != null ? imageProviders
				.get(getActiveEditor())
				: defaultImageProvider;

		return ip.createImageDescriptor(object);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// PROVIDER: COMMAND
	//

	/**
	 * Create a command from within an itemProvider.
	 * 
	 * @param commandType
	 * @param domain
	 * @param owner
	 * @param feature
	 * @param data
	 * @return
	 */
	public Command createProviderCommand(String commandType, EditingDomain domain,
			Object owner, EStructuralFeature feature, Object data)
	{
		ICommandProvider cp = commandProviders.get(getActiveEditor()) != null ? commandProviders
				.get(getActiveEditor())
				: defaultCommandProvider;

		return cp.createProviderCommand(commandType, domain, owner, feature, data);
	}


	/**
	 * Create an editingdomain command.
	 * 
	 * @param domain
	 * @param commandClass
	 * @param commandParameter
	 * @return
	 */
	public Command createCommand(AdapterFactoryEditingDomain domain, Class commandClass,
			CommandParameter commandParameter)
	{
		ICommandProvider cp = commandProviders.get(getActiveEditor()) != null ? commandProviders
				.get(getActiveEditor())
				: defaultCommandProvider;

		return cp.createCommand(domain, commandClass, commandParameter);
	}


	// ///////////////////////////////////////////////////////////////////////////
	// PROVIDER: MODEL
	//

	/**
	 * Modify the list of a model object's children.
	 * 
	 * @param object
	 * @param standardChildren
	 * @return
	 */
	public Collection getModelChildren(Object object, Collection standardChildren)
	{
		IModelProvider mp = modelProviders.get(getActiveEditor()) != null ? modelProviders
				.get(getActiveEditor())
				: defaultModelProvider;

		return mp.getModelChildren(object, standardChildren);
	}

}
