/* * 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 #$ */ /** @author Alessio Ceroni (a.ceroni@imperial.ac.uk) */ package org.eurocarbdb.application.glycoworkbench.plugin.grammar; import org.eurocarbdb.application.glycoworkbench.*; import org.eurocarbdb.application.glycanbuilder.*; import java.util.*; import java.util.regex.*; public class GrammarTree implements Comparable { static Pattern pattern; static { pattern = Pattern.compile("[1-9N\\?][abo\\?][1-3\\?]-[DL\\?]-[a-zA-Z]+"); } public static final String END = "+"; // String label = ""; GrammarTree parent = null; Vector<GrammarTree> children = new Vector<GrammarTree>(); // public GrammarTree() { } public GrammarTree(String _label) { label = _label; } public String getLabel() { return label; } public GrammarTree getParent() { return parent; } public Collection<GrammarTree> getChildren() { return children; } public int getNoChildren() { return children.size(); } public GrammarTree getRoot() { if( parent!=null ) return parent.getRoot(); return this; } public void addChild(GrammarTree toadd) { if( toadd==null ) return; children.add(toadd); toadd.parent = this; } public GrammarTree clone() { return clone(null,null); } public GrammarTree clone(GrammarTree stop_at, GrammarTree stop_el) { if( this==stop_at ) return stop_el; GrammarTree ret = new GrammarTree(label); for( GrammarTree child : children ) ret.addChild(child.clone(stop_at,stop_el)); return ret; } public int compareTo(Object o) { if( o==null || !(o instanceof GrammarTree)) return 1; return this.toString(true).compareTo(((GrammarTree)o).toString(true)); } // public boolean hasChildrenTagged() { for( GrammarTree child : children ) { if( child.isTagged() ) return true; } return false; } public static void tag(GrammarTree gt, String tag, Collection<GrammarTree> to_be_tagged) { if( gt==null || to_be_tagged==null ) return; if( to_be_tagged.contains(gt) ) gt.label = addTag(gt.label,tag); for(GrammarTree child : gt.children ) tag(child,tag,to_be_tagged); } public static String removeTag(String str) { if( str==null ) return null; int ind = str.indexOf('#'); if( ind!=-1 ) return str.substring(0,ind); return str; } public static String addTag(String str, String tag) { if( str.equals(END) ) return str; return removeTag(str) + "#" + tag; } public boolean isTagged() { if( label==null ) return false; return (label.indexOf('#')!=-1); } // serialization public static GrammarTree fromGlycan(Glycan structure, boolean add_info) throws Exception { if( structure.isFuzzy() ) throw new Exception("Cannot convert a fuzzy structure into grammar tree"); if( structure.isFragment() ) throw new Exception("Cannot convert a fragmented structure into grammar tree"); if( structure.hasRepetition() ) throw new Exception("Cannot convert a repeating structure into grammar tree"); return toGrammarTree(structure.getRoot(),add_info); } public Glycan toGlycan(MassOptions default_mass_options) throws Exception { return new Glycan(fromGrammarTree(this),true,default_mass_options); } public String toString() { return toString(false); } public String toString(boolean ordered) { StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(label); if( ordered) { // convert children to string and sort LinkedList<String> sortedList = new LinkedList<String>(); for( GrammarTree child : children ) { String str_child = child.toString(ordered); int index = Collections.binarySearch(sortedList, str_child); if (index < 0) sortedList.add(-index-1, str_child); else sortedList.add(index, str_child); } // write children for( String child : sortedList ) sb.append(child); } else { // write children directl for( GrammarTree child : children ) sb.append(child.toString(ordered)); } sb.append(")"); return sb.toString(); } private static GrammarTree toGrammarTree(Residue current, boolean add_info) { if( current==null ) return null; GrammarTree ret = new GrammarTree(); // set label for current ret.label=""; if( current.isReducingEnd() && !current.isSaccharide() ) ret.label = END; else { if( add_info ) { ret.label += current.getParentLinkage().getParentPositionsSingle(); ret.label += current.getAnomericState(); ret.label += current.getAnomericCarbon(); ret.label += "-"; ret.label += current.getChirality(); ret.label += "-"; } ret.label += current.getTypeName(); } // add children for( Linkage l : current.getChildrenLinkages() ) ret.addChild(toGrammarTree(l.getChildResidue(),add_info)); return ret; } private static int countOpenPar(String str) { int count = 0; char[] buf = str.toCharArray(); for( int i=0; i<buf.length; i++ ) if( buf[i]=='(' ) count++; return count; } private static int countClosePar(String str) { int count = 0; char[] buf = str.toCharArray(); for( int i=0; i<buf.length; i++ ) if( buf[i]==')' ) count++; return count; } public static GrammarTree fromString(String str) throws Exception { str = TextUtils.trim(str); if( str==null || str.length()==0 ) return null; GrammarTree ret = new GrammarTree(); // check parentheses if( str.charAt(0)!='(' ) throw new Exception("Missing start parenthesis: " + str); if( str.charAt(str.length()-1)!=')' ) throw new Exception("Missing end parenthesis: " + str); str = str.substring(1,str.length()-1); // get label int ind = str.indexOf('('); if( ind==-1 ) ind = str.length(); ret.label = str.substring(0,ind); str = str.substring(ind); // parse children while(str.length()>0 ) { if( str.charAt(0)!='(' ) throw new Exception("Missing start parenthesis: " + str); int ind2 = TextUtils.findEnclosed(str); if( ind2==-1 ) throw new Exception("Missing end parenthesis: " + str); ret.addChild(fromString(str.substring(0,ind2+1))); str = str.substring(ind2+1); } return ret; } public static Residue fromGrammarTree(GrammarTree gt) throws Exception { // parse residue type; Residue ret = null; if( gt.label.equals(END) ) ret = new Residue(ResidueType.createFreeReducingEnd()); else { // remove tag String type = removeTag(gt.label); // parse info Matcher m = pattern.matcher(type); if( m.matches() ) { ret = ResidueDictionary.newResidue(type.substring(6)); ret.setParentLinkage(new Linkage(null,ret,type.charAt(0))); ret.setAnomericState(type.charAt(1)); ret.setAnomericCarbon(type.charAt(2)); ret.setChirality(type.charAt(4)); } else { ret = ResidueDictionary.newResidue(type); ret.setParentLinkage(new Linkage(null,ret)); } } // parse children for( GrammarTree gtc : gt.children ) { Residue child = fromGrammarTree(gtc); ret.addChild(child,child.getParentLinkage().getParentPositionsSingle()); } return ret; } }