/*******************************************************************************
 * Copyright (c) 2011 David A Carlson.
 * 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:
 *     David A Carlson (XMLmodeling.com) - initial API and implementation
 *
 * $Id$
 *******************************************************************************/
package org.eclipse.mdht.uml.common.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Comment;
import org.eclipse.uml2.uml.Constraint;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.Substitution;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;

public class ModelConsolidator {
	public static final String SOURCE_CLASS_ANNOTATION = "org.eclipse.mdht.sourceClass";

	private Package sourcePackage;

	private Map<Classifier, List<Classifier>> sourceInheritance;

	private Package consolPackage;

	private Map<String, Class> consolMapping;

	private Map<String, String> qnameMapping;

	private Map<Classifier, List<Classifier>> consolInheritance;

	private List<Classifier> importedClassifiers;

	private Set<Classifier> processedClassifiers;

	private boolean includeBaseModel = false;

	public ModelConsolidator() {
		sourceInheritance = new HashMap<Classifier, List<Classifier>>();
		consolMapping = new HashMap<String, Class>();
		qnameMapping = new HashMap<String, String>();
		consolInheritance = new HashMap<Classifier, List<Classifier>>();
		importedClassifiers = new ArrayList<Classifier>();
		processedClassifiers = new HashSet<Classifier>();
	}

	public void initialize(Package sourcePackage, Package consolPackage) {
		this.sourcePackage = sourcePackage;
		this.consolPackage = consolPackage;

		// assure that all proxies are resolved.
		if (sourcePackage != null) {
			EcoreUtil.resolveAll(sourcePackage.eResource());
			mapClassInheritance(sourcePackage, sourceInheritance);
		}
		if (consolPackage != null) {
			EcoreUtil.resolveAll(consolPackage.eResource());
			mapExistingConsolidation();
			mapConsolInheritance(consolPackage, consolInheritance);
		}
	}

	public boolean isIncludeBaseModel() {
		return includeBaseModel;
	}

	public void setIncludeBaseModel(boolean includeBaseModel) {
		this.includeBaseModel = includeBaseModel;
	}

	/**
	 * Default implementation: element's classifier has no superclass from a different package.
	 */
	protected boolean isBaseModel(Element element) {
		return false;

		// Package elementPackage = element.getNearestPackage();
		// Classifier elementClassifier = null;
		// if (element instanceof Classifier) {
		// elementClassifier = (Classifier) element;
		// } else {
		// EObject eContainer = element.eContainer();
		// while (eContainer != null) {
		// if (eContainer instanceof Classifier) {
		// elementClassifier = (Classifier) eContainer;
		// break;
		// }
		// eContainer = eContainer.eContainer();
		// }
		// }
		//
		// for (Classifier general : UMLUtil.getAllGeneralizations(elementClassifier)) {
		// if (elementPackage != general.getNearestPackage()) {
		// return false;
		// }
		// }
		//
		// return true;
	}

	/**
	 * Default implementation same as getBaseModel(), but allow for a more abstract reference model
	 * that is superclass of the base model.
	 */
	protected boolean isReferenceModel(Element element) {
		return isBaseModel(element);
	}

	protected Class getBaseModelClass(Classifier subClassifier) {
		Class baseModelClass = null;

		// if the provided class is from the base model
		if (isBaseModel(subClassifier) && subClassifier instanceof Class) {
			return (Class) subClassifier;
		}

		for (Classifier parent : subClassifier.allParents()) {
			// nearest package may be null if base model is not available
			if (parent.getNearestPackage() != null) {
				if (isBaseModel(parent) && parent instanceof Class) {
					baseModelClass = (Class) parent;
					break;
				}
			}
		}

		return baseModelClass;
	}

	protected Property getBaseModelProperty(Property property) {
		if (property.getClass_() == null) {
			return null;
		}

		// if the provided property is from a base model class
		if (isBaseModel(property)) {
			return property;
		}

		for (Classifier parent : property.getClass_().allParents()) {
			for (Property inherited : parent.getAttributes()) {
				if (inherited.getName().equals(property.getName()) && isBaseModel(inherited)) {
					return inherited;
				}
			}
		}

		return null;
	}

