/* * 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.GlycoVisitor; import org.eurocarbdb.MolecularFramework.util.visitor.GlycoVisitorException; import org.eurocarbdb.MolecularFramework.util.visitor.GlycoVisitorNodeType; public class SugarUnitRepeat extends GlycoNode implements GlycoGraph { public static final int UNKNOWN = -1; private GlycoEdge m_linkRepeatLinkage = null; private int m_iMinCount = SugarUnitRepeat.UNKNOWN; private int m_iMaxCount = SugarUnitRepeat.UNKNOWN; private ArrayList<GlycoNode> m_aResidues = new ArrayList<GlycoNode>(); private ArrayList<UnderdeterminedSubTree> m_aSpezialTrees = new ArrayList<UnderdeterminedSubTree>(); public SugarUnitRepeat() { super(); this.m_aResidues.clear(); } /** * * @return minima count for this repeat unit ; -1 for unknown */ public int getMinRepeatCount() { return this.m_iMinCount; } /** * * @return maxima count for this repeat unit ; -1 for unknown */ public int getMaxRepeatCount() { return this.m_iMaxCount; } /** * */ public void setMinRepeatCount(int a_iCount) { this.m_iMinCount = a_iCount; } /** * */ public void setMaxRepeatCount(int a_iCount) { this.m_iMaxCount = a_iCount; } /** * Sets the repeat linkage * @param a_objLinkage * @param a_objChild * @param a_objParent * @throws GlycoconjugateException */ public void setRepeatLinkage(GlycoEdge a_objLinkage, GlycoNode a_objParent, GlycoNode a_objChild) throws GlycoconjugateException { if ( a_objChild == null || a_objLinkage == null || a_objParent == null ) { throw new GlycoconjugateException("null is not valide for a internal repeat linkage and residue."); } this.m_linkRepeatLinkage = a_objLinkage; this.m_linkRepeatLinkage.setParent(a_objParent); this.m_linkRepeatLinkage.setChild(a_objChild); } /** * Delivers the repeat linkage. * * @return repeat linkage */ public GlycoEdge getRepeatLinkage() { return this.m_linkRepeatLinkage; } /** * @see org.eurocarbdb.util.Visitable#accept(org.eurocarbdb.util.GlycoVisitor) */ public void accept(GlycoVisitor a_objVisitor) throws GlycoVisitorException { a_objVisitor.visit(this); } /** * 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("Repeat unit 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."); } if ( !this.m_aResidues.contains(a_objResidue) ) { try { GlycoVisitorNodeType t_objNodeType = new GlycoVisitorNodeType(); if ( t_objNodeType.isSugarUnitCyclic(a_objResidue) ) { throw new GlycoconjugateException("Cyclic unit are not allowed in repeat units."); } } 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 repeat unit."); } // test for indirect cyclic structures if ( this.isParent(a_objChild,a_objParent) ) { throw new GlycoconjugateException("You try to create a cyclic sugar, cyclic units are not allowed in repeat units."); } 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); } } } } /** * @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 SugarUnitRepeat copy() throws GlycoconjugateException { ArrayList<SugarUnitAlternative> t_aAlternative = new ArrayList<SugarUnitAlternative>(); HashMap<GlycoNode,GlycoNode> t_hashResidues = new HashMap<GlycoNode,GlycoNode>(); SugarUnitRepeat t_objCopy = new SugarUnitRepeat(); GlycoNode t_objNodeOne; GlycoNode t_objNodeTwo; GlycoEdge t_objLinkOriginal; GlycoEdge t_objLinkCopy; ArrayList<GlycoEdge> t_aLinkages; GlycoVisitorNodeType t_visNodeType = new GlycoVisitorNodeType(); // copy all nodes for (Iterator<GlycoNode> t_iterNode = this.m_aResidues.iterator(); t_iterNode.hasNext();) { t_objNodeOne = t_iterNode.next(); try { if ( !t_visNodeType.isSugarUnitCyclic(t_objNodeOne) ) { if ( t_visNodeType.isSugarUnitAlternative(t_objNodeOne) ) { throw new GlycoconjugateException("Unable to copy alternative residues."); } else { t_objNodeTwo = t_objNodeOne.copy(); t_hashResidues.put(t_objNodeOne,t_objNodeTwo); t_objCopy.addNode(t_objNodeTwo); } } } catch (GlycoVisitorException e) { throw new GlycoconjugateException(e.getMessage(),e); } } // 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 repeat unit. Null values in copy."); } t_objCopy.addEdge( t_objNodeOne, t_objNodeTwo, t_objLinkCopy); } } // copy repeat linkage t_objLinkOriginal = this.m_linkRepeatLinkage; 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 repeat unit. Null values in copy."); } t_objCopy.setRepeatLinkage(t_objLinkCopy,t_objNodeOne,t_objNodeTwo); // copie repeat t_objCopy.setMinRepeatCount( this.m_iMinCount ); t_objCopy.setMaxRepeatCount( this.m_iMaxCount ); // correkt alternative attache positions for (Iterator<SugarUnitAlternative> t_iterAlternatives = t_aAlternative.iterator(); t_iterAlternatives.hasNext();) { SugarUnitAlternative t_objAlternative = t_iterAlternatives.next(); GlycoGraphAlternative t_objAltGraph; GlycoNode t_objKeyNode; GlycoNode t_objKeyNodeNew; HashMap<GlycoNode,GlycoNode> t_objMapNew = new HashMap<GlycoNode,GlycoNode>(); HashMap<GlycoNode,GlycoNode> t_objMapOld; for (Iterator<GlycoGraphAlternative> t_iterAltGraph = t_objAlternative.getAlternatives().iterator(); t_iterAltGraph.hasNext();) { t_objAltGraph = t_iterAltGraph.next(); t_objMapNew.clear(); t_objMapOld = t_objAltGraph.getLeadOutNodeToNode(); for (Iterator<GlycoNode> t_iterPositions = t_objMapOld.keySet().iterator(); t_iterPositions.hasNext();) { t_objKeyNode = t_iterPositions.next(); t_objKeyNodeNew = t_hashResidues.get(t_objKeyNode); if ( t_objKeyNodeNew == null ) { throw new GlycoconjugateException("Error child attache position of alternative graph was not translated."); } t_objMapNew.put(t_objKeyNodeNew, t_objMapOld.get(t_objKeyNode)); } t_objAlternative.setLeadOutNodeToNode(t_objMapNew,t_objAltGraph); } } // copie special units UnderdeterminedSubTree t_objTreeOriginal; UnderdeterminedSubTree t_objTreeCopy; for (Iterator<UnderdeterminedSubTree> t_iterTree = this.m_aSpezialTrees.iterator(); t_iterTree.hasNext();) { t_objTreeOriginal = t_iterTree.next(); t_objTreeCopy = t_objTreeOriginal.copy(); t_objCopy.addUndeterminedSubTree(t_objTreeCopy); // copy parent information for (Iterator<GlycoNode> t_iterParents = t_objTreeOriginal.getParents().iterator(); t_iterParents.hasNext();) { t_objNodeOne = t_iterParents.next(); t_objNodeTwo = t_hashResidues.get(t_objNodeOne); if ( t_objNodeTwo == null ) { throw new GlycoconjugateException("Impossible to copy repeat unit. Null values in copy."); } t_objTreeCopy.addParent( t_objNodeTwo ); } } return t_objCopy; } public void setUndeterminedSubTrees(ArrayList<UnderdeterminedSubTree> a_aSubTree) throws GlycoconjugateException { if ( a_aSubTree == null ) { throw new GlycoconjugateException("null is not a valide set of special subtrees."); } this.m_aSpezialTrees.clear(); for (Iterator<UnderdeterminedSubTree> t_iterTree = a_aSubTree.iterator(); t_iterTree.hasNext();) { this.addUndeterminedSubTree(t_iterTree.next()); } } public ArrayList<UnderdeterminedSubTree> getUndeterminedSubTrees() { return this.m_aSpezialTrees; } public boolean addUndeterminedSubTreeParent(UnderdeterminedSubTree a_objTree, GlycoNode a_objParent ) throws GlycoconjugateException { if ( !this.m_aResidues.contains(a_objParent) ) { throw new GlycoconjugateException("Parent is not part of the sugar."); } if ( !this.m_aSpezialTrees.contains(a_objTree) ) { throw new GlycoconjugateException("UnderdeterminedSubTree is not part of the sugar."); } return a_objTree.addParent(a_objParent); } public boolean addUndeterminedSubTree(UnderdeterminedSubTree a_objTree) throws GlycoconjugateException { if ( a_objTree == null ) { throw new GlycoconjugateException("null is not valide for special subtree."); } if ( !this.m_aSpezialTrees.contains(a_objTree) ) { return this.m_aSpezialTrees.add(a_objTree); } return false; } /** * @param i */ public void setRepeatCount(int a_iCount) { this.setMinRepeatCount(a_iCount); this.setMaxRepeatCount(a_iCount); } }