package uk.org.squirm3.model;
import uk.org.squirm3.model.type.AtomType;
import uk.org.squirm3.model.type.ReactionType;
import uk.org.squirm3.model.type.def.WildcardType;
import static com.google.common.base.Preconditions.checkNotNull;
public final class Reaction {
private final ReactionType aType, bType;
private final int aState, bState;
private final boolean bondedBefore, bondedAfter;
private final int futureAState, futureBState;
public Reaction(final ReactionType aType, final int aState,
final boolean bondedBefore, final ReactionType bType,
final int bState, final int futureAState,
final boolean bondedAfter, final int futureBState) {
this.aType = checkNotNull(aType);
this.aState = aState;
this.bondedBefore = bondedBefore;
this.bType = checkNotNull(bType);
this.bState = bState;
this.futureAState = futureAState;
this.bondedAfter = bondedAfter;
this.futureBState = futureBState;
}
@Override
public String toString() {
final StringBuffer stringBuffer = new StringBuffer(15);
stringBuffer.append(aType.getCharacterIdentifier()).append(aState);
if (!bondedBefore) {
stringBuffer.append(" + ");
}
stringBuffer.append(bType.getCharacterIdentifier()).append(bState);
stringBuffer.append(" => ");
stringBuffer.append(aType.getCharacterIdentifier())
.append(futureAState);
if (!bondedAfter) {
stringBuffer.append(" + ");
}
stringBuffer.append(bType.getCharacterIdentifier())
.append(futureBState);
return stringBuffer.toString();
}
public boolean tryOn(final Atom a, final Atom b) {
if (rejectReactionOn(a, b)) {
return false;
}
applyReactionOn(a, b);
return true;
}
private boolean rejectReactionOn(final Atom a, final Atom b) {
// is the type for 'a' specified and correct?
if (aType instanceof AtomType && a.getType() != aType) {
return true;
}
// is the type for 'b' specified and correct?
if (bType instanceof AtomType && b.getType() != bType) {
return true;
}
// is the type for 'b' specified as matching that of 'a' and correct?
if (bType instanceof WildcardType && bType == aType
&& b.getType() != a.getType()) {
return true; // both x or both y
}
// is the state of 'a' and 'b' correct?
if (aState != a.getState() || bState != b.getState()) {
return true;
}
// is the bonded/not status correct?
if (bondedBefore && !a.hasBondWith(b) || !bondedBefore
&& a.hasBondWith(b)) {
return true;
}
return false;
}
private void applyReactionOn(final Atom a, final Atom b) {
if (!bondedBefore && bondedAfter) {
a.bondWith(b);
} else if (bondedBefore && !bondedAfter) {
a.breakBondWith(b);
}
a.setState(futureAState);
b.setState(futureBState);
}
}