package urban.transformers;
import static urban.util.Pair.pairOf;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.TreeMap;
import org.apache.commons.collections15.Transformer;
import urban.model.Agent;
import urban.model.Site;
import urban.shapes.BondNode;
import urban.shapes.Link;
import urban.shapes.Node;
import urban.shapes.RuleGraph;
import urban.shapes.Shape;
import urban.shapes.SiteNode;
import urban.util.Pair;
/**
* Converts a ShapePlusSite to a RuleGraph.
*
* To convert a Shape to a RuleGraph the root site needs specified. This is done by using the
* class ShapePlusSite.
*/
public class ShapeToRuleGraphTransformer implements Transformer<Shape.ShapePlusSite, RuleGraph> {
private final RuleGraph template;
private static class Data {
public Map<String, Pair<Agent,Site>> first;
public Map<String, Pair<Agent,Site>> second;
public Queue<Pair<Agent,RuleGraph>> q;
public LinkedList<Agent> lhs;
public RuleGraph[] rgArrays;
public Data(Collection<Agent> lhs) {
this.first = new TreeMap<String, Pair<Agent,Site>>();
this.second = new TreeMap<String, Pair<Agent,Site>>();
this.q = new LinkedList<Pair<Agent, RuleGraph>>();
this.lhs = new LinkedList<Agent>(lhs);
this.rgArrays = new RuleGraph[this.lhs.size()];
Iterator<Agent> lhsIt = this.lhs.iterator();
while(lhsIt.hasNext()) {
Agent a = lhsIt.next();
Iterator<Site> asIt = a.getSites().iterator();
while(asIt.hasNext()){
Site s = asIt.next();
String m = s.getBindingMark();
if (m != null && !"?".equals(m) && !"_".equals(m)){
if (first.containsKey(m))
second.put(m, pairOf(a,s));
else
first.put(m, pairOf(a,s));
}
}
}
}
private Pair<Agent,Site> getLinked(Agent aL, String m) {
if (m == null)
return null;
Pair<Agent,Site> p = first.get(m);
if (p == null || p.fst == aL)
p = second.get(m);
first.remove(m);
second.remove(m);
return p;
}
}
/**
* Constructor to be used when the rulegraph to be generated is a bond and agents and sites are identical
*
* @param rg1
*/
public ShapeToRuleGraphTransformer(RuleGraph rg1) {
this.template = rg1;
}
/**
* Constructor
*/
public ShapeToRuleGraphTransformer() {
this.template = null;
}
@Override
public RuleGraph transform(Shape.ShapePlusSite r) {
if (r == null)
return null;
Data data = new Data(r.shape.getAgents());
RuleGraph result = createRoot(r, data);
fillDAG(data);
return result;
}
private void fillDAG(Data data) {
while(!data.q.isEmpty()){
Pair<Agent,RuleGraph> p = data.q.poll();
Agent aL = p.fst;
RuleGraph current = p.snd;
for(Site s : aL.getSites()){
String m = s.getBindingMark();
if (m != null && !"?".equals(m) && !"_".equals(m)){
Pair<Agent,Site> p2 = data.getLinked(aL, m);
if (p2 != null){
Agent a = p2.fst;
int indexOf = data.lhs.indexOf(a);
if (data.rgArrays[indexOf] == null){
data.rgArrays[indexOf] = new RuleGraph(new Node(a));
data.q.add(pairOf(a,data.rgArrays[indexOf]));
}
RuleGraph value = data.rgArrays[indexOf];
current.addChild(new Link(s.getName(),p2.snd.getName()), value);
}
}
if ("_".equals(m)){
current.addChild(new Link(s.getName(),"_"), null);
}
}
}
}
private RuleGraph createRoot(Shape.ShapePlusSite arg0, Data d) {
RuleGraph rg;
Site s = arg0.site;
if (s.getState() == null){
rg = new RuleGraph(new BondNode());
RuleGraph r1 = new RuleGraph(new Node(arg0.agent));
final Link key = new Link("1",s.getName());
if (template == null){
rg.addChild(key, r1);
d.q.add(pairOf(arg0.agent, r1));
} else {
rg.addChild(key, template.getChildrenMap().get(key));
rg.addChild(new Link("2",s.getName()), r1);
d.q.add(pairOf(arg0.agent, r1));
}
Pair<Agent, RuleGraph> r2 = createRuleGraph(d, rg, arg0.agent, s);
if (r2 != null && r2.fst != null)
d.q.add(r2);
} else {
rg = new RuleGraph(new SiteNode(arg0.agent, s.getName(),s.getState()));
d.q.add(pairOf(arg0.agent, rg));
}
return rg;
}
private Pair<Agent, RuleGraph> createRuleGraph(Data d, RuleGraph rg, Agent fst, Site s) {
String bindingMark = s.getBindingMark();
Pair<Agent,Site> other = d.getLinked(fst, bindingMark);
if (other != null){
RuleGraph r2 = new RuleGraph(new Node(other.fst));
rg.addChild(new Link("2",other.snd.getName()), r2);
return pairOf(other.fst, r2);
}
return null;
}
}