/*******************************************************************************
* Copyright (c) 2009 University of Edinburgh.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the BSD Licence, which accompanies this feature
* and can be downloaded from http://groups.inf.ed.ac.uk/pepa/update/licence.txt
******************************************************************************/
package uk.ac.ed.inf.biopepa.core.sba;
import java.util.*;
import uk.ac.ed.inf.biopepa.core.compiler.CompiledExpression;
import uk.ac.ed.inf.biopepa.core.compiler.TransportData;
import uk.ac.ed.inf.biopepa.core.sba.SBAComponentBehaviour.Type;
public class SBAReaction {
String name, reversibleName, forwardName;
private String originalName;
boolean reversible = false;
private boolean enabled = true; // By default a reaction is enabled.
// The permanence of this variable is open for discussion, hence it not
// gaining public accessor methods. See line ~98 for usage.
TransportData transportation = null;
List<SBAComponentBehaviour> reactants, products;
CompiledExpression reactionRate;
SBAReaction(String name, CompiledExpression rate) {
reactants = new LinkedList<SBAComponentBehaviour>();
products = new LinkedList<SBAComponentBehaviour>();
originalName = name;
this.name = name;
reactionRate = rate;
}
public String getName() {
return name;
}
public List<SBAComponentBehaviour> getReactants() {
List<SBAComponentBehaviour> newList = new LinkedList<SBAComponentBehaviour>();
newList.addAll(reactants);
return newList;
}
public List<SBAComponentBehaviour> getProducts() {
List<SBAComponentBehaviour> newList = new LinkedList<SBAComponentBehaviour>();
newList.addAll(products);
return newList;
}
public CompiledExpression getRate() {
return reactionRate;
}
void setReversible(boolean reversible) {
this.reversible = reversible;
if (reversible) {
for (SBAComponentBehaviour cb : reactants)
if (!cb.type.equals(Type.REACTANT))
throw new IllegalStateException("");
}
}
public boolean isReversible() {
return reversible;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isEnabled() {
return enabled;
}
boolean addComponent(SBAComponentBehaviour c) {
if (c == null)
throw new NullPointerException("SBAComponent must be non-null.");
if (c.type.equals(Type.PRODUCT)) {
if (products.contains(c))
return false;
return products.add(c);
}
if (reactants.contains(c))
return false;
if (reversible && !c.type.equals(Type.REACTANT))
throw new IllegalStateException("");
return reactants.add(c);
}
public SBAReaction clone() {
SBAReaction r = new SBAReaction(originalName, reactionRate);
r.name = name;
for (SBAComponentBehaviour cb : reactants)
r.reactants.add(cb.clone());
for (SBAComponentBehaviour cb : products)
r.products.add(cb.clone());
r.reversible = reversible;
r.transportation = transportation;
return r;
}
public static List<SBAReaction> merge(SBAReaction one, SBAReaction two) {
if (one == null)
throw new NullPointerException("First SBAReaction cannot be null.");
if (two == null)
throw new NullPointerException("Second SBAReaction cannot be null.");
if (!one.originalName.equals(two.originalName))
throw new IllegalArgumentException("Can only merge on identical action names.");
if (one.reversible != two.reversible)
throw new IllegalArgumentException("Cannot merge reversible and non-reversible reactions.");
if (one.transportation != two.transportation)
throw new IllegalArgumentException("Cannot merge transportation reactions.");
/*
* This is where we need to solve our locations bug.
* These reactions should not be blindly merged. Previously this method had returned
* a single reaction, I've changed the types, but the semantics are still the same.
* We need to return more than one reaction here. It depends on what sides have what
* located species etc.
*/
SBAReaction r = one.clone();
r.reversible = one.reversible;
for (SBAComponentBehaviour cb : two.reactants)
r.reactants.add(cb);
for (SBAComponentBehaviour cb : two.products)
r.products.add(cb);
LinkedList<SBAReaction> result = new LinkedList<SBAReaction>();
result.add(r);
return result;
}
/*
* Gives the net affect of the current reaction on the given
* named component. For example if the reaction is
* A+A -> A+B then the netAffect of A is -1 and for B is +1.
*/
public int netAffect(String componentName){
int net = 0;
for (SBAComponentBehaviour reactant : this.reactants){
if (reactant.getName().equals(componentName)){
net -= reactant.stoichiometry;
}
}
for (SBAComponentBehaviour product : this.products){
if (product.getName().equals(componentName)){
net += product.stoichiometry;
}
}
return net;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append(", ");
for (SBAComponentBehaviour cb : reactants)
sb.append(cb.toString()).append(" + ");
if (reactants.size() > 0)
sb.delete(sb.length() - 3, sb.length());
if (reversible)
sb.append(" <-> ");
else
sb.append(" -> ");
for (SBAComponentBehaviour cb : products)
sb.append(cb.toString()).append(" + ");
if (products.size() > 0)
sb.delete(sb.length() - 3, sb.length());
return sb.toString();
}
}