/**
 * File:    TemplateCopier.java
 * Created: 22.10.2008
 *
 *
/*******************************************************************************
 * 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.we.misc.wizards.template.exp;

import java.util.Map;

import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.eclipse.emf.ecore.util.FeatureMapUtil;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;


/**
 * This is a custom EMF copier that replicates a set of EObjects given to the copyAll()
 * method. The difference to the official copier is, that containment hierarchies are
 * restored between the copied objects, so it is possible to extract complete and
 * independent templates from a model.
 * 
 * @version $Id: ExportTemplateCopier.java,v 1.2 2009-11-26 12:41:47 chsaad Exp $
 * @author Christian Saad, Programming distributed Systems Lab, University of Augsburg,
 *         Germany, www.ds-lab.org
 */
public class ExportTemplateCopier
		extends Copier
{

	public ExportTemplateCopier()
	{
		super();
	}


	public ExportTemplateCopier(boolean arg0)
	{
		super(arg0);
	}


	public ExportTemplateCopier(boolean arg0, boolean arg1)
	{
		super(arg0, arg1);
	}


	/**
	 * Serial version ID.
	 */
	private static final long serialVersionUID = 6266078539903569954L;


	/**
	 * Hooks up cross references; it delegates to {@link #copyReference copyReference}.
	 */
	@Override
	public void copyReferences()
	{
		for (Map.Entry<EObject, EObject> entry : entrySet())
		{
			EObject eObject = entry.getKey();
			EObject copyEObject = entry.getValue();
			EClass eClass = eObject.eClass();
			for (int j = 0, size = eClass.getFeatureCount(); j < size; ++j)
			{
				EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(j);
				if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
				{
					if (eStructuralFeature instanceof EReference)
					{
						EReference eReference = (EReference) eStructuralFeature;
						//if (!eReference.isContainment() && !eReference.isContainer())
						{
							copyReference(eReference, eObject, copyEObject);
						}
					}
					else if (FeatureMapUtil.isFeatureMap(eStructuralFeature))
					{
						FeatureMap featureMap = (FeatureMap) eObject
								.eGet(eStructuralFeature);
						FeatureMap copyFeatureMap = (FeatureMap) copyEObject
								.eGet(getTarget(eStructuralFeature));
						int copyFeatureMapSize = copyFeatureMap.size();
						for (int k = 0, featureMapSize = featureMap.size(); k < featureMapSize; ++k)
						{
							EStructuralFeature feature = featureMap
									.getEStructuralFeature(k);
							if (feature instanceof EReference)
							{
								Object referencedEObject = featureMap.getValue(k);
								Object copyReferencedEObject = get(referencedEObject);
								if (copyReferencedEObject == null
										&& referencedEObject != null)
								{
									EReference reference = (EReference) feature;
									if (!useOriginalReferences
									// LINK CONTAINMENTS JUST LIKE REFERENCES
											// || reference.isContainment()
											|| reference.getEOpposite() != null)
									{
										continue;
									}
									copyReferencedEObject = referencedEObject;
								}
								// If we can't add it, it must already be in the list so
								// find it and move it to the end.
								if (!copyFeatureMap.add(feature, copyReferencedEObject))
								{
									for (int l = 0; l < copyFeatureMapSize; ++l)
									{
										if (copyFeatureMap.getEStructuralFeature(l) == feature
												&& copyFeatureMap.getValue(l) == copyReferencedEObject)
										{
											copyFeatureMap.move(
													copyFeatureMap.size() - 1, l);
											--copyFeatureMapSize;
											break;
										}
									}
								}
							}
							else
							{
								copyFeatureMap.add(featureMap.get(k));
							}
						}
					}
				}
			}
		}
	}


	/**
	 * Returns a copy of the given eObject.
	 * 
	 * @param eObject
	 *            the object to copy.
	 * @return the copy.
	 */
	@Override
	public EObject copy(EObject eObject)
	{
		EObject copyEObject = createCopy(eObject);
		put(eObject, copyEObject);
		EClass eClass = eObject.eClass();
		for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
		{
			EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i);
			if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
			{
				if (eStructuralFeature instanceof EAttribute)
				{
					copyAttribute((EAttribute) eStructuralFeature, eObject, copyEObject);
				}
				else
				{
					// DO NOT COPY CONTAINMENT HIERARCHY
					// EReference eReference = (EReference) eStructuralFeature;
					// if (eReference.isContainment())
					// {
					// copyContainment(eReference, eObject, copyEObject);
					// }
				}
			}
		}

		copyProxyURI(eObject, copyEObject);

		return copyEObject;
	}

}