	protected boolean isXMLAttribute(Property property) {
		Property baseProperty = getBaseModelProperty(property);
		if (baseProperty != null) {
			Stereotype eAttribute = baseProperty.getAppliedStereotype("Ecore::EAttribute");
			if (eAttribute != null) {
				return true;
			}
		}

		return false;
	}

	public List<Classifier> getImportedClassifiers() {
		return importedClassifiers;
	}

	public void addImportedClassifier(Classifier classifier) {
		if (!importedClassifiers.contains(classifier)) {
			importedClassifiers.add(classifier);
		}
	}

	public Set<Classifier> getProcessedClassifiers() {
		return processedClassifiers;
	}

	public void addProcessedClassifier(Classifier classifier) {
		if (!processedClassifiers.contains(classifier)) {
			processedClassifiers.add(classifier);
		}
	}

	public Map<String, Class> getConsolMapping() {
		return consolMapping;
	}

	public void removeAllConsolidationAnnotations() {
		for (Type type : consolPackage.getOwnedTypes()) {
			EAnnotation annotation = type.getEAnnotation(SOURCE_CLASS_ANNOTATION);
			if (annotation != null) {
				type.getEAnnotations().remove(annotation);
			}
		}
	}

	public void renameReferencesInOCL() {
		// iterate through all OCL expressions in consolidated package

	}

	public Class consolidateClass(Class sourceClass) {
		if (isBaseModel(sourceClass)) {
			return sourceClass;
		}

		// if (sourceClass.getOwner() instanceof Class) {
		// System.out.println("Inner class: " + sourceClass.getQualifiedName());
		// }

		Class consolidatedClass = consolMapping.get(EcoreUtil.getURI(sourceClass).toString());
		if (consolidatedClass == null) {
			// if a more specific type defined in flattened model, use it
			consolidatedClass = findConsolSpecialization(sourceClass);

			if (consolidatedClass == null) {
				// Class sourceSpecialization = findSourceSpecialization(sourceClass);
				// if (sourceSpecialization != null && sourceSpecialization != sourceClass) {
				// consolidateClass(sourceSpecialization);
				// } else {
				consolidatedClass = copyToConsolPackage(sourceClass);
				mergeInheritedProperties(sourceClass, consolidatedClass);
				// }
			}
		}

		return consolidatedClass;
	}

	public List<Property> getAllProperties(Classifier umlClass) {
		return getAllProperties(umlClass, null);
	}

	public List<Property> getAllProperties(Classifier umlClass, Class consolidationStop) {
		List<Property> allProperties = new ArrayList<Property>();
		List<Property> allAssociations = new ArrayList<Property>();

		List<Classifier> consolidatedParents = getConsolidatedGeneralizations(
			umlClass, getConsolSource(consolidationStop));

		// process parents in reverse order, base model class first
		for (int i = consolidatedParents.size() - 1; i >= 0; i--) {
			Classifier parent = consolidatedParents.get(i);

			for (Property property : UMLUtil.getOwnedAttributes(parent)) {
				if (property.getAssociation() != null) {
					allAssociations.add(property);
				} else {
					// if list contains this property name, replace it; else append
					int index = findProperty(allProperties, property.getName());
					if (index >= 0) {
						allProperties.set(index, property);
					} else {
						allProperties.add(property);
					}
				}
			}
		}

		Iterator<Property> propertyIterator = allProperties.iterator();
		while (propertyIterator.hasNext()) {
			Property property = propertyIterator.next();
			if (!isIncludeBaseModel() && isBaseModel(property) && property.getLower() == 0) {
				// include only required base model class properties
				propertyIterator.remove();

			}
		}

		Iterator<Property> associationIterator = allAssociations.iterator();
		while (associationIterator.hasNext()) {
			Property property = associationIterator.next();
			if (!isIncludeBaseModel() && isBaseModel(property) && property.getLower() == 0) {
				// include only required base model class properties
				associationIterator.remove();
			}
		}

		/*
		 * Include only associations that are not redefined in a subclass.
		 * TODO There must be a better way... use UML property redefinition in model.
		 */
		List<Classifier> endTypes = new ArrayList<Classifier>();
		List<Property> redefinedProperties = new ArrayList<Property>();

		for (Property property : allAssociations) {
			Classifier type = (Classifier) property.getType();
			endTypes.add(type);

			// classes are processed top-down, thus property from different class is in a superclass
			int dupIndex = endTypes.indexOf(type);
			if (dupIndex >= 0 && property.getClass_() != allAssociations.get(dupIndex).getClass_()) {
				redefinedProperties.add(allAssociations.get(dupIndex));
				// System.out.println(property.getQualifiedName() + " redefines " +
				// allAssociations.get(dupIndex).getQualifiedName());
			}
		}

		for (int index = 0; index < allAssociations.size(); index++) {
			Classifier endType = endTypes.get(index);

			boolean hasSpecialization = false;
			for (Classifier specific : UMLUtil.getAllSpecializations(endType)) {
				if (endTypes.contains(specific)) {
					hasSpecialization = true;
					break;
				}
			}

			Property assocProperty = allAssociations.get(index);
			if (!hasSpecialization && !redefinedProperties.contains(assocProperty)) {
				allProperties.add(assocProperty);
			}
		}

		return allProperties;
	}

