package agg.xt_basis;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Vector;
import agg.attribute.AttrInstance;
import agg.attribute.AttrEvent;
import agg.attribute.impl.AttrTupleManager;
import agg.attribute.impl.ValueTuple;
import agg.attribute.impl.ValueMember;
import agg.attribute.impl.VarTuple;
import agg.attribute.impl.VarMember;
import agg.attribute.impl.ContextView;
import agg.util.XMLHelper;
import agg.util.XMLObject;
import agg.util.Change;
import agg.util.Pair;
/**
* @version $Id: Node.java,v 1.47 2010/11/06 18:34:59 olga Exp $
* @author $Author: olga $
*/
@SuppressWarnings("serial")
public class Node extends GraphObject implements XMLObject {
// // test: node XY-position as attribute
public boolean xyAttr = false;
// final protected Vector<Arc> itsOutgoingArcs = new Vector<Arc>();
// final protected Vector<Arc> itsIncomingArcs = new Vector<Arc>();
final protected LinkedHashSet<Arc> itsOutgoingArcs = new LinkedHashSet<Arc>();
final protected LinkedHashSet<Arc> itsIncomingArcs = new LinkedHashSet<Arc>();
protected Node(Type type, Graph context) {
this.itsContext = context;
this.itsType = type;
this.itsContextUsage = hashCode();
// test: XY Position as attributes
addXYPosAttrs(this.itsContext != null && this.itsContext.xyAttr);
if (!this.itsType.isAttrTypeEmpty() && this.itsAttr == null) {
this.itsAttr = AttrTupleManager.getDefaultManager().newInstance(
this.itsType.getAttrType(), context.getAttrContext());
}
if (this.itsAttr != null)
this.itsAttr.addObserver(this);
}
public Node(AttrInstance attr, Type type, Graph context) {
this.itsContext = context;
this.itsType = type;
this.itsContextUsage = hashCode();
this.itsAttr = attr;
// test: XY Position as attributes
addXYPosAttrs(this.itsContext != null && this.itsContext.xyAttr);
if (this.itsAttr != null)
this.itsAttr.addObserver(this);
}
private void addXYPosAttrs(boolean xyPosAttrs) {
// test: XY Position as attributes
if (xyPosAttrs) {
xyAttr = true;
if (this.itsAttr == null) {
if (this.itsType.getAttrType() == null)
((NodeTypeImpl)this.itsType).setAttributeType(
AttrTupleManager.getDefaultManager().newType());
this.itsAttr = AttrTupleManager.getDefaultManager().newInstance(
this.itsType.getAttrType(), this.itsContext.getAttrContext());
}
agg.attribute.AttrType attrType = itsType.getAttrType();
if(!((agg.attribute.impl.DeclTuple)attrType).containsName("thisX"))
attrType.addMember(
agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),
"int", "thisX" );
if(!((agg.attribute.impl.DeclTuple)attrType).containsName("thisY"))
attrType.addMember(
agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),
"int", "thisY" );
}
}
protected Node(Node orig, Graph context) {
this(orig.getType(), context);
if (orig.getAttribute() != null) {
if (this.itsAttr == null)
this.createAttributeInstance();
((ValueTuple) this.itsAttr).copyEntries(orig.getAttribute());
}
// object name is not jet used in AGG GUI
if (!"".equals(orig.getObjectName())) {
this.setObjectName(orig.getObjectName());
}
}
public void dispose() {
this.itsOutgoingArcs.clear();
this.itsIncomingArcs.clear();
if (this.itsAttr != null) {
this.itsAttr.removeObserver(this);
((ValueTuple) this.itsAttr).dispose();
this.itsAttr = null;
}
this.itsType = null;
this.itsContext = null;
this.itsContextUsage = -1;
}
public void finalize() {
}
protected synchronized void addOut(GraphObject obj) {
this.itsOutgoingArcs.add((Arc) obj);
}
protected synchronized void addIn(GraphObject obj) {
this.itsIncomingArcs.add((Arc) obj);
}
protected synchronized void removeOut(GraphObject obj) {
this.itsOutgoingArcs.remove(obj);
}
protected synchronized void removeIn(GraphObject obj) {
this.itsIncomingArcs.remove(obj);
}
public final int getNumberOfArcs() {
return this.itsOutgoingArcs.size() + this.itsIncomingArcs.size();
}
/**
* Iterate through all the arcs that I am the target of.
*
* @see agg.xt_basis.Arc
*/
public final Iterator<Arc> getIncomingArcs() {
return ((LinkedHashSet<Arc>) this.itsIncomingArcs).iterator();
}
/**
* @deprecated replaced by <code>HashSet<Arc> getIncomingArcsSet()</code>.<br>
* The order of arcs may differ from the arc creation order.
*/
public final List<Arc> getIncomingArcsVec() {
return (new ArrayList<Arc>(this.itsIncomingArcs));
}
/**
* @return a set of ordered incoming arcs. The order of arcs is the arc creation order.
*/
public final Iterator<Arc> getIncomingArcsIterator() {
return this.itsIncomingArcs.iterator();
}
/**
* @return a set of incoming arcs. The order of arcs may differ from the arc creation order.
*/
public final HashSet<Arc> getIncomingArcsSet() {
return this.itsIncomingArcs;
}
public final int getNumberOfIncomingArcs() {
return this.itsIncomingArcs.size();
}
public final int getNumberOfIncomingArcs(Type t) {
int n = 0;
Iterator<Arc> iter = this.itsIncomingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t))
n++;
}
return n;
}
public final int getNumberOfIncomingArcsOfTypeFromSourceType(Type t, Type srcType) {
int n = 0;
Iterator<Arc> iter = this.itsIncomingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (srcType.isParentOf(go.getSource().getType()) ) {
n++;
}
}
}
return n;
}
/**
*
* @param t type of incoming arcs
* @param src (parent) type of the source node of incoming arcs
* @return number of incoming arcs
*/
public final int getNumberOfIncomingArcs(Type t, Type src) {
int n = 0;
Iterator<Arc> iter = this.itsIncomingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (src.isParentOf(go.getSourceType()) ) {
n++;
}
else if (!this.itsContext.isCompleteGraph() &&
go.getSourceType().isParentOf(src)) {
n++;
}
}
}
return n;
}
public final List<Arc> getIncomingArcs(Type t, Type src) {
final List<Arc> result = new Vector<Arc>(2);
Iterator<Arc> iter = this.itsIncomingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (src.isParentOf(go.getSourceType()) ) {
result.add(go);
}
else if (!this.itsContext.isCompleteGraph() &&
go.getSourceType().isParentOf(src)) {
result.add(go);
}
}
}
return result;
}
/**
*
* @param t (parent) type of the source node of an incoming arc
* @return true when an incoming arc exists
*/
public boolean hasIncomingArcFrom(Type t) {
Iterator<Arc> e = this.itsIncomingArcs.iterator();
while (e.hasNext()) {
Arc a = e.next();
if (t.isParentOf(a.getSourceType())
|| a.getSourceType().isParentOf(t)
) {
return true;
}
}
return false;
}
/**
* Iterate through all the arcs that I am the source of.
*
* @see agg.xt_basis.Arc
*/
public final Iterator<Arc> getOutgoingArcs() {
return ((LinkedHashSet<Arc>) this.itsOutgoingArcs).iterator();
}
public final int getNumberOfOutgoingArcs() {
return this.itsOutgoingArcs.size();
}
/**
* @deprecated replaced by <code>HashSet<Arc> getOutgoingArcsSet()</code>.
* The order of arcs may differ from the arc creation order.
*/
public final List<Arc> getOutgoingArcsVec() {
return (new ArrayList<Arc>(this.itsOutgoingArcs));
}
/**
* @return a set of outgoing arcs.
* The order of arcs may differ from the arc creation order.
*/
public final HashSet<Arc> getOutgoingArcsSet() {
return this.itsOutgoingArcs;
}
/**
* @return a set of ordered outgoing arcs.
* The order of arcs may differ from the arc creation order.
*/
public final Iterator<Arc> getOutgoingArcsIterator() {
return this.itsOutgoingArcs.iterator();
}
public final int getNumberOfOutgoingArcs(Type t) {
int n = 0;
Iterator<Arc> iter = this.itsOutgoingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t))
n++;
}
return n;
}
public final int getNumberOfOutgoingArcsOfTypeToTargetType(Type t, Type tarType) {
int n = 0;
Iterator<Arc> iter = this.itsOutgoingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (tarType.isParentOf(go.getTarget().getType()) ) {
n++;
}
}
}
return n;
}
/**
*
* @param t type of outgoing arcs
* @param tar (parent) type of the target node of outgoing arcs
* @return number of outgoing arcs
*/
public final int getNumberOfOutgoingArcs(Type t, Type tar) {
int n = 0;
Iterator<Arc> iter = this.itsOutgoingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (tar.isParentOf(go.getTargetType())) {
n++;
}
else if (!this.itsContext.isCompleteGraph() &&
go.getTargetType().isParentOf(tar)) {
n++;
}
}
}
return n;
}
/*
* Checks whether this node is the source of an edge of the given type
* and the specified target node.
*/
public boolean hasArc(final Type arct, final Node tar) {
return (this.getOutgoingArc(arct, tar) != null);
}
public final List<Arc> getOutgoingArcs(Type t, Type tar) {
final List<Arc> result = new Vector<Arc>(2);
Iterator<Arc> iter = this.itsOutgoingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getType().compareTo(t)) {
if (tar.isParentOf(go.getTargetType())) {
result.add(go);
}
else if (!this.itsContext.isCompleteGraph() &&
go.getTargetType().isParentOf(tar)) {
result.add(go);
}
}
}
return result;
}
public final Arc getOutgoingArc(Type t, Node tar) {
Iterator<Arc> iter = this.itsOutgoingArcs.iterator();
while (iter.hasNext()) {
Arc go = iter.next();
if (go.getTarget() == tar
&& go.getType().compareTo(t))
return go;
}
return null;
}
/**
*
* @param t (parent) type of the target node of an outgoing arc
* @return true when an outgoing arc exists
*/
public boolean hasOutgoingArcTo(Type t) {
Iterator<Arc> e = this.itsOutgoingArcs.iterator();
while (e.hasNext()) {
Arc a = e.next();
if (t.isParentOf(a.getTargetType())
|| a.getTargetType().isParentOf(t)
)
return true;
}
return false;
}
public final int getNumberOfInOutArcs() {
int nb = this.itsIncomingArcs.size() + this.itsOutgoingArcs.size();
return nb;
}
/**
* Converts my type to a type key string that is used for search
* operations.
*/
public String convertToKey() {
return this.getType().convertToKey();
}
public String resetTypeKey() {
return this.getType().resetKey();
}
public boolean compareTo(GraphObject o) {
if (!o.isNode()) {
return false;
}
Node n = (Node) o;
// if (!this.getObjectName().equals(n.getObjectName())) {
// return false;
// }
if (!this.itsType.isParentOf(n.getType())) {
return false;
}
if ((this.itsAttr == null && n.getAttribute() == null)
|| ((this.attrExists() && n.attrExists())
&& this.itsAttr.compareTo(n.getAttribute()))) {
;
} else {
return false;
}
if (!this.compareMultiplicityTo(n)) {
return false;
}
return true;
}
protected boolean compareMultiplicityTo(Node n) {
if (this.itsContext.isTypeGraph()) {
int minmax = this.itsType.getSourceMin();
int n_minmax = n.getType().getSourceMin();
if (minmax != n_minmax)
return false;
else {
minmax = this.itsType.getSourceMax();
n_minmax = n.getType().getSourceMax();
if (minmax != n_minmax)
return false;
}
}
return true;
}
public void XwriteObject(XMLHelper h) {
h.openNewElem("Node", this);
if (!this.visible)
h.addAttr("visible", "false");
if (!this.getObjectName().equals(""))
h.addAttr("name", this.getObjectName());
// if(!itsContextUsage.equals("")) h.addAttr("context",
// itsContextUsage);
h.addObject("type", this.itsType, false);
// System.out.println("Node.XwriteObject ...
// "+itsAttr.toString());
// h.addObject("", itsAttr, true);
// save multiplicity, if part of type graph
if (this.itsContext != null && this.itsContext.isTypeGraph()) {
// System.out.println("Node.Xwrite... is elem of type graph");
int minmax = this.itsType.getSourceMin();
if (minmax != Type.UNDEFINED)
h.addAttr("sourcemin", Integer.toString(minmax));
minmax = this.itsType.getSourceMax();
if (minmax != Type.UNDEFINED)
h.addAttr("sourcemax", Integer.toString(minmax));
} //else
{
// System.out.println("Node.XwriteObject ...
// "+itsAttr.toString());
h.addObject("", this.itsAttr, true);
}
h.close();
}
public void XreadObject(XMLHelper h) {
if (h.isTag("Node", this)) {
// System.out.println("Node.XreadObject: ");
String str = h.readAttr("visible");
str = h.readAttr("visible");
this.visible = str.equals("false")? false: true;
str = h.readAttr("name");
this.setObjectName(str);
if (this.itsType.getAttrType() != null
|| this.itsType.hasInheritedAttribute()
|| (this.itsContext != null && this.itsContext.xyAttr)
)
this.createAttributeInstance();
AttrInstance attri = this.itsAttr;
if (attri != null) {
if (this.itsContext != null && this.itsContext.xyAttr) {
xyAttr = true;
agg.attribute.AttrType attrType = itsType.getAttrType();
if(!((agg.attribute.impl.DeclTuple)attrType).containsName("thisX"))
attrType.addMember(
agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),
"int", "thisX" );
if(!((agg.attribute.impl.DeclTuple)attrType).containsName("thisY"))
attrType.addMember(
agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),
"int", "thisY" );
}
// if(Debug.HASHCODE){
// agg.attribute.AttrType attrType = itsType.getAttrType();
// if(!((agg.attribute.impl.DeclTuple)
// attrType).containsName("HASHCODE"))
// attrType.addMember(agg.attribute.facade.impl.DefaultInformationFacade.self().getJavaHandler(),"String",
// "HASHCODE" );
//
// agg.attribute.impl.ValueMember mem =
// ((agg.attribute.impl.ValueTuple)
// attri).getValueMemberAt("HASHCODE");
// String hc = String.valueOf(hashCode());
// mem.setExprAsObject(hc);
// mem.checkValidity();
// }
h.enrichObject(attri);
}
h.close();
// if this node uses variable
// in its attribute so the variable will be marked
if (this.itsContext != null && this.itsContext.getAttrContext() != null
&& this.itsAttr != null) {
ValueTuple value = (ValueTuple) this.itsAttr;
for (int i = 0; i < value.getSize(); i++) {
ValueMember val = value.getValueMemberAt(i);
if (val.isSet()) {
if (val.getExpr().isVariable()) {
ContextView viewContext = (ContextView) ((ValueTuple) val
.getHoldingTuple()).getContext();
VarTuple variable = (VarTuple) viewContext
.getVariables();
VarMember var = variable.getVarMemberAt(val
.getExprAsText());
if (getContext().isNacGraph())
var.setMark(VarMember.NAC);
else if (getContext().isPacGraph())
var.setMark(VarMember.PAC);
else if (viewContext.doesAllowComplexExpressions())
var.setMark(VarMember.RHS);
else
var.setMark(VarMember.LHS);
// System.out.println(this.itsContext.getName()+" "+var.getName()+" "+var.getMark());
}
}
}
}
}
}
public final boolean isArc() {
return false;
}
public final boolean isNode() {
return true;
}
/**
* @return true if don't exist any outgoing or incoming edges, otherwise false
*/
public final boolean isIsolated() {
if (this.itsOutgoingArcs.isEmpty()
&& this.itsIncomingArcs.isEmpty()) {
return true;
}
return false;
}
public String toString() {
String result = "";
String t = this.itsType.getStringRepr();
if (this.itsAttr != null)
result = " (" + "[" + hashCode() + "] " + "Node: " + t + ") "
+ this.itsAttr.toString();
else
result = " (" + "[" + hashCode() + "] " + "Node: " + t + ") ";
return result;
}
/**
* Implements the AttrObserver. Propagates the change
* <code>agg.util.Change.OBJECT_MODIFIED<code>
* and object Pair (this, ev)
* to its Graph if the attributes are changed.
*/
public void attributeChanged(AttrEvent ev) {
if (this.itsContext != null) {
Pair<Object, AttrEvent> p = new Pair<Object, AttrEvent>(this, ev);
if (this.itsContext.isTypeGraph()) {
if (ev.getID() == AttrEvent.MEMBER_VALUE_MODIFIED)
propagateAttrValueToChildNode();
}
this.itsContext.propagateChange(new Change(Change.OBJECT_MODIFIED, p));
}
}
private void propagateAttrValueToChildNode() {
Enumeration<Type> children = this.getType().getChildren().elements();
while (children.hasMoreElements()) {
Type cht = children.nextElement();
List<Node> chnodes = this.itsContext.getNodesByParentType(cht);
if (chnodes != null) {
Node childNode = chnodes.get(0);
if (childNode != this) {
setValueToChildMember(childNode);
}
}
}
}
private void setValueToChildMember(Node childNode) {
for (int i=0; i<((ValueTuple) this.itsAttr).getNumberOfEntries(); i++) {
ValueMember vm = ((ValueTuple) this.itsAttr).getValueMemberAt(i);
if (vm.isSet()
&& childNode.getAttribute() != null
&& ((ValueTuple) childNode.getAttribute()).getValueAt(vm.getName()) == null) {
((ValueTuple) childNode.getAttribute()).setExprValueAt(vm.getExprAsText(), vm.getName());
}
}
}
public void propagateAttrValueFromParentNode() {
if (!this.itsContext.isTypeGraph())
return;
Enumeration<Type> parents = this.getType().getParents().elements();
while (parents.hasMoreElements()) {
Type part = parents.nextElement();
List<Node> parnodes = this.itsContext.getNodesByParentType(part);
if (parnodes != null) {
Node parNode = parnodes.get(0);
if (parNode != this)
setValueFromParentMember(parNode);
}
}
}
private void setValueFromParentMember(Node parentNode) {
if (parentNode.getAttribute() != null && this.itsAttr == null) {
this.createAttributeInstance();
for (int i=0; i<((ValueTuple) this.itsAttr).getNumberOfEntries(); i++) {
ValueMember vm = ((ValueTuple) this.itsAttr).getValueMemberAt(i);
ValueMember parvm = ((ValueTuple) parentNode.getAttribute()).getValueMemberAt(vm.getName());
if (parvm != null && !vm.isSet() && parvm.isSet()) {
((ValueTuple) this.itsAttr).setExprValueAt(parvm.getExprAsText(), parvm.getName());
}
}
}
}
}