/*
* #%~
* UML2 Translator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ide.plugins.uml2.vdm2uml;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.uml2.uml.AggregationKind;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.DepthFirstAnalysisAdaptorAnswer;
import org.overture.ast.expressions.PExp;
import org.overture.ast.node.INode;
import org.overture.ast.types.AAccessSpecifierAccessSpecifier;
import org.overture.ast.types.ABracketType;
import org.overture.ast.types.AClassType;
import org.overture.ast.types.AFunctionType;
import org.overture.ast.types.AInMapMapType;
import org.overture.ast.types.ANamedInvariantType;
import org.overture.ast.types.AOperationType;
import org.overture.ast.types.AOptionalType;
import org.overture.ast.types.AParameterType;
import org.overture.ast.types.AProductType;
import org.overture.ast.types.AQuoteType;
import org.overture.ast.types.SSetType;
import org.overture.ast.types.AUndefinedType;
import org.overture.ast.types.AUnionType;
import org.overture.ast.types.AUnknownType;
import org.overture.ast.types.AUnresolvedType;
import org.overture.ast.types.AVoidReturnType;
import org.overture.ast.types.AVoidType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SBasicType;
import org.overture.ast.types.SInvariantType;
import org.overture.ast.types.SMapType;
import org.overture.ast.types.SSeqType;
public class Vdm2UmlAssociationUtil
{
public static class UnknownTypeDetector
extends
DepthFirstAnalysisAdaptorAnswer<UnknownTypeDetector.UnknownDetectorResult>
{
public static class UnknownDetectorResult
{
public boolean hasUnknown = false;
public UnknownDetectorResult()
{
}
public UnknownDetectorResult(boolean found)
{
this.hasUnknown = found;
}
}
@Override
public UnknownDetectorResult createNewReturnValue(INode node)
{
return new UnknownDetectorResult();
}
@Override
public UnknownDetectorResult createNewReturnValue(Object node)
{
return new UnknownDetectorResult();
}
@Override
public UnknownDetectorResult caseAUnknownType(AUnknownType node)
throws AnalysisException
{
return new UnknownDetectorResult(true);
}
@Override
public UnknownDetectorResult mergeReturns(
UnknownDetectorResult original, UnknownDetectorResult new_)
{
if (new_ != null && new_.hasUnknown)
{
original.hasUnknown = true;
}
return original;
}
}
public static final UnknownTypeDetector unknownDetector = new UnknownTypeDetector();
public static boolean isSimpleType(PType type)
{
if (type instanceof ANamedInvariantType)
{
return true;
}
try
{
return Vdm2UmlUtil.assistantFactory.createPTypeAssistant().isClass(type, null)
&& !type.apply(unknownDetector).hasUnknown;
} catch (AnalysisException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}// || type.kindPType()==EType.BASIC;
}
public static boolean validType(PType type)
{
if (type instanceof SBasicType)
{
return false;
} else if (type instanceof ABracketType)
{
} else if (type instanceof AClassType)
{
} else if (type instanceof AFunctionType)
{
return false;
} else if (type instanceof SInvariantType)
{
return type instanceof ANamedInvariantType;
} else if (type instanceof SMapType)
{
SMapType mType = (SMapType) type;
// return isSimpleType(mType.getFrom())
// && isSimpleType(mType.getTo());
return validMapFromType(mType.getFrom())
&& validMapType(mType.getTo());
} else if (type instanceof AOperationType)
{
return false;
} else if (type instanceof AOptionalType)
{
AOptionalType optionalType = (AOptionalType) type;
return isSimpleType(optionalType.getType());
} else if (type instanceof AParameterType)
{
return false;
} else if (type instanceof AProductType)
{
return false;
} else if (type instanceof AQuoteType)
{
} else if (type instanceof SSeqType)
{
SSeqType seqType = (SSeqType) type;
return isSimpleType(seqType.getSeqof());
} else if (type instanceof SSetType)
{
SSetType setType = (SSetType) type;
return isSimpleType(setType.getSetof());
} else if (type instanceof AUndefinedType || type instanceof AUnionType
|| type instanceof AUnknownType
|| type instanceof AUnresolvedType || type instanceof AVoidType
|| type instanceof AVoidReturnType)
{
return false;
}
if (Vdm2UmlUtil.assistantFactory.createPTypeAssistant().isClass(type, null))
{
return true;
}
return false;
}
private static boolean validMapType(PType type)
{
if (isSimpleType(type)
|| Vdm2UmlUtil.assistantFactory.createPTypeAssistant().isClass(type, null))
{
return true;
}
if (type instanceof SSeqType)
{
SSeqType seqType = (SSeqType) type;
return isSimpleType(seqType.getSeqof());
} else if (type instanceof SSetType)
{
SSetType setType = (SSetType) type;
return isSimpleType(setType.getSetof());
} else
{
return false;
}
}
private static boolean validMapFromType(PType type)
{
if (type instanceof SSeqType)
{
SSeqType seqType = (SSeqType) type;
if (seqType.getSeqof() instanceof SBasicType)
{
return true;
}
} else if (type instanceof SSetType)
{
SSetType setType = (SSetType) type;
if (setType.getSetof() instanceof SBasicType)
{
return true;
}
} else if (type instanceof SBasicType)
{
return true;
}
return validMapType(type);
}
public static Type getReferenceClass(PType type, Map<String, Class> classes)
{
if (type instanceof AOptionalType)
{
type = ((AOptionalType) type).getType();
}
if (Vdm2UmlUtil.assistantFactory.createPTypeAssistant().isClass(type, null))
{
return getType(classes, type);
}
if (type instanceof SBasicType)
{
return getType(classes, type);
} else if (type instanceof ABracketType)
{
} else if (type instanceof AClassType)
{
} else if (type instanceof AFunctionType)
{
} else if (type instanceof SInvariantType)
{
if (type instanceof ANamedInvariantType)
{
ANamedInvariantType nInvType = (ANamedInvariantType) type;
return getType(classes, nInvType);
}
} else if (type instanceof SMapType)
{
SMapType mType = (SMapType) type;
return getTypeForMap(classes, mType.getTo());
} else if (type instanceof AOperationType)
{
} else if (type instanceof AOptionalType)
{
} else if (type instanceof AParameterType)
{
} else if (type instanceof AProductType)
{
} else if (type instanceof AQuoteType)
{
} else if (type instanceof SSeqType)
{
SSeqType seqType = (SSeqType) type;
return getType(classes, seqType.getSeqof());
} else if (type instanceof SSetType)
{
SSetType setType = (SSetType) type;
return getType(classes, setType.getSetof());
} else if (type instanceof AUndefinedType)
{
} else if (type instanceof AUnionType)
{
} else if (type instanceof AUnknownType)
{
} else if (type instanceof AUnresolvedType)
{
} else if (type instanceof AVoidType)
{
} else if (type instanceof AVoidReturnType)
{
}
return null;
}
private static Type getType(Map<String, Class> classes, String name)
{
if (classes.containsKey(name))
{
return classes.get(name);
}
for (Class c : classes.values())
{
if (name.contains(UmlTypeCreatorBase.NAME_SEPERATOR))
{
int index = name.indexOf(UmlTypeCreatorBase.NAME_SEPERATOR);
if (!c.getName().equals(name.subSequence(0, index)))
{
continue;
} else
{
name = name.substring(index
+ UmlTypeCreatorBase.NAME_SEPERATOR.length());
}
}
Classifier ncl = c.getNestedClassifier(name);
if (ncl != null)
{
return ncl;
}
}
return null;
}
static Type getType(Map<String, Class> classes, PType type)
{
return getType(classes, UmlTypeCreatorBase.getName(type));
}
static Type getTypeForMap(Map<String, Class> classes, PType type)
{
if (type instanceof SSeqType)
{
type = ((SSeqType) type).getSeqof();
} else if (type instanceof SSetType)
{
type = ((SSetType) type).getSetof();
}else if(type instanceof AOptionalType)
{
type = ((AOptionalType) type).getType();
}
return getType(classes, UmlTypeCreatorBase.getName(type));
}
public static void createAssociation(String name, PType defType,
AAccessSpecifierAccessSpecifier access, PExp defaultExp,
Map<String, Class> classes, Class class_, boolean readOnly,
UmlTypeCreator utc)
{
Type referencedClass = Vdm2UmlAssociationUtil.getReferenceClass(defType, classes);
Assert.isNotNull(referencedClass, "association end with: "+defType+" cannot be found");
int lower = Vdm2UmlUtil.extractLower(defType);
Association association = class_.createAssociation(true, AggregationKind.NONE_LITERAL, name, lower, Vdm2UmlUtil.extractUpper(defType), referencedClass, false, AggregationKind.NONE_LITERAL, "", 1, 1);
association.setVisibility(Vdm2UmlUtil.convertAccessSpecifierToVisibility(access));
Property prop = association.getMemberEnd(name, null);
prop.setVisibility(association.getVisibility());
prop.setIsReadOnly(readOnly);
// set default
if (defaultExp != null)
{
prop.setDefault(defaultExp.toString());
}
// set static
prop.setIsStatic(access.getStatic() != null);
// set ordered
prop.setIsOrdered(defType instanceof SSeqType);
prop.setIsUnique(!(defType instanceof SSeqType || defType instanceof SMapType));
// set qualifier if map
if (defType instanceof SMapType)
{
SMapType mType = (SMapType) defType;
PType fromType = mType.getFrom();
PType toType = mType.getTo();
Property qualifier = prop.createQualifier(null, Vdm2UmlAssociationUtil.getQualifierReferenceClass(class_, fromType, classes, utc));
qualifier.setLower(Vdm2UmlUtil.extractLower(fromType));
qualifier.setUpper(Vdm2UmlUtil.extractUpper(fromType));
// set ordered
qualifier.setIsOrdered(fromType instanceof SSeqType);
qualifier.setIsUnique(!(fromType instanceof SSeqType || fromType instanceof SMapType));
prop.setLower(Vdm2UmlUtil.extractLower(toType));
prop.setUpper(Vdm2UmlUtil.extractUpper(toType));
// set ordered
prop.setIsOrdered(toType instanceof SSeqType);
prop.setIsUnique(!(toType instanceof SSeqType || toType instanceof SMapType));
// Map unique
prop.setIsUnique(mType instanceof AInMapMapType);
Property targetProp = association.getMemberEnd("", null);
targetProp.setIsUnique(true);
}
}
private static Type getQualifierReferenceClass(Class class_, PType type,
Map<String, Class> classes, UmlTypeCreator utc)
{
PType qualifierType = unfoldSetSeqTypes(type);
if (qualifierType instanceof SBasicType)
{
utc.create(class_, qualifierType);
return utc.getUmlType(qualifierType);
}
return getReferenceClass(qualifierType, classes);
}
private static PType unfoldSetSeqTypes(PType type)
{
if (type instanceof SSeqType)
{
return ((SSeqType) type).getSeqof();
} else if (type instanceof SSetType)
{
return ((SSetType) type).getSetof();
}
return type;
}
}