	protected void mergeInheritedProperties(Class sourceClass, Class consolidatedClass) {
		Class baseModelClass = getBaseModelClass(sourceClass);
		List<Classifier> allConsolidatedParents = UMLUtil.getAllGeneralizations(consolidatedClass);

		Class consolidationStop = null;
		for (Classifier consolParent : allConsolidatedParents) {
			if (!isIncludeBaseModel() && (isBaseModel(consolParent) || isReferenceModel(consolParent))) {
				continue;
			}

			// Does a parent class exist in consolidated model? If so, retain that generalization
			Class parentConsolClass = consolMapping.get(EcoreUtil.getURI(consolParent).toString());
			if (parentConsolClass != null && parentConsolClass != consolidatedClass) {
				consolidationStop = parentConsolClass;
				break;
			}

			// Does a specialization of the parent class exist in consolidated model? If so, retain that generalization
			Class consolSpecial = findConsolSpecialization((Class) consolParent);
			if (consolSpecial != null && consolSpecial != consolidatedClass) {
				// TODO problems with multiple subclasses in template models
				// consolidationStop = consolSpecial;
				// break;
			}
		}

		List<Classifier> consolidatedParents = getConsolidatedGeneralizations(
			consolidatedClass, getConsolSource(consolidationStop));

		List<Property> allProperties = getAllProperties(consolidatedClass, consolidationStop);
		List<Property> allAttributes = new ArrayList<Property>();
		List<Constraint> allConstraints = new ArrayList<Constraint>();

		// collect all inherited constraints
		for (int i = consolidatedParents.size() - 1; i >= 0; i--) {
			Class parent = (Class) consolidatedParents.get(i);

			if (!isBaseModel(parent)) {
				for (Constraint constraint : parent.getOwnedRules()) {
					allConstraints.add(constraint);
				}
			}
		}

		for (Property property : allProperties) {
			if (isXMLAttribute(property)) {
				allAttributes.add(property);
			}
		}
		allProperties.removeAll(allAttributes);
		Collections.sort(allAttributes, new NamedElementComparator());

		// XML attributes
		for (Property property : allAttributes) {
			Property mergedProperty = null;
			if (consolidatedClass.getOwnedAttributes().contains(property)) {
				mergedProperty = property;
				// remove and re-add for correct sort order
				consolidatedClass.getOwnedAttributes().remove(property);
				consolidatedClass.getOwnedAttributes().add(property);
			} else {
				mergedProperty = EcoreUtil.copy(property);
				consolidatedClass.getOwnedAttributes().add(mergedProperty);
				UMLUtil.cloneStereotypes(property, mergedProperty);
			}

			// test original property so that we can evaluate base model context
			// if (isIncludeBaseModel() && !ModelFilterUtil.hasFilterState(mergedProperty) && isDefaultFiltered(property)) {
			// ModelFilterUtil.setAsHidden(mergedProperty);
			// }
		}

		// XML elements
		for (Property property : allProperties) {
			Property mergedProperty = null;

			if (consolidatedClass.getOwnedAttributes().contains(property)) {
				mergedProperty = property;
				// remove and re-add for correct sort order
				consolidatedClass.getOwnedAttributes().remove(property);
				consolidatedClass.getOwnedAttributes().add(mergedProperty);
			} else {
				mergedProperty = EcoreUtil.copy(property);
				// must be added to model before applying stereotypes
				consolidatedClass.getOwnedAttributes().add(mergedProperty);
				UMLUtil.cloneStereotypes(property, mergedProperty);
			}

			// remove all property redefinition relationships to old superclasses
			mergedProperty.getRedefinedProperties().clear();

			// remove all property subset relationships to old superclasses
			mergedProperty.getSubsettedProperties().clear();

			// test original property so that we can evaluate base model context
			// if (isIncludeBaseModel() && !ModelFilterUtil.hasFilterState(mergedProperty)) {
			// if (isDefaultFiltered(property)) {
			// ModelFilterUtil.setAsHidden(mergedProperty);
			// } else if (isDefaultCollapsed(property)) {
			// ModelFilterUtil.setAsCollapsed(mergedProperty);
			// }
			// }

			if (property.getAssociation() != null) {
				Type endType = property.getType();
				if (endType instanceof Class) {
					Class consolType = null;
					// if association to base model type, leave it unchanged
					if (!isBaseModel(endType)) {
						// don't use specialization of nested classes
						// if ((endType.getOwner() instanceof Class)) {
						// consolType = (Class) mergedProperty.getType();

						// if a more specific type defined in consol or source model, use it
						consolType = findConsolSpecialization((Class) endType);

						if (consolType == null) {
							Class sourceType = findSourceSpecialization((Class) endType);
							if (sourceType != null) {
								consolType = consolidateClass(sourceType);
							}
						}
					}
					if (consolType == null) {
						if (endType.eIsProxy()) {
							System.err.println("Property type is unresolved proxy: " + property.getQualifiedName());
						} else {
							consolType = consolidateClass((Class) endType);
						}
					}

					mergedProperty.setType(consolType);

					if (property.getAssociation().getNearestPackage() != consolidatedClass.getNearestPackage()) {
						Association assocClone = (Association) consolidatedClass.getNearestPackage().createOwnedType(
							null, UMLPackage.Literals.ASSOCIATION);
						assocClone.getMemberEnds().add(mergedProperty);
						Property ownedEnd = UMLFactory.eINSTANCE.createProperty();
						ownedEnd.setType(consolidatedClass);
						assocClone.getOwnedEnds().add(ownedEnd);

						UMLUtil.cloneStereotypes(property.getAssociation(), assocClone);
					}
				}
			}
		}

		// Constraints
		for (Constraint constraint : allConstraints) {
			if (consolidatedClass.getOwnedRules().contains(constraint)) {
				// remove and re-add for correct sort order
				consolidatedClass.getOwnedRules().remove(constraint);
				consolidatedClass.getOwnedRules().add(constraint);
			} else {
				Constraint clone = EcoreUtil.copy(constraint);
				consolidatedClass.getOwnedRules().add(clone);
				UMLUtil.cloneStereotypes(constraint, clone);

				// remove constrainedElement to parent class model
				clone.getConstrainedElements().clear();
			}
		}

		// Comments
		List<Comment> currentComments = new ArrayList<Comment>(consolidatedClass.getOwnedComments());
		consolidatedClass.getOwnedComments().clear();

		// use i>0 to omit the consolidated class
		// for (int i = consolidatedParents.size() - 1; i > 0; i--) {
		for (int i = 1; i < consolidatedParents.size(); i++) {
			Classifier parent = consolidatedParents.get(i);
			List<Comment> comments = new ArrayList<Comment>(parent.getOwnedComments());

			for (Comment comment : comments) {
				Comment clone = EcoreUtil.copy(comment);
				consolidatedClass.getOwnedComments().add(clone);
				UMLUtil.cloneStereotypes(comment, clone);
			}

			// copy comments from only the nearest parent that has comments
			if (comments.size() > 0) {
				break;
			}
		}
		consolidatedClass.getOwnedComments().addAll(currentComments);

		// consolidated comments may refer to consolidated parent class
		for (Comment comment : consolidatedClass.getOwnedComments()) {
			comment.getAnnotatedElements().clear();
			comment.getAnnotatedElements().add(consolidatedClass);
		}

		// update generalizations
		// remove non-consolidated superclasses
		consolidatedClass.getGeneralizations().clear();
		if (!isIncludeBaseModel() && consolidationStop != null) {
			consolidatedClass.createGeneralization(consolidationStop);
		}
		if (!isIncludeBaseModel() && baseModelClass != null && consolidatedClass.getGeneralizations().isEmpty()) {
			consolidatedClass.createGeneralization(baseModelClass);
		}

		if (isIncludeBaseModel()) {
			List<Substitution> substitutions = new ArrayList<Substitution>(consolidatedClass.getSubstitutions());
			for (Substitution subst : substitutions) {
				subst.destroy();
			}
			consolidatedClass.createSubstitution(null, baseModelClass);

		} else {
			// add Substitition for all source model generalizations
			Set<Class> substitutions = new HashSet<Class>();
			List<Classifier> allSourceParents = UMLUtil.getAllGeneralizations(sourceClass);
			for (int i = allSourceParents.size() - 1; i >= 0; i--) {
				Class parent = (Class) allSourceParents.get(i);
				if ((isIncludeBaseModel() || (!isReferenceModel(parent) && !isBaseModel(parent))) &&
						!substitutions.contains(parent)) {
					// add Substitution
					// consolidatedClass.createSubstitution(null, parent);
					substitutions.add(parent);
				}
			}

		}
	}

