package urban.shapes;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import urban.transformers.RuleGraphToRuleTransformer;
/**
* Represents a rule as a directed acyclic graph.
* Only rules that change a single bond or state are able to be represented.
*/
public class RuleGraph {
private final Node root;
private Map<Link, RuleGraph> children;
/**
* Constructor
* @param node
* agent or bond
*/
public RuleGraph(Node node) {
this.root = node;
this.children = new TreeMap<Link, RuleGraph>();
}
/**
* The head of the graph.
* @return the root node
*/
public Node getRoot() {
return root;
}
/**
* Children of this node are agents that are bonded to this one.
* @return a set of all children
*/
public Set<Entry<Link, RuleGraph>> getChildren(){
return children.entrySet();
}
/**
* @return a map of links to children
*/
public Map<Link, RuleGraph> getChildrenMap(){
return children;
}
RuleGraph getChild(Link name){
return children.get(name);
}
/**
* @param key
* @param value
*/
public void addChild(Link key, RuleGraph value) {
children.put(key, value);
}
public String toString(){
return new RuleGraphToRuleTransformer().transform(this).toString();
}
/**
* This inner class allows for sets of rulegraphs to be created with equality
* being by value. It exists because sometimes we want to have a set of rulegraphs
* based on identity and at others based on value.
*/
public class WithHash {
private String v;
WithHash(){
v = getRuleGraph().toString();
}
/**
* @return the rulegraph that this represents
*/
public RuleGraph getRuleGraph() {
return RuleGraph.this;
}
@Override
public int hashCode() {
return v.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
WithHash other = ((WithHash) obj);
return v.equals(other.v);
}
}
/**
* Creates an object that can be used for hashsets when equality is to be based on content
* rather than reference.
* @return an object that can be used for hashsets of RuleGraphs
*/
public WithHash withHash() {
return new WithHash();
}
/**
* Removes a child from the graph
* @param key link to be removed
*/
public void removeChild(Link key) {
children.remove(key);
}
/**
* A test to check if the root of the graph represents a symmetrical bond.
* eg A(a!1),A(a!1)
* @return true if representing a symmetrical bond
*/
public boolean hasSymmetricalBond() {
if (!(getRoot() instanceof BondNode))
return false;
Iterator<Entry<Link, RuleGraph>> iterator = getChildren().iterator();
if (!iterator.hasNext())
return false;
final Entry<Link, RuleGraph> left = iterator.next();
if (!iterator.hasNext())
return false;
final Entry<Link, RuleGraph> right = iterator.next();
return left.getKey().getDst().equals(right.getKey().getDst())
&& left.getValue().getRoot().getName().equals(right.getValue().getRoot().getName());
}
/**
* Gets a mirrored version of a rulegraph if the graph represents a bond.
* eg A(a!1,b),A(a!1) would become A(a!1),A(a!1,b)
* @return a mirrored rulegraph
*/
public RuleGraph getMirror() {
RuleGraph m = new RuleGraph(root);
for(Entry<Link,RuleGraph> e : children.entrySet()){
if (e.getKey().getSrc() == "1"){
m.addChild(new Link("2",e.getKey().getDst()), e.getValue());
} else if (e.getKey().getSrc() == "2"){
m.addChild(new Link("1",e.getKey().getDst()), e.getValue());
} else {
// not a bond rulegraph - cannot be mirrored
return this;
}
}
return m;
}
}