package urban.model;
import java.util.Collection;
import java.util.Collections;
import org.antlr.stringtemplate.StringTemplate;
import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.collections15.Transformer;
import urban.transformers.CanonicalBindingsTransformer;
import urban.util.DoubleRenderer;
/**
* Line of the form "'name' A(x),A(y) <-> A(x!1),A(y!1) @ 1, 2"
*/
public class Rule extends AbstractStatement {
private final StringTemplate template = new StringTemplate("$if(a.name)$'$a.name$' $endif$$a.lhs; separator=\",\"$ $if(a.bidirectional)$<->$else$->$endif$ $a.rhs; separator=\",\"$ @ $a.forwardRate$$if(a.backwardRate)$, $a.backwardRate$$endif$\n");
private final String name;
private final Collection<Agent> lhs;
private final Collection<Agent> rhs;
private final boolean bidirectional;
private final Double forwardRate;
private final Double backwardRate;
/**
* @param name
* @param lhs
* @param rhs
* @param bidirectional
* @param forwardRate
* @param backwardRate
*/
public Rule(String name, Collection<Agent> lhs, Collection<Agent> rhs, boolean bidirectional, Double forwardRate, Double backwardRate) {
this.name = name == null ? name : name.replaceAll("['\"]", "");
this.lhs = canon(lhs);
this.rhs = canon(rhs);
this.bidirectional = bidirectional;
this.forwardRate = forwardRate;
this.backwardRate = backwardRate;
this.template.setAttribute("a",this);
this.template.registerRenderer(Double.class, new DoubleRenderer());
}
/**
* @return the forward rate
*/
public Double getForwardRate() {
return forwardRate;
}
/**
* @return the backward rate, null if the rule is not bidirectional
*/
public Double getBackwardRate() {
return backwardRate;
}
/**
* @return the name of the rule or null if one is not given
*/
public String getName() {
return name;
}
/**
* @return the agents on the left hand side of the rule
*/
public Collection<Agent> getLhs() {
return Collections.unmodifiableCollection(lhs);
}
/**
* @return the agents on the right hand side of the rule
*/
public Collection<Agent> getRhs() {
return Collections.unmodifiableCollection(rhs);
}
@Override
public Collection<Agent> getAgents(){
return CollectionUtils.union(getLhs(), getRhs());
}
/**
* @return true if the rule is bidirectional and has a backward rate
*/
public boolean isBidirectional() {
return bidirectional;
}
@Override
public Statement transformAgent(Transformer<Agent, Agent> t) {
Rule r = new Rule(
name,
CollectionUtils.collect(lhs, t),
CollectionUtils.collect(rhs, t),
bidirectional,
forwardRate,
backwardRate
);
return r;
}
@Override
public Rule transformAgent(final Transformer<Agent, Agent> t, final int i) {
Rule r = new Rule(
name,
CollectionUtils.collect(lhs, getTransformAtI(t, i)),
CollectionUtils.collect(rhs, getTransformAtI(t, i)),
bidirectional,
forwardRate,
backwardRate
);
return r;
}
private CanonicalBindingsTransformer transformer = new CanonicalBindingsTransformer();
private Collection<Agent> canon(Collection<Agent> agents) {
return transformer.transform(agents);
}
@Override
public String toString() {
return template.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((backwardRate == null) ? 0 : backwardRate.hashCode());
result = prime * result + (bidirectional ? 1231 : 1237);
result = prime * result + ((forwardRate == null) ? 0 : forwardRate.hashCode());
result = prime * result + ((lhs == null) ? 0 : lhs.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((rhs == null) ? 0 : rhs.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Rule other = (Rule) obj;
if (backwardRate == null) {
if (other.backwardRate != null)
return false;
} else if (!backwardRate.equals(other.backwardRate))
return false;
if (bidirectional != other.bidirectional)
return false;
if (forwardRate == null) {
if (other.forwardRate != null)
return false;
} else if (!forwardRate.equals(other.forwardRate))
return false;
if (lhs == null) {
if (other.lhs != null)
return false;
} else if (!lhs.equals(other.lhs))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (rhs == null) {
if (other.rhs != null)
return false;
} else if (!rhs.equals(other.rhs))
return false;
return true;
}
}