	protected void mapExistingConsolidation() {
		for (Type consolType : consolPackage.getOwnedTypes()) {
			if (consolType instanceof Class) {
				EAnnotation annotation = consolType.getEAnnotation(SOURCE_CLASS_ANNOTATION);
				if (annotation != null && !annotation.getReferences().isEmpty()) {
					for (EObject reference : annotation.getReferences()) {
						if (reference instanceof Class) {
							consolMapping.put(EcoreUtil.getURI(reference).toString(), (Class) consolType);
						}
					}
				}
			}
		}
	}

	protected Class copyToConsolPackage(Class sourceClass) {
		Class mappedClass = consolMapping.get(EcoreUtil.getURI(sourceClass).toString());
		if (mappedClass == null) {
			// inner classes were previously copied as content of parent class
			if (sourceClass.getOwner() instanceof Class) {
				Class mappedOwner = consolMapping.get(EcoreUtil.getURI(sourceClass.getOwner()).toString());
				if (mappedOwner != null) {
					mappedClass = (Class) mappedOwner.getNestedClassifier(sourceClass.getName());
				}
			}
			if (mappedClass == null) {
				mappedClass = EcoreUtil.copy(sourceClass);
				consolPackage.getOwnedTypes().add(mappedClass);
				UMLUtil.cloneStereotypes(sourceClass, mappedClass);
			}

			consolMapping.put(EcoreUtil.getURI(sourceClass).toString(), mappedClass);
			consolInheritance.put(mappedClass, UMLUtil.getAllGeneralizations(sourceClass));

			if (!sourceClass.getQualifiedName().equals(mappedClass.getQualifiedName())) {
				qnameMapping.put(sourceClass.getQualifiedName(), mappedClass.getQualifiedName());
				// System.out.println("mapping: " + umlClass.getQualifiedName() + " -> " + mappedClass.getQualifiedName());

				// also map all superclass types to the consolidated class
				List<Classifier> allParents = UMLUtil.getAllGeneralizations(sourceClass);
				for (Classifier classifier : allParents) {
					if (!isBaseModel(classifier) && !isReferenceModel(classifier) &&
							qnameMapping.get(classifier.getQualifiedName()) == null) {
						qnameMapping.put(classifier.getQualifiedName(), mappedClass.getQualifiedName());
						// System.out.println("parent mapping: " + classifier.getQualifiedName() + " -> " +
						// mappedClass.getQualifiedName());
					}
				}
			}

			// add Ecore annotation with source UML class reference
			EAnnotation sourceAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
			sourceAnnotation.setSource(SOURCE_CLASS_ANNOTATION);
			sourceAnnotation.getReferences().add(sourceClass);
			mappedClass.getEAnnotations().add(sourceAnnotation);

			for (Property property : sourceClass.getOwnedAttributes()) {
				if (property.getAssociation() != null) {
					Property mappedProperty = mappedClass.getOwnedAttribute(property.getName(), property.getType());
					if (mappedProperty == null) {
						// this should never happen
						continue;
					}

					Association assocClone = (Association) mappedClass.getNearestPackage().createOwnedType(
						null, UMLPackage.Literals.ASSOCIATION);
					assocClone.getMemberEnds().add(mappedProperty);
					Property ownedEnd = UMLFactory.eINSTANCE.createProperty();
					ownedEnd.setType(mappedClass);
					assocClone.getOwnedEnds().add(ownedEnd);

					UMLUtil.cloneStereotypes(property.getAssociation(), assocClone);
				}
			}
		}

		return mappedClass;
	}

