//------------------------------------------------------------------------------
// 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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.library.configuration;

import java.util.List;

import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.epf.library.edit.IFilter;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.RoleDescriptor;
import org.eclipse.epf.uma.TaskDescriptor;
import org.eclipse.epf.uma.VariabilityElement;
import org.eclipse.epf.uma.WorkProductDescriptor;


/**
 * Realizes the element based on the configuration and realize options.
 * 
 * @author Jinhua Xi
 * @since 1.0
 */
public abstract class ElementRealizer {

	protected MethodConfiguration config;

	// note: discard contributor takes higher priority, if set to true,
	// resolveContributor will be ignored
	private boolean discardContributor = false;

	private boolean resolveContributor = true;

	private boolean resolveReplacer = true;

	protected IFilter filter = null;
	
	public ElementRealizer(MethodConfiguration config) {
		this(config, true, true);
	}

	public ElementRealizer(MethodConfiguration config,
			boolean resolveContributor, boolean resolveReplacer) {
		this.config = config;
		this.resolveContributor = resolveContributor;
		this.resolveReplacer = resolveReplacer;
	}

	public void setDiscardContributor(boolean discardContributor) {
		this.discardContributor = discardContributor;
	}

	public void setResolveContributor(boolean resolveContributor) {
		this.resolveContributor = resolveContributor;
	}

	public void setResolveReplacer(boolean resolveReplacer) {
		this.resolveReplacer = resolveReplacer;
	}

	public void setFilter(IFilter filter) {
		this.filter = filter;
	}
	
	public MethodConfiguration getConfiguration() {
		return config;
	}
	
	public MethodElement realize(MethodElement element) {
		
		if (element == null || !ConfigurationHelper.inConfig(element, config)) {
			return null;
		}

		// RATLC00384820 - Work product descriptors that point to work products
		// outside the configuration are still published
		// linked element must be in config as well
		MethodElement linkedElement = null;
		if (element instanceof TaskDescriptor) {
			linkedElement = ((TaskDescriptor) element).getTask();
		} else if (element instanceof WorkProductDescriptor) {
			linkedElement = ((WorkProductDescriptor) element).getWorkProduct();
		} else if (element instanceof RoleDescriptor) {
			linkedElement = ((RoleDescriptor) element).getRole();
		}

		if ((linkedElement != null)
				&& !ConfigurationHelper.inConfig(linkedElement, config)) {
			return null;
		}

		// if no configuration is specified, don't calculate
		if (config == null) {
			return element;
		}

		if (element instanceof VariabilityElement) {
			VariabilityElement ve = (VariabilityElement) element;
			VariabilityElement e;

			// if discardContributor set to true, discard the contributor and
			// return null
			if (discardContributor && ConfigurationHelper.isContributor(ve)) {
				return null;
			}

			if (resolveContributor) {
				// if the element is a contributor, resovle to it's base
				while (ConfigurationHelper.isContributor(ve)) {
					e = ve.getVariabilityBasedOnElement();
					if (ConfigurationHelper.inConfig(e, config)) {
						ve = e;
					} else {
						// if the base is not in the configuration, it's an
						// error
						System.out
								.println("Configuration closure error: Base element '" + LibraryUtil.getTypeName(ve) + "' not in configuration"); //$NON-NLS-1$ //$NON-NLS-2$
						break;
					}
				}
			}

			if (resolveReplacer) {
				e = ConfigurationHelper.getReplacer(ve, config);
				if (e != null) {
					return e;
				}
			} else if (!ConfigurationHelper.inConfig(ve, config)) {
				return null;
			}
			
			// if the element is a replacer, and the base is a contributor, 
			// need to resolve the element to the base if resolveContributor is true
			// 152230 - Browsing: Role<-->WP relationship shows inconsistancy
			e = ve;
			while ((e != null) && ConfigurationHelper.isReplacer(e)) {
				e = (VariabilityElement) e.getVariabilityBasedOnElement();
				if (ConfigurationHelper.isContributor(e)) {
					return realize(e);
				}
			}
			
			// can't return here, need to check canShow
			// return ve;
			if (ConfigurationHelper.canShow(ve, config)) {
				return ve;
			}

			return null;
		}

		if (ConfigurationHelper.canShow(element, config)) {
			return element;
		}

		return null;
	}

	/**
	 * realize the list of feature values and returns a new list of values
	 * The new might be a re-sorting of the original list 
	 * or some of the values can be filtered out, depending on the detail implementation
	 * Note: the list value passed in might be updated as well.
	 * @param element MethodElement
	 * @param feature EStructuralFeature
	 * @param values List
	 * @return List
	 */
	public abstract List realize(MethodElement element,
			EStructuralFeature feature, List values);
	
}
