package agg.xt_basis;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Vector;
import agg.attribute.impl.ValueTuple;
import agg.util.Change;
public class UndirectedGraph extends Graph {
public UndirectedGraph(TypeSet aTypeSet) {
this.itsTypes = aTypeSet;
}
/**
* Creates an empty graph with the specified TypeSet.
*
* @param aTypeSet
* the TypeSet to use
* @param completeGraph
* true, to create a host graph
*/
public UndirectedGraph(TypeSet aTypeSet, boolean completeGraph) {
super(aTypeSet, completeGraph);
}
/**
* Returns an error if the type multiplicity check failed after an edge of
* the specified type would be created, otherwise - null.
*/
public TypeError canCreateArc(
final Type edgeType,
final Node src,
final Node tar,
int currentTypeGraphLevel) {
// check src->tar already exists
TypeError error = this.itsTypes.canCreateArc(
this, edgeType, src, tar, currentTypeGraphLevel);
// check tar->src already exists
if (error == null)
error = this.itsTypes.canCreateArc(
this, edgeType, tar, src, currentTypeGraphLevel);
return error;
}
/**
* Checks if the specified edge to create is allowed.
*/
public TypeError checkConnectValid(Type edgeType, Node src, Node tar) {
if (this.itsTypes.getTypeGraph() == null
|| this.itsTypes.getLevelOfTypeGraphCheck() == TypeSet.DISABLED
|| this.itsTypes.getLevelOfTypeGraphCheck() == TypeSet.ENABLED_INHERITANCE) {
if (isParallelArcAllowed(edgeType, src, tar)) {
return null;
}
return new TypeError(TypeError.NO_PARALLEL_ARC,
"No parallel edges allowed");
}
Arc typearc = this.itsTypes.getTypeGraphArc(edgeType, src.getType(), tar.getType());
if (typearc == null)
typearc = this.itsTypes.getTypeGraphArc(edgeType, tar.getType(), src.getType());
if (typearc != null) {
if (isParallelArcAllowed(edgeType, src, tar)) {
return null;
}
return new TypeError(TypeError.NO_PARALLEL_ARC,
"No parallel edges allowed");
}
return new TypeError(TypeError.NO_SUCH_TYPE,
"The edge of the type \"" + edgeType.getName()
+ "\" is not allowed between node type \""
+ src.getType().getName() + "\" and \""
+ tar.getType().getName() + "\".");
}
public boolean isParallelArcAllowed(Type edgeType, Node src, Node tar) {
if (this.itsTypes.isArcParallel()
|| (src.getOutgoingArc(edgeType, tar) == null
&& tar.getOutgoingArc(edgeType, src) == null))
return true;
else
return false;
}
//???
public TypeError checkNodeRequiresArc(final int actTypeGraphLevel) {
if (this.itsTypes.getTypeGraph() == null
|| actTypeGraphLevel != TypeSet.ENABLED_MAX_MIN)
return null;
Iterator<Node> iter = this.itsNodes.iterator();
while (iter.hasNext()) {
Node n = iter.next();
List<String> list = this.itsTypes.nodeRequiresArc(n);
if (list != null && !list.isEmpty()) {
return new TypeError(TypeError.TO_LESS_ARCS,
"Node type "
+ "\""+n.getType().getName()+ "\" \n"
+ "requires edge(s) of type: \n"
+ list.toString(), n.getType());
}
}
return null;
}
/**
* Creates and add a new UndirectedArc of the specified type, source and target nodes,
* which must be part of this graph.
*/
public Arc createArc(Type type, Node src, Node tar) throws TypeException {
if (src == null || tar == null) {
throw new TypeException("UndirectedGraph.createArc:: Cannot create an UndirectedArc of type : "+type.getStringRepr()+" Source or target node is null!");
} else if (!this.isNode(src) || !this.isNode(tar)) {
throw new TypeException("UndirectedGraph.createArc:: Cannot create an UndirectedArc of type : "+type.getStringRepr()+" Source or target is not a Node!");
}
Type t = null;
if (this.itsTypes.containsType(type))
t = type;
if (t == null) {
t = this.itsTypes.getSimilarType(type);
if (t == null)
t = this.itsTypes.addType(type);
if (t.getAdditionalRepr().indexOf("[EDGE]") == -1)
t.setAdditionalRepr("[EDGE]");
}
TypeError typeError = this.checkConnectValid(t, src, tar);
if (typeError != null) {
throw new TypeException(typeError);
}
UndirectedArc anArc = new UndirectedArc(t, src, tar, this);
// if this is not a type graph, so check this graph
// against its type graph
typeError = this.itsTypes.checkType(anArc, this.isCompleteGraph());
if (typeError != null) {
((Node)anArc.getSource()).removeOut(anArc);
((Node)anArc.getTarget()).removeOut(anArc);
throw new TypeException(typeError);
}
this.attributed = this.attributed || anArc.getAttribute() != null;
this.itsArcs.add(anArc);
addToTypeObjectsMap(anArc);
this.changed = true;
propagateChange(new Change(Change.OBJECT_CREATED, anArc));
return anArc;
}
/**
* Creates a new UndirectedArc as a copy of the <code>orig</code>.
* Only its type and attributes are copied,
* the structural context (source, target) - is not.
* The specified source <code>src</code> and target <code>tar</code> objects
* must be a part of this graph, but this is not checked here.
*/
public Arc copyArc(final Arc orig, final Node src, final Node tar) throws TypeException {
UndirectedArc arc = null;
try {
arc = (UndirectedArc)this.createArc(orig.getType(), src, tar);
if (arc != null) {
arc.setObjectName(orig.getObjectName());
if (orig.getAttribute() != null) {
arc.createAttributeInstance();
((ValueTuple) arc.getAttribute()).copyEntries(orig
.getAttribute());
}
} else {
throw new TypeException("Graph.copyArc:: Cannot create an UndirectedArc of type : "
+orig.getType().getName());
}
} catch (TypeException ex) {
if (src != null && tar != null) {
throw new TypeException(" "
+orig.getType().getName()
+" from "+src.getType().getName()
+" to "+tar.getType().getName()
+" "+ex.getLocalizedMessage());
}
throw new TypeException(ex.getLocalizedMessage());
}
return arc;
}
/**
* Creates and adds a new arc.
*/
protected Arc newArc(Type t, Node src, Node tar) throws TypeException {
TypeError typeError = this.checkConnectValid(t, src, tar);
if (typeError != null) {
throw new TypeException(typeError);
}
UndirectedArc anArc = new UndirectedArc(t, src, tar, this);
// check for type mismatches, also multiplicity max of source and target
typeError = this.itsTypes.checkType(anArc, this.isCompleteGraph());
if (typeError != null) {
((Node)anArc.getSource()).removeOut(anArc);
((Node)anArc.getTarget()).removeOut(anArc);
throw new TypeException(typeError);
}
this.attributed = this.attributed || anArc.getAttribute() != null;
this.itsArcs.add(anArc);
addToTypeObjectsMap(anArc);
this.changed = true;
propagateChange(new Change(Change.OBJECT_CREATED, anArc));
return anArc;
}
protected Arc newArcFast(Type t, Node src, Node tar) {
// long time = System.nanoTime();
UndirectedArc anArc = new UndirectedArc(t, src, tar, this);
this.attributed = this.attributed || anArc.getAttribute() != null;
this.itsArcs.add(anArc);
addToTypeObjectsMap(anArc);
this.changed = true;
propagateChange(new Change(Change.OBJECT_CREATED, anArc));
// System.out.println("Arc created in: "+(System.nanoTime()-time)+"nano");
return anArc;
}
/**
* Adds the specified edge to my edges. The type of the specified edge has
* to be in my type set.<br>
* The edge must be an instance of <code>UndirectedArc</code>.
*/
public void addArc(Arc anArc) {
if (anArc instanceof UndirectedArc
&& !this.itsArcs.contains(anArc)) {
this.itsArcs.add(anArc);
addToTypeObjectsMap(anArc);
this.attributed = this.attributed || anArc.getAttribute() != null;
this.changed = true;
}
}
protected void addToTypeObjectsMap(GraphObject anObj) {
if (anObj.isNode()) {
this.extendTypeObjectsMapByNode((Node)anObj);
} else {
this.extendTypeObjectsMapByArc((Arc)anObj);
}
}
protected void extendTypeObjectsMapByArc(final Arc arc) {
if (this.itsTypes.hasInheritance()
&& arc.getSource().getType().hasParent()
|| arc.getTarget().getType().hasParent()) {
Vector<Type> srcParents = arc.getSource().getType().getAllParents();
Vector<Type> tarParents = arc.getTarget().getType().getAllParents();
for (int i = 0; i < srcParents.size(); ++i) {
for (int j = 0; j < tarParents.size(); ++j) {
String keystr = srcParents.get(i).convertToKey()
+ arc.getType().convertToKey()
+ tarParents.get(j).convertToKey();
String keystr2 = tarParents.get(j).convertToKey()
+ arc.getType().convertToKey()
+ srcParents.get(i).convertToKey();
HashSet<GraphObject> objSet = this.itsTypeObjectsMap.get(keystr);
if (objSet == null) {
// look for inverse arc key
objSet = this.itsTypeObjectsMap.get(keystr2);
}
if (objSet == null) {
objSet = new LinkedHashSet<GraphObject>();
this.itsTypeObjectsMap.put(keystr, objSet);
}
objSet.add(arc);
}
}
} else {
String keystr = arc.convertToKey();
String keystr2 = ((UndirectedArc)arc).convertToInverseKey();
HashSet<GraphObject> objSet = this.itsTypeObjectsMap.get(keystr);
if (objSet == null) {
// look for inverse arc key
objSet = this.itsTypeObjectsMap.get(keystr2);
}
if (objSet == null) {
objSet = new LinkedHashSet<GraphObject>();
this.itsTypeObjectsMap.put(keystr, objSet);
}
objSet.add(arc);
}
}
protected void removeArc(final Arc a) {
if (a.getContext() == this) {
// remove arc from its source / target
((Node)a.getSource()).removeOut(a);
((Node)a.getTarget()).removeOut(a);
for (int i = 0; i < this.itsUsingMorphs.size(); i++) {
this.itsUsingMorphs.get(i).removeMapping(a);
}
this.itsArcs.remove(a);
removeArcFromTypeObjectsMap(a);
this.changed = true;
}
}
protected void removeArcFromTypeObjectsMap(final Arc arc) {
if (arc.getSource() != null
&& arc.getTarget() != null) {
if (arc.getSource().getType().hasParent()
|| arc.getTarget().getType().hasParent()) {
Vector<Type> srcParents = arc.getSource().getType().getAllParents();
Vector<Type> tarParents = arc.getTarget().getType().getAllParents();
for (int i = 0; i < srcParents.size(); ++i) {
for (int j = 0; j < tarParents.size(); ++j) {
String keystr = srcParents.get(i).convertToKey()
+ arc.getType().convertToKey()
+ tarParents.get(j).convertToKey();
String keystr2 = tarParents.get(j).convertToKey()
+ arc.getType().convertToKey()
+ srcParents.get(i).convertToKey();
HashSet<GraphObject> objSet = this.itsTypeObjectsMap.get(keystr);
if (objSet == null) {
// look for inverse arc key
objSet = this.itsTypeObjectsMap.get(keystr2);
}
if (objSet != null) {
objSet.remove(arc);
}
}
}
} else {
String keystr = arc.convertToKey();
String keystr2 = ((UndirectedArc)arc).convertToInverseKey();
HashSet<GraphObject> objSet = this.itsTypeObjectsMap.get(keystr);
if (objSet == null) {
// look for inverse arc key
objSet = this.itsTypeObjectsMap.get(keystr2);
}
if (objSet != null) {
objSet.remove(arc);
}
}
}
}
/** Returns <code>true</code> if this graph uses the specified type. */
public boolean isUsingType(GraphObject t) {
if (t.isArc()) {
boolean hasTypeGraphArc = this.getTypeSet().getTypeGraphArc(
t.getType(), ((Arc) t).getSource().getType(),
((Arc) t).getTarget().getType()) != null ? true : false;
Iterator<Arc> iter = this.itsArcs.iterator();
while (iter.hasNext()) {
Arc o = iter.next();
if (hasTypeGraphArc) {
if (o.getType().compareTo(t.getType())) {
if (((o.getSource().getType().compareTo(((Arc) t)
.getSource().getType())) || (o.getSource()
.getType().isChildOf(((Arc) t).getSource()
.getType())))
&& ((o.getTarget().getType().compareTo(((Arc) t)
.getTarget().getType())) || (o.getTarget()
.getType().isChildOf(((Arc) t).getTarget()
.getType()))))
return true;
else if (((o.getTarget().getType().compareTo(((Arc) t)
.getSource().getType())) || (o.getTarget()
.getType().isChildOf(((Arc) t).getSource()
.getType())))
&& ((o.getSource().getType().compareTo(((Arc) t)
.getTarget().getType())) || (o.getSource()
.getType().isChildOf(((Arc) t).getTarget()
.getType()))))
return true;
}
}
else if (o.getType().compareTo(t.getType())) {
return true;
}
}
} else {
while (this.itsNodes.iterator().hasNext()) {
Node o = this.itsNodes.iterator().next();
if (o.getType().compareTo(t.getType()))
return true;
else if (o.getType().isChildOf(t.getType()))
return true;
}
}
return false;
}
}