	/*
	 * Stop when reaching a previously consolidated class.
	 * TODO: doesn't support multiple inheritance
	 */
	protected List<Classifier> getConsolidatedGeneralizations(Classifier consolidatedClass, Class consolidationStop) {
		List<Classifier> parents = new ArrayList<Classifier>();
		parents.add(consolidatedClass);

		for (Classifier parent : consolidatedClass.getGenerals()) {
			Class special = findConsolSpecialization((Class) parent);
			if (special != null) {
				special = getConsolSource(special);
			}
			if (consolidationStop == null || (!parents.contains(parent) && !consolidationStop.equals(parent) &&
					!consolidationStop.equals(special))) {

				parents.addAll(getConsolidatedGeneralizations(parent, consolidationStop));
			}
		}

		return parents;
	}

	private void mapClassInheritance(Package umlPackage, Map<Classifier, List<Classifier>> map) {
		for (Type type : umlPackage.getOwnedTypes()) {
			// do not include Association
			if (type instanceof Class) {
				mapClassInheritance((Class) type, map);
			}
		}
	}

	private void mapConsolInheritance(Package umlPackage, Map<Classifier, List<Classifier>> map) {
		for (Type type : umlPackage.getOwnedTypes()) {
			// do not include Association
			if (type instanceof Class) {
				mapConsolInheritance((Class) type, map);
			}
		}
	}

