package urban.transformers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import org.apache.commons.collections15.Transformer;
import urban.model.Agent;
import urban.model.Rule;
import urban.model.Site;
import urban.shapes.BondNode;
import urban.shapes.Link;
import urban.shapes.Node;
import urban.shapes.RuleGraph;
/**
* Converts from RuleGraph to Rule.
*
* The order of agents in the rule is determined by a breadth first traversal of the graph.
*/
public class RuleGraphToRuleTransformer implements Transformer<RuleGraph, Rule> {
@Override
public Rule transform(RuleGraph merge) {
if (merge == null)
return null;
Map<Node, List<Site>> lhs = new HashMap<Node, List<Site>>();
Map<Node, List<Site>> rhs = new HashMap<Node, List<Site>>();
List<Node> ordering = new ArrayList<Node>();
Queue<RuleGraph> q = new LinkedList<RuleGraph>();
q.add(merge);
int i=1;
while(!q.isEmpty()){
RuleGraph graph = q.poll();
Node root = graph.getRoot();
if (root instanceof BondNode){
Iterator<Entry<Link, RuleGraph>> children = sorted(graph.getChildren()).iterator();
Entry<Link, RuleGraph> entry1 = children.next();
Entry<Link, RuleGraph> entry2 = children.next();
Node a = entry1.getValue().getRoot();
Node b = entry2.getValue().getRoot();
get(rhs,a).add(new Site(a.getName(), entry1.getKey().getDst(), null, ""+i));
get(rhs,b).add(new Site(b.getName(), entry2.getKey().getDst(), null, ""+i));
i++;
q.add(entry1.getValue());
q.add(entry2.getValue());
} else {
ordering.add(root);
String agent = root.getName();
List<Site> sitesL = get(lhs, root);
List<Site> sitesR = get(rhs, root);
addAll(sitesL, root.getSitesL());
addAll(sitesR, root.getSitesR());
for(Entry<Link, RuleGraph> e : sorted(graph.getChildren())){
if (e.getValue() == null){
String siteName = e.getKey().getSrc();
sitesL.add(new Site(agent, siteName, null, "_"));
sitesR.add(new Site(agent, siteName, null, "_"));
} else {
if (!lhs.containsKey(e.getValue().getRoot())){
q.add(e.getValue());
}
String src = e.getKey().getSrc();
sitesL.add(new Site(agent, src, null, ""+i));
sitesR.add(new Site(agent, src, null, ""+i));
Node root2 = e.getValue().getRoot();
String dst = e.getKey().getDst();
get(lhs, root2).add(new Site(root2.getName(), dst, null, ""+i));
get(rhs, root2).add(new Site(root2.getName(), dst, null, ""+i));
i++;
}
}
}
}
return new Rule(null, toAgents(lhs, ordering), toAgents(rhs, ordering), true, 0.0, 0.0);
}
private Collection<Entry<Link, RuleGraph>> sorted(Set<Entry<Link, RuleGraph>> children) {
Comparator<Entry<Link, RuleGraph>> byLink = new Comparator<Map.Entry<Link,RuleGraph>>() {
public int compare(Entry<Link, RuleGraph> o1, Entry<Link, RuleGraph> o2) {
int i = o1.getValue().getRoot().getName().toString().compareTo(o2.getValue().getRoot().getName().toString());
if (i != 0)
return i;
return o1.getKey().compareTo(o2.getKey());
}
};
final ArrayList<Entry<Link, RuleGraph>> tmp = new ArrayList<Entry<Link, RuleGraph>>(children);
Collections.sort(tmp, byLink);
return tmp;
}
private static List<Site> get(Map<Node, List<Site>> lhs, Node root) {
List<Site> list = lhs.get(root);
if (list == null){
list = new ArrayList<Site>();
lhs.put(root, list);
}
return list;
}
private static void addAll(List<Site> sitesL, List<Site> sitesL2) {
for(Site s : sitesL2){
boolean addSite = true;
for(Site s2 : sitesL){
if (s2.getName().equals(s.getName())){
addSite = false;
}
}
if (addSite)
sitesL.add(s);
}
}
private static Collection<Agent> toAgents(Map<Node, List<Site>> lhs, List<Node> ordering) {
List<Agent> agents = new ArrayList<Agent>();
for(Node n : ordering){
agents.add(new Agent(n.getName(), lhs.get(n)));
}
return agents;
}
}