/*******************************************************************************
 * Copyright (c) 2005, 2006 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ui.internal.navigator.extensions;

import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.internal.navigator.CustomAndExpression;
import org.eclipse.ui.internal.navigator.NavigatorPlugin;
import org.eclipse.ui.navigator.ILinkHelper;

/**
 * Provides a wrapper around
 * <b>org.eclipse.ui.navigator.navigatorContent/linkHelper</b> extensions.
 * 
 * @since 3.2
 * 
 */
public class LinkHelperDescriptor implements ILinkHelperExtPtConstants {

	private final IConfigurationElement configElement;

	private String id;

	private Expression editorInputEnablement;

	/* The following field may be null */
	private Expression selectionEnablement;

	private boolean hasLinkHelperFailedCreation;

	/* package */LinkHelperDescriptor(IConfigurationElement aConfigElement) {
		Assert.isNotNull(aConfigElement,
				"LinkHelperRegistry.Descriptor objects cannot be null."); //$NON-NLS-1$
		Assert
				.isLegal(LINK_HELPER.equals(aConfigElement.getName()),
						"LinkHelperRegistry.Descriptor objects must have the name \"linkHelper\"."); //$NON-NLS-1$
		configElement = aConfigElement;
		init();
	}

	void init() {
		id = configElement.getAttribute(ATT_ID);
		IConfigurationElement[] expressions = this.configElement
				.getChildren(EDITOR_INPUT_ENABLEMENT);
		Assert
				.isLegal(
						expressions.length == 1,
						"The linkHelper extension point requires exactly one editorInputEnablement child."); //$NON-NLS-1$

		editorInputEnablement = new CustomAndExpression(expressions[0]);

		expressions = configElement.getChildren(SELECTION_ENABLEMENT);
		if (expressions.length > 0) {
			/* The following attribute is optional */
			// navigatorContentExtensionId = expressions[0]
			// .getAttribute(ATT_NAVIGATOR_CONTENT_EXTENSION_ID);
			if (expressions[0].getChildren() != null
					&& expressions[0].getChildren().length > 0) {

				selectionEnablement = new CustomAndExpression(expressions[0]);

			}
		}
	}

	/**
	 * @return Returns the id.
	 */
	public String getId() {
		return id;
	}

	/**
	 * Create a link helper instance from this descriptors class attribute.
	 * 
	 * @return An instance of the helper that is defined by the extension, or a
	 *         Skeleton Link Helper.
	 */
	public ILinkHelper createLinkHelper() {
		if (hasLinkHelperFailedCreation)
			return SkeletonLinkHelper.INSTANCE;
		try {
			return (ILinkHelper) configElement
					.createExecutableExtension(ATT_CLASS);
		} catch (Throwable t) {
			hasLinkHelperFailedCreation = true;
			NavigatorPlugin.logError(0, t.getMessage(), t);
		}
		return SkeletonLinkHelper.INSTANCE;
	}

	/**
	 * 
	 * @param anInput
	 *            The editor input from the editor that was activated.
	 * @return True if this linkHelper descriptor can produce a selection from
	 *         the editor input.
	 */
	public boolean isEnabledFor(IEditorInput anInput) {

		if (editorInputEnablement == null || anInput == null) {
			return false;
		}

		try {
			EvaluationContext context = new EvaluationContext(null, anInput);
			context.setAllowPluginActivation(true);
			return (editorInputEnablement.evaluate(context) == EvaluationResult.TRUE);
		} catch (CoreException e) {
			NavigatorPlugin.log(IStatus.ERROR, 0, e.getMessage(), e);
		}
		return false;
	}

	/**
	 * @param anObject
	 *            The selection from the CommonViewer
	 * @return True if this dscriptor can determine a valid editor to activate
	 *         from the selection.
	 */
	public boolean isEnabledFor(Object anObject) {
		if (selectionEnablement == null) {
			return false;
		}

		IEvaluationContext context = new EvaluationContext(null, anObject);
		context.setAllowPluginActivation(true);
		try {
			if (selectionEnablement.evaluate(context) != EvaluationResult.TRUE) {
				return false;
			}
		} catch (CoreException e) {
			NavigatorPlugin.log(IStatus.ERROR, 0, e.getMessage(), e);
			return false;
		}
		return true;
	}
}