	private void mapClassInheritance(Class umlClass, Map<Classifier, List<Classifier>> map) {
		map.put(umlClass, UMLUtil.getAllGeneralizations(umlClass));
	}

	private void mapConsolInheritance(Class umlClass, Map<Classifier, List<Classifier>> map) {
		EAnnotation annotation = umlClass.getEAnnotation(SOURCE_CLASS_ANNOTATION);
		if (annotation != null && !annotation.getReferences().isEmpty()) {
			for (EObject reference : annotation.getReferences()) {
				if (reference instanceof Class) {
					map.put(umlClass, UMLUtil.getAllGeneralizations((Class) reference));
				}
			}
		}
	}

	protected Class getConsolSource(Class consolidatedClass) {
		if (consolidatedClass != null) {
			EAnnotation annotation = consolidatedClass.getEAnnotation(SOURCE_CLASS_ANNOTATION);
			if (annotation != null && !annotation.getReferences().isEmpty()) {
				for (EObject reference : annotation.getReferences()) {
					if (reference instanceof Class) {
						return (Class) reference;
					}
				}
			}
		}
		return null;
	}

	protected Class findConsolSpecialization(Class umlClass) {
		Class specific = null;
		for (Classifier classifier : consolInheritance.keySet()) {
			if (consolInheritance.get(classifier).contains(umlClass)) {
				// must be a Class or UML model is invalid
				return (Class) classifier;
			}
		}

		return specific;
	}

	protected Class findSourceSpecialization(Class umlClass) {
		Class specific = null;
		for (Classifier classifier : sourceInheritance.keySet()) {
			if (sourceInheritance.get(classifier).contains(umlClass)) {
				// must be a Class or UML model is invalid
				return (Class) classifier;
			}
		}

		return specific;
	}

	protected int findProperty(List<Property> properties, String name) {
		if (name != null) {
			for (int i = 0; i < properties.size(); i++) {
				if (name.equals(properties.get(i).getName())) {
					return i;
				}
			}
		}
		return -1;
	}

}
