package uk.ac.ed.inf.biopepa.core.imports;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import uk.ac.ed.inf.biopepa.core.sba.LineStringBuilder;
/*
* This module attempts to translate a series of
* NetworKinLines into a working biopepa model.
* Generally this doesn't quite work but we can at least
* generate a syntactically correct model.
*/
public class NetworKinTranslate {
private List<NetworKinLine> networkLines;
public NetworKinTranslate (List<NetworKinLine> lines){
this.networkLines = lines;
}
/*
* Ultimately this should produce an ast Model
* but for now we will return a string since we'll start
* by producing some intermediate results.
*/
public void translate (){
// Composites are represented as sets, in this way
// by printing a composite we can make sure that two
// composites are the same if they are composed of the
// same molecules, that is we do not suffer from producing
// both: K1:K2:P and K2:K1:P
// First we build up a mapping from composite names to proteins
HashMap<String, Protein> proteinMap =
new HashMap<String, Protein>();
// Each protein consists of a mapping from residues to the
// the set of kinases which may attach there.
for (NetworKinLine nline : this.networkLines){
Composite kinase = new Composite (nline.getKinase());
String residue = nline.getResidue();
String proteinName = nline.getProtein();
Composite protein = new Composite (proteinName);
Protein proteinValue = proteinMap.get(proteinName);
if (proteinValue == null){
proteinValue = new Protein(protein);
proteinMap.put(proteinName, proteinValue);
}
proteinValue.addKinaseAtResidue(kinase, residue);
}
// Now we build up a set of reactions, a reaction essentially
// combines a protein and a kinase at a given residue, for
// now we'll just build up a reaction for each possible binding
// later we'll see that we need more, to account for the composites
// made via such reactions which can still participate in such
// reactions, for that I think I'll need a stack, anyway for now
// do the easiest thing possible.
reactions = new LinkedList<Reaction>();
Stack <Protein> proteinStack = new Stack <Protein>();
for (Entry<String, Protein> entry : proteinMap.entrySet()){
proteinStack.add(entry.getValue());
}
while (!proteinStack.isEmpty()){
Protein protein = proteinStack.pop();
Composite proteinComposite = protein.getComposite();
for (Entry <String, HashSet<Composite>> residueEntry :
protein.residueMap.entrySet()){
String residue = residueEntry.getKey();
// int number = 0;
for (Composite kinase : residueEntry.getValue()){
HashSet<Composite> reactants = new HashSet<Composite>();
HashSet<Composite> products = new HashSet<Composite>();
String kName = kinase.printSyntax();
String reactionName = "attach_" + kName + "_" + residue;
// + "_" + number;
reactants.add(proteinComposite);
reactants.add(kinase);
Protein productProtein =
protein.attachKinaseAtResidue(kinase, residue);
Composite product = productProtein.getComposite();
products.add(product);
Reaction r =
new Reaction (reactionName, reactants, products);
reactions.addLast(r);
// number++;
proteinStack.add(productProtein);
}
}
}
// Translating reactions into biopepa components is not
// so difficult. We keep a mapping from composites to their
// biopepa component, for each reaction, we add it to the reactants
// and products by first looking up the composite in the new mapping
// and creating one if it isn't there.
HashMap<Composite, BioPEPAComponent> componentMap =
new HashMap<Composite, BioPEPAComponent> ();
for (Reaction reaction : reactions){
String reactionName = reaction.getName();
for (Composite reactant : reaction.getReactants()){
BioPEPAComponent reactantComp = componentMap.get(reactant);
if (reactantComp == null){
reactantComp = new BioPEPAComponent(reactant);
componentMap.put(reactant, reactantComp);
}
reactantComp.addReactantReaction(reactionName);
}
// Do (almost) the exact same for the products.
for (Composite product : reaction.getProducts()){
BioPEPAComponent reactantComp = componentMap.get(product);
if (reactantComp == null){
reactantComp = new BioPEPAComponent(product);
componentMap.put(product, reactantComp);
}
reactantComp.addProductReaction(reactionName);
}
}
this.biopepaComponents = componentMap.values();
return;
}
// These are set by translate, and should not examined until
// translate has been called.
private LinkedList<Reaction> reactions;
private Collection<BioPEPAComponent> biopepaComponents;
/*
* Should not be called until this.translate has been called.
*/
public String getBioPepaString (){
LineStringBuilder sb = new LineStringBuilder ();
for (BioPEPAComponent component : this.biopepaComponents){
sb.appendLine(component.printSyntax());
}
return sb.toString();
}
/*
* Should not be called until this.translate has been called.
*/
public String reactionsString (){
LineStringBuilder sb = new LineStringBuilder ();
for (Reaction reaction : this.reactions){
sb.appendLine(reaction.printSyntax());
}
return sb.toString();
}
// A protein consists of a mapping from residue names
// to sets of Kinase names which may phosphorylate the protein
// on that particular residue
private class Protein {
HashMap<String, HashSet<Composite>> residueMap;
Composite composite;
Protein (Composite name){
this.composite = name;
this.residueMap = new HashMap<String, HashSet<Composite>> ();
}
public Composite getComposite(){
return this.composite;
}
/*
* This is for use when building up the definition of the protein
* We build up a mapping of residues associated with the protein,
* to sets of kinases which may attach to the protein at that
* residue.
*/
public void addKinaseAtResidue(Composite kinase, String residue){
HashSet<Composite> kinases = this.residueMap.get(residue);
// If there is currently no set in the map corresponding to
// the given residue, put one in.
if (kinases == null){
kinases = new HashSet<Composite> ();
this.residueMap.put(residue, kinases);
}
// Either way add the current kinase to the set (now)
// associated with the residue
kinases.add(kinase);
}
/*
* When we actually create the action for attaching a kinase
* we need to make a new protein which has the kinase already
* attached.
*/
@SuppressWarnings("unchecked")
public Protein attachKinaseAtResidue(Composite kinase, String residue){
Composite newProteinName = this.composite.combine(kinase);
Protein newProtein = new Protein (newProteinName);
// We copy across the current protein's residue map to the
// newly formed composite of the protein plus the attached
// kinase. However we not cannot attach anything else at the
// same residue hence we remove the residue from the cloned
// residuemap.
newProtein.residueMap =
(HashMap<String, HashSet<Composite>>) residueMap.clone ();
newProtein.residueMap.remove(residue);
return newProtein;
}
}
private class Composite extends Object {
HashSet<String> constituents;
Composite (){
this.constituents = new HashSet<String> ();
}
Composite(String component){
this.constituents = new HashSet<String> ();
this.constituents.add(component);
}
public Composite combine (Composite additional){
Composite result = new Composite();
result.constituents.addAll(this.constituents);
result.constituents.addAll(additional.constituents);
return result;
}
public String printSyntax (){
String[] names =
constituents.toArray(new String [this.constituents.size()]);
if (names.length == 0){
return "UnknownConstituents";
}
String name = names[0];
for (int index = 1; index < names.length; index++){
name = name + ":" + names[index];
}
return name;
}
public boolean equals(Object obj){
if (!(obj instanceof Composite)){
return false;
}
Composite c = (Composite) obj;
boolean result = this.constituents.equals(c.constituents);
return result;
}
public int hashCode (){
return this.constituents.hashCode();
}
}
private class Reaction {
HashSet<Composite> reactants;
HashSet<Composite> products;
String name;
Reaction (String name,
HashSet<Composite> reactants,
HashSet<Composite> products){
this.name = name;
this.reactants = reactants;
this.products = products;
}
public String getName (){
return this.name;
}
public Set<Composite> getReactants(){
return this.reactants;
}
public Set<Composite> getProducts(){
return this.products;
}
public String printSyntax (){
LineStringBuilder sb = new LineStringBuilder ();
sb.append (this.name);
sb.append (": ");
boolean first = true;
for (Composite reactant : this.reactants){
if (!first){
sb.append(" + ");
}
first = false;
sb.append(reactant.printSyntax());
}
sb.append(" ----> ");
first = true;
for (Composite product : this.products){
if (!first){
sb.append(" + ");
}
first = false;
sb.append(product.printSyntax());
}
return sb.toString();
}
}
private class BioPEPAComponent {
Composite name;
HashSet<String> reactantReactions;
HashSet<String> productReactions;
BioPEPAComponent (Composite name){
this.name = name;
this.reactantReactions = new HashSet<String>();
this.productReactions = new HashSet<String>();
}
public void addReactantReaction (String name){
this.reactantReactions.add(name);
}
public void addProductReaction (String name){
this.productReactions.add(name);
}
public String printSyntax (){
String result = name.printSyntax() + " = ";
for (String r : this.reactantReactions){
result = result + " " + r + " << ";
}
for (String r : this.productReactions){
result = result + " " + r + " >> ";
}
return result + " ;";
}
}
}