/*****************************************************************************
* Copyright (c) 2011 CEA LIST.
*
*
* 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:
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.alf.validation.typing;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.papyrus.uml.alf.alf.InstanceCreationTupleElement;
import org.eclipse.papyrus.uml.alf.alf.QualifiedNameWithBinding;
import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.Behavior;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.FunctionBehavior;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Reception;
import org.eclipse.uml2.uml.StateMachine;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.TemplateParameterSubstitution;
import org.eclipse.uml2.uml.TemplateableElement;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
public class SignatureFacade {
private String name = "";
protected List<TypeExpression> parameters = new ArrayList<TypeExpression>();
//
protected Map<String, TypeExpression> parametersMap = new HashMap<String, TypeExpression>() ;
//
//private TypeExpression returnType = TypeExpressionFactory.eInstance.createTypeExpression(TypeUtils._undefined, 0, 0, false, false) ;
private TypeExpression returnType = null ;
private EObject actualSignatureObject = null ;
public EObject getActualSignatureObject() {
return actualSignatureObject;
}
public SignatureFacade() {
}
public SignatureFacade(EObject o) {
if (o instanceof Operation) {
Operation operation = (Operation)o ;
this.actualSignatureObject = operation ;
this.name = operation.getName() ;
for (Parameter p : operation.getOwnedParameters()) {
if (p.getDirection() == ParameterDirectionKind.RETURN_LITERAL)
returnType = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
else {
TypeExpression typeOfP = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
parameters.add(typeOfP) ;
parametersMap.put(p.getName(), typeOfP) ;
}
}
}
else if (o instanceof Behavior) {
Behavior behavior = (Behavior) o ;
this.actualSignatureObject = behavior ;
this.name = behavior.getName() ;
for (Parameter p : behavior.getOwnedParameters()) {
if (p.getDirection() == ParameterDirectionKind.RETURN_LITERAL)
returnType = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
else {
TypeExpression typeOfP = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
parameters.add(typeOfP) ;
parametersMap.put(p.getName(), typeOfP) ;
}
}
}
else if (o instanceof ElementImport) {
ElementImport eImport = (ElementImport)o ;
if (eImport.getImportedElement() instanceof Behavior) {
Behavior b = (Behavior)eImport.getImportedElement() ;
this.actualSignatureObject = b ;
if (eImport.getAlias() != null)
this.name = eImport.getAlias() ;
else
this.name = b.getName() ;
for (Parameter p : b.getOwnedParameters()) {
if (p.getDirection() == ParameterDirectionKind.RETURN_LITERAL)
returnType = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
else {
TypeExpression typeOfP = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
parameters.add(typeOfP) ;
parametersMap.put(p.getName(), typeOfP) ;
}
}
}
}
else if (o instanceof Reception) {
Reception r = (Reception)o ;
this.actualSignatureObject = r ;
this.name = r.getName() ;
if (r.getSignal() != null) {
for (Property p : r.getSignal().getAllAttributes()) {
TypeExpression typeOfP = TypeExpressionFactory.eInstance.createTypeExpression(p) ;
parameters.add(typeOfP) ;
parametersMap.put(p.getName(), typeOfP) ;
}
}
}
}
public String getName() {
return name ;
}
public void setName(String name) {
this.name = "" + name ;
}
public List<TypeExpression> getParameters() {
return parameters ;
}
public boolean hasReturnType() {
return returnType != null ;
}
public TypeExpression getReturnType() {
return returnType ;
}
public void setReturnType(TypeExpression returnType) {
this.returnType = returnType ;
}
public String isCompatibleWithMe(List<TypeExpression> arguments, boolean getErrorMessage) {
int compatibilityLevel = this.isCompatibleWithMe(arguments) ;
String errorMessage = "" ;
if (compatibilityLevel == 0) {
errorMessage += this.getLabel() + " does not apply to arguments " ;
String argumentsString = "(" ;
boolean first = true ;
for (TypeExpression type : arguments) {
if (!first) argumentsString += ", " ; else first = false ;
argumentsString += type.getLabel() ;
}
argumentsString += ")" ;
errorMessage += argumentsString ;
}
return errorMessage ;
}
public String getLabel() {
String label = name + "(" ;
boolean first = true ;
for (TypeExpression type : parameters) {
if (!first) label += ", " ; else first = false ;
label += type.getLabel() ;
}
label += ")" ;
return label ;
}
public int isCompatibleWithMe(List<TypeExpression> arguments) {
if (arguments.size() != parameters.size())
return 0 ;
else if (arguments.size() == 0 )
return 3 ;
int compatibilityLevel = 0 ;
boolean first = true ;
for (int i = 0 ; i < parameters.size() ; i++) {
int currentCompatibilityLevel = parameters.get(i).isCompatibleWithMe(arguments.get(i)) ;
if (first && currentCompatibilityLevel < 3)
return 0 ; //TODO: temporary solution. this is to give a higher value to the first argument if it perfectly matches. Should probably consider the context... Check the spec...
if (currentCompatibilityLevel == 0)
return 0 ;
else {
compatibilityLevel += currentCompatibilityLevel ;
}
first = false ;
}
return compatibilityLevel ;
}
public String isCompatibleWithMe(Map<String,TypeExpression> arguments) {
if (arguments.keySet().size() == 0 )
return "" ;
String compatibility = "" ;
for (String parameterName : arguments.keySet()) {
if (parametersMap.get(parameterName) == null) {
compatibility += "Parameter " + parameterName + " is undefined\n";
}
else {
int compatibilityLevel = parametersMap.get(parameterName).isCompatibleWithMe(arguments.get(parameterName)) ;
if (compatibilityLevel == 0) {
compatibility += "Parameter " + parameterName + " requires an argument of type " + parametersMap.get(parameterName).getLabel() + "\n" ;
}
}
}
return compatibility ;
}
public static List<SignatureFacade> findNearestSignature(List<TypeExpression> arguments, List<SignatureFacade> candidates) {
List<SignatureFacade> matchingSignatures = new ArrayList<SignatureFacade>() ;
int bestScore = 0 ;
for (SignatureFacade cddMatchingSignature : candidates) {
int currentScore = cddMatchingSignature.isCompatibleWithMe(arguments) ;
if (currentScore != 0) {
if (currentScore >= bestScore) {
if (currentScore > bestScore)
matchingSignatures.clear() ;
matchingSignatures.add(cddMatchingSignature) ;
bestScore = currentScore ;
}
}
}
return matchingSignatures ;
}
public static List<SignatureFacade> findNearestConstructorSignature(Map<String, TypeExpression> arguments, List<SignatureFacade> candidates) {
List<SignatureFacade> matchingSignatures = new ArrayList<SignatureFacade>() ;
for (SignatureFacade cddMatchingSignature : candidates) {
String compatibility = cddMatchingSignature.isCompatibleWithMe(arguments) ;
if (compatibility.length()==0) {
matchingSignatures.add(cddMatchingSignature) ;
}
}
return matchingSignatures ;
}
public List<SignatureFacade> isNotDistinguishableFrom(List<SignatureFacade> candidates) {
List<SignatureFacade> matchingSignatures = new ArrayList<SignatureFacade>() ;
for (SignatureFacade cddMatchingSignature : candidates) {
if (this.name.equals(cddMatchingSignature.getName())) {
if (this.parameters.size() == cddMatchingSignature.parameters.size()) {
boolean parameterThatDoesNotMatchFound = false ;
for (int i = 0 ; i < this.parameters.size() && !parameterThatDoesNotMatchFound ; ) {
int compatibilityLevel = this.parameters.get(i).isCompatibleWithMe(cddMatchingSignature.getParameters().get(i)) ;
if (compatibilityLevel != 3)
parameterThatDoesNotMatchFound = true ;
i++ ;
}
if (!parameterThatDoesNotMatchFound) {
matchingSignatures.add(cddMatchingSignature) ;
}
}
}
}
return matchingSignatures ;
}
public boolean equals(Operation o) {
return this.actualSignatureObject == o ;
}
public boolean equals(Behavior b) {
return this.actualSignatureObject == b ;
}
public boolean isAConstructor() {
Element signature = null ;
if (actualSignatureObject instanceof Operation || actualSignatureObject instanceof Behavior)
signature = (Element)actualSignatureObject ;
else if (actualSignatureObject instanceof ElementImport)
signature = (Element)((ElementImport)actualSignatureObject).getImportedElement() ;
if (signature == null)
return false ;
return signature.getAppliedStereotype("Standard::Create") != null ;
}
public boolean isADestructor() {
Element signature = null ;
if (actualSignatureObject instanceof Operation || actualSignatureObject instanceof Behavior)
signature = (Element)actualSignatureObject ;
else if (actualSignatureObject instanceof ElementImport)
signature = (Element)((ElementImport)actualSignatureObject).getImportedElement() ;
if (signature == null)
return false ;
return signature.getAppliedStereotype("Standard::Destroy") != null ;
}
public Map<String, TypeExpression> getParametersMap() {
return this.parametersMap ;
}
public boolean isATemplate() {
if (this.actualSignatureObject instanceof TemplateableElement) {
return ((TemplateableElement)this.actualSignatureObject).isTemplate() ;
}
return false ;
}
}