/*
* EuroCarbDB, a framework for carbohydrate bioinformatics
*
* Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
* A copy of this license accompanies this distribution in the file LICENSE.txt.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* Last commit: $Rev: 1210 $ by $Author: glycoslave $ on $Date:: 2009-06-12 #$
*/
/**
*
*/
package org.eurocarbdb.MolecularFramework.sugar;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.eurocarbdb.MolecularFramework.util.visitor.GlycoVisitorException;
import org.eurocarbdb.MolecularFramework.util.visitor.GlycoVisitorNodeType;
/**
* Can store only simple GlycoNodes (NonMS, MS, Unvalidated, Subst)
* @author rene
*
*/
public class UnderdeterminedSubTree implements GlycoGraph
{
private ArrayList<GlycoNode> m_aParents = new ArrayList<GlycoNode>();
private GlycoEdge m_objConnection = null;
private ArrayList<GlycoNode> m_aResidues = new ArrayList<GlycoNode>();
public static final double UNKNOWN = -1;
private double m_dAufenthaltswahrscheinlichkeitUpper = 100;
private double m_dAufenthaltswahrscheinlichkeitLower = 100;
/**
* Delivers all Residues that does not have a parent residue.
* @throws GlycoconjugateException if the structure contain a cyclic part or if the sugar contain no residue with a parent
* @see de.glycosciences.glycoconjugate.GlycoGraph#getRootResiduesForNonCyclicSugars()
*/
public ArrayList<GlycoNode> getRootNodes() throws GlycoconjugateException
{
ArrayList<GlycoNode> t_aResult = new ArrayList<GlycoNode>();
GlycoNode t_objResidue;
// for all residues of the sugar
Iterator<GlycoNode> t_iterResidue = this.getNodeIterator();
while (t_iterResidue.hasNext())
{
t_objResidue = t_iterResidue.next();
GlycoEdge t_objParents = t_objResidue.getParentEdge();
if ( t_objParents == null )
{
t_aResult.add(t_objResidue);
}
}
if ( t_aResult.size() < 1 )
{
throw new GlycoconjugateException("Sugar seems not to have at least one root residue");
}
return t_aResult;
}
/**
* @see de.glycosciences.glycoconjugate.GlycoGraph#getResidueIterator()
*/
public Iterator<GlycoNode> getNodeIterator()
{
return this.m_aResidues.iterator();
}
/**
* @see de.glycosciences.MolecularFrameWork.sugar.GlycoGraph#isConnected()
*/
public boolean isConnected() throws GlycoconjugateException
{
ArrayList<GlycoNode> t_objRoots = this.getRootNodes();
if ( t_objRoots.size() > 1 )
{
return false;
}
return true;
}
public boolean removeNode(GlycoNode a_objResidue) throws GlycoconjugateException
{
GlycoEdge t_objLinkage;
GlycoNode t_objResidue;
if ( a_objResidue == null )
{
throw new GlycoconjugateException("Invalide residue.");
}
if ( a_objResidue.getClass() != SugarUnitCyclic.class )
{
this.searchCyclicForDeleting(a_objResidue);
}
t_objLinkage = a_objResidue.getParentEdge();
if ( t_objLinkage != null )
{
t_objResidue = t_objLinkage.getParent();
if ( t_objResidue == null )
{
throw new GlycoconjugateException("A linkage with a null parent exists.");
}
t_objResidue.removeChildEdge(t_objLinkage);
}
for (Iterator<GlycoEdge> t_iterEdges = a_objResidue.getChildEdges().iterator(); t_iterEdges.hasNext();)
{
t_objLinkage = t_iterEdges.next();
t_objResidue = t_objLinkage.getChild();
if ( t_objResidue == null )
{
throw new GlycoconjugateException("A linkage with a null child exists.");
}
t_objResidue.removeParentEdge(t_objLinkage);
}
return this.m_aResidues.remove(a_objResidue);
}
public ArrayList<GlycoNode> getNodes()
{
return this.m_aResidues;
}
/**
* @see org.eurocarbdb.MolecularFramework.sugar.GlycoGraph#addNode(org.eurocarbdb.MolecularFramework.sugar.GlycoNode)
*/
public boolean addNode(GlycoNode a_objResidue) throws GlycoconjugateException
{
if ( a_objResidue == null )
{
throw new GlycoconjugateException("Invalide residue.");
}
GlycoVisitorNodeType t_objNodeType = new GlycoVisitorNodeType();
if ( !this.m_aResidues.contains(a_objResidue) )
{
try
{
if ( t_objNodeType.isSugarUnitCyclic(a_objResidue) )
{
throw new GlycoconjugateException("Cyclic unit are not allowed in underdetermined subtrees.");
}
if ( t_objNodeType.isSugarUnitRepeat(a_objResidue) )
{
throw new GlycoconjugateException("repeat unit are not allowed in underdetermined subtrees.");
}
if ( t_objNodeType.isSugarUnitAlternative(a_objResidue) )
{
throw new GlycoconjugateException("Alternative units are not allowed in underdetermined subtrees.");
}
}
catch (GlycoVisitorException e)
{
throw new GlycoconjugateException(e.getMessage(),e);
}
a_objResidue.removeAllEdges();
return this.m_aResidues.add(a_objResidue);
}
return false;
}
/**
* @see org.eurocarbdb.MolecularFramework.sugar.GlycoGraph#addNode(org.eurocarbdb.MolecularFramework.sugar.GlycoNode, org.eurocarbdb.MolecularFramework.sugar.GlycoEdge, org.eurocarbdb.MolecularFramework.sugar.GlycoNode)
*/
public boolean addNode(GlycoNode a_objParent, GlycoEdge a_objLinkage, GlycoNode a_objChild) throws GlycoconjugateException
{
if ( a_objParent == null || a_objChild == null )
{
throw new GlycoconjugateException("Invalide residue.");
}
if ( a_objLinkage == null )
{
throw new GlycoconjugateException("Invalide linkage.");
}
if ( a_objChild.getParentEdge() != null )
{
throw new GlycoconjugateException("The child residue has a parent residue.");
}
this.addNode(a_objChild);
this.addNode(a_objParent);
if ( !this.m_aResidues.contains(a_objChild) || !this.m_aResidues.contains(a_objParent) )
{
throw new GlycoconjugateException("Could not add residue to undetermined subtree.");
}
// test for indirect cyclic structures
if ( this.isParent(a_objChild,a_objParent) )
{
throw new GlycoconjugateException("You try to create a cyclic sugar, which are not allowed in underdeterminded trees.");
}
a_objChild.setParentEdge(a_objLinkage);
a_objParent.addChildEdge(a_objLinkage);
a_objLinkage.setChild(a_objChild);
a_objLinkage.setParent(a_objParent);
return true;
}
/**
* @see org.eurocarbdb.MolecularFramework.sugar.GlycoGraph#addEdge(org.eurocarbdb.MolecularFramework.sugar.GlycoNode, org.eurocarbdb.MolecularFramework.sugar.GlycoNode, org.eurocarbdb.MolecularFramework.sugar.GlycoEdge)
*/
public boolean addEdge(GlycoNode a_objParent, GlycoNode a_objChild, GlycoEdge a_objLinkage) throws GlycoconjugateException
{
return this.addNode(a_objParent,a_objLinkage,a_objChild);
}
/**
* @see org.eurocarbdb.MolecularFramework.sugar.GlycoGraph#containsNode(org.eurocarbdb.MolecularFramework.sugar.GlycoNode)
*/
public boolean containsNode(GlycoNode a_objNode)
{
return this.m_aResidues.contains(a_objNode);
}
/**
* @param residue
* @throws GlycoconjugateException
*/
private void searchCyclicForDeleting(GlycoNode a_objResidue) throws GlycoconjugateException
{
for (Iterator<GlycoNode> t_iterNodes = this.m_aResidues.iterator(); t_iterNodes.hasNext(); )
{
GlycoNode t_objElement = t_iterNodes.next();
if ( t_objElement.getClass() == SugarUnitCyclic.class )
{
SugarUnitCyclic t_objCyclic = (SugarUnitCyclic) t_objElement;
if ( t_objCyclic.getCyclicStart() == a_objResidue )
{
this.removeNode(t_objElement);
}
}
}
}
/**Recursive check if query node has specified parent
* @param child
* @param parent
* @return
*/
public boolean isParent(GlycoNode a_objParent, GlycoNode a_objNode)
{
GlycoNode t_objParent = a_objNode.getParentNode();
if ( t_objParent == null )
{
return false;
}
if ( t_objParent == a_objParent )
{
return true;
}
return this.isParent(a_objParent,t_objParent);
}
/**
* @see org.eurocarbdb.MolecularFramework.sugar.GlycoGraph#removeEdge(org.eurocarbdb.MolecularFramework.sugar.GlycoEdge)
*/
public boolean removeEdge(GlycoEdge a_objEdge) throws GlycoconjugateException
{
GlycoNode t_objChild = a_objEdge.getChild();
GlycoNode t_objParent = a_objEdge.getParent();
if ( a_objEdge == null )
{
return false;
}
if ( t_objChild == null || t_objParent == null )
{
throw new GlycoconjugateException("The edge contains null values.");
}
if ( t_objChild.getParentEdge() != a_objEdge )
{
throw new GlycoconjugateException("The child attachment is not correct");
}
ArrayList<GlycoEdge> t_aEdges = t_objParent.getChildEdges();
if ( !t_aEdges.contains(a_objEdge) )
{
throw new GlycoconjugateException("The parent attachment is not correct");
}
t_objChild.removeParentEdge(a_objEdge);
t_objParent.removeChildEdge(a_objEdge);
return true;
}
public void setConnection(GlycoEdge a_objEdge)
{
a_objEdge.setParent(null);
a_objEdge.setChild(null);
this.m_objConnection = a_objEdge;
}
public GlycoEdge getConnection()
{
return this.m_objConnection;
}
public ArrayList<GlycoNode> getParents()
{
return this.m_aParents;
}
protected boolean addParent(GlycoNode a_objParent) throws GlycoconjugateException
{
if ( a_objParent == null )
{
throw new GlycoconjugateException("null is not a valide parent.");
}
if ( this.m_aParents.contains(a_objParent) )
{
return false;
}
GlycoVisitorNodeType t_objType = new GlycoVisitorNodeType();
try
{
if ( t_objType.isSugarUnitCyclic(a_objParent) )
{
throw new GlycoconjugateException("A cyclic unit can't be a parent of a ProbabilisticSugarPart.");
}
if ( t_objType.isSugarUnitAlternative(a_objParent) )
{
throw new GlycoconjugateException("A alternative unit can't be a parent of a ProbabilisticSugarPart.");
}
this.m_aParents.add(a_objParent);
}
catch (GlycoVisitorException e)
{
throw new GlycoconjugateException(e.getErrorMessage(),e);
}
return true;
}
public double getProbabilityUpper()
{
return this.m_dAufenthaltswahrscheinlichkeitUpper;
}
public double getProbabilityLower()
{
return this.m_dAufenthaltswahrscheinlichkeitLower;
}
public void setProbability(double a_dLower,double a_dUpper) throws GlycoconjugateException
{
if ( a_dLower > a_dUpper )
{
throw new GlycoconjugateException("The lower border of a probability must be smaller or equal than the upper border.");
}
this.m_dAufenthaltswahrscheinlichkeitLower = a_dLower;
this.m_dAufenthaltswahrscheinlichkeitUpper = a_dUpper;
}
public void setProbability(double a_dProb)
{
this.m_dAufenthaltswahrscheinlichkeitLower = a_dProb;
this.m_dAufenthaltswahrscheinlichkeitUpper = a_dProb;
}
/**
* Does not copy the parent nodes.
* @return
* @throws GlycoconjugateException
*/
public UnderdeterminedSubTree copy() throws GlycoconjugateException
{
HashMap<GlycoNode,GlycoNode> t_hashResidues = new HashMap<GlycoNode,GlycoNode>();
UnderdeterminedSubTree t_objCopy = new UnderdeterminedSubTree();
GlycoNode t_objNodeOne;
GlycoNode t_objNodeTwo;
GlycoEdge t_objLinkOriginal;
GlycoEdge t_objLinkCopy;
ArrayList<GlycoEdge> t_aLinkages;
// copy all nodes
for (Iterator<GlycoNode> t_iterNode = this.m_aResidues.iterator(); t_iterNode.hasNext();)
{
t_objNodeOne = t_iterNode.next();
t_objNodeTwo = t_objNodeOne.copy();
t_hashResidues.put(t_objNodeOne,t_objNodeTwo);
t_objCopy.addNode(t_objNodeTwo);
}
// copy linkages
for (Iterator<GlycoNode> t_iterNode = this.m_aResidues.iterator(); t_iterNode.hasNext();)
{
t_objNodeOne = t_iterNode.next();
t_aLinkages = t_objNodeOne.getChildEdges();
for (Iterator<GlycoEdge> t_iterLinkages = t_aLinkages.iterator(); t_iterLinkages.hasNext();)
{
t_objLinkOriginal = t_iterLinkages.next();
t_objLinkCopy = t_objLinkOriginal.copy();
t_objNodeOne = t_hashResidues.get(t_objLinkOriginal.getParent());
t_objNodeTwo = t_hashResidues.get(t_objLinkOriginal.getChild());
if ( t_objNodeOne == null || t_objNodeTwo == null )
{
throw new GlycoconjugateException("Impossible to copy underdetermined subtree unit. Null values in copy.");
}
t_objCopy.addEdge( t_objNodeOne, t_objNodeTwo, t_objLinkCopy);
}
}
// copy special infos
t_objCopy.setProbability( this.m_dAufenthaltswahrscheinlichkeitLower, this.m_dAufenthaltswahrscheinlichkeitUpper );
if ( this.m_objConnection != null )
{
t_objCopy.setConnection(this.m_objConnection.copy());
}
return t_objCopy;
}
}