package de.ovgu.cide.af;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import cide.gast.IASTNode;
import cide.languages.ExtendedLanguageExtension;
import cide.languages.ILanguageExtension;
import de.ovgu.cide.features.IFeature;
import de.ovgu.cide.features.source.ColoredSourceFile;
import de.ovgu.cide.languages.LanguageExtensionProxy;
/**
* Einfache Struktur zur Repraesentation einer Alternative, z.B. eines alternativen Sourcecode-Fragments.
*
* ACHTUNG: Es sind je nach Anwendungssituation nicht immer alle Felder bef�llt! Ist nicht sch�n, aber
* erspart oft aufwendige Arbeiten, die n�tig w�ren, um solche Felder zu bef�llen, obwohl sie
* in dem Fall gar nicht ben�tigt werden.
*
* @author Malte Rosenthal
*/
public class Alternative {
/**
* ID der Alternative
*/
public String altID;
/**
* ID der zugrunde liegenden Entit�t (z.B. ID des AST-Knotens)
*/
public String entityID;
/**
* Indikator: Zugrunde liegende Entit�t (z.B. AST-Knoten) ist optional,
* d.h. es muss nicht in jeder Konfiguration eine Alternative existieren.
*/
public boolean isOptional;
/**
* Liste von IDs aller Eltern-Entit�ten (auch Gro�eltern usw.)
*/
public List<String> entityParentIDs;
/**
* Menge von eigenen Features, mit der die Alternative annotiert ist
*/
public Set<IFeature> ownFeatures;
/**
* Menge von Features, die die Alternative von seinen Eltern erbt
*/
public Set<IFeature> inheritedFeatures;
/**
* Text der Alternative, z.B. Sourcecode
*/
public String text;
/**
* Indikator: Alternative ist aktiv
*/
public boolean isActive;
private Alternative parent;
private List<Alternative> children;
protected Alternative() { }
public Alternative(String altID, String entityID, boolean isOptional, List<String> entityParentIDs, Set<IFeature> features) {
this.altID = altID;
this.entityID = entityID;
this.isOptional = isOptional;
this.entityParentIDs = entityParentIDs;
this.ownFeatures = features;
this.text = null;
this.isActive = true;
}
public Alternative(IASTNode node, Set<IFeature> inheritedFeatures) {
if (node != null) {
this.altID = "Non-explicit alternative";
this.entityID = node.getId();
this.isOptional = node.isOptional();
this.text = node.render();
this.inheritedFeatures = inheritedFeatures;
}
}
public Alternative getRoot() {
Alternative root = this;
while (root.parent != null)
root = root.parent;
return root;
}
public void setParent(Alternative parent) {
this.parent = parent;
}
public Alternative getParent() {
return parent;
}
public boolean hasAncestor(Alternative alternative) {
if (alternative == null)
return (this.parent == null);
if (alternative.equals(this.parent))
return true;
if (this.parent != null)
return this.parent.hasAncestor(alternative);
return false;
}
public boolean parentIsActive() {
return ((parent == null) || parent.isActive);
}
public void addChild(Alternative alt) {
if (children == null)
children = new LinkedList<Alternative>();
children.add(alt);
}
public boolean hasMultipleChildren() {
return ((children != null) && (children.size() > 1));
}
@SuppressWarnings("unchecked")
public <NodeType extends IASTNode> NodeType getNode(ColoredSourceFile sourceFile, NodeType modelNode) {
ILanguageExtension le = sourceFile.getLanguageExtension();
if (le instanceof LanguageExtensionProxy)
le = ((LanguageExtensionProxy) le).getTarget();
ExtendedLanguageExtension languageExtension = (ExtendedLanguageExtension) le;
return (NodeType) languageExtension.parseCodeFragment(modelNode, this.text);
}
public void update(ColoredSourceFile sourceFile, IASTNode node) {
if ((sourceFile != null) && (node != null)) {
this.inheritedFeatures = sourceFile.getColorManager().getInheritedColors(node);
this.ownFeatures = sourceFile.getColorManager().getOwnColors(node);
this.text = node.render();
}
}
public Alternative setEntityID(String entityID) {
this.entityID = entityID;
return this;
}
public Alternative setActive(boolean isActive) {
this.isActive = isActive;
return this;
}
public Alternative setText(String text) {
this.text = text;
return this;
}
public Alternative setInheritedFeatures(Set<IFeature> features) {
this.inheritedFeatures = features;
return this;
}
/**
* Gibt die Menge aller Features zur�ck, mit der die Alternative annotiert ist (eigene Features plus geerbte Features).
*/
public Set<IFeature> getFeatures() {
return addAll(ownFeatures, inheritedFeatures);
}
@Override
public boolean equals(Object obj) {
if ((obj == null) || !(obj instanceof Alternative))
return false;
Alternative that = (Alternative) obj;
if (this.isActive != that.isActive) return false;
if (this.isOptional != that.isOptional) return false;
if (!this.altID.equals(that.altID)) return false;
if (!this.entityID.equals(that.entityID)) return false;
if (!this.inheritedFeatures.equals(that.inheritedFeatures)) return false;
if (!this.ownFeatures.equals(that.ownFeatures)) return false;
return true;
}
public static Set<IFeature> addAll(Set<IFeature> to, Set<IFeature> from) {
if (to == null)
return from;
if (from == null)
return to;
// Wir machen diesen Workaround, weil >to< oft ein unmodifiable set ist.
Set<IFeature> result = new HashSet<IFeature>();
for (IFeature f : to) {
result.add(f);
}
for (IFeature f : from) {
result.add(f);
}
return result;
}
}