/*
* 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.application.glycanbuilder;
import java.util.regex.*;
/**
Match a rule to a linkage. Is used by the {@link
LinkageStyleDictionary} to decide the style of the linkage for
rendering. The base class has different implementations depending
on the rules applied.
@see LinkageStyle
@author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
public abstract class LinkageMatcher {
/**
Return a matcher corresponding the rule specified by the
string. A rule is a boolean predicate containing boolean
operators and conditions matching certain information about the
linkage. The standard binary operators (& = and, ¦
= or, ^ = xor, ! = not) apply. Normal parenthesis can
be used for the boolean operations.
<p>
The possible linkage conditions are:
<ul>
<li>1: always true </li>
<li>0: always false </li>
<li>re: parent is a reducing end marker </li>
<li>ps: parent is a monosaccharide </li>
<li>pr: parent is a ring fragment </li>
<li>px: parent is a special residue </li>
<li>pc: parent is a glycosidic cleaveage</li>
<li>pb: parent is a bracket residue</li>
<li>pp: parent is a repeating block indicator</li>
<li>pa: parent is an anchor point</li>
<li>cs: child is a monosaccharide </li>
<li>cr: child is a ring fragment </li>
<li>cx: child is a special residue </li>
<li>cc: child is a glycosidic cleaveage</li>
<li>cp: child is a repeating block indicator</li>
</ul>
*/
static public LinkageMatcher parse(String init) {
try {
return OperatorFactory.fromString(init);
}
catch(Exception e) {
LogUtils.report(e);
return null;
}
}
/**
Return <code>true</code> if the rule represented by this object
matches the linkage information
@param parent the parent residue in the linkage
@param link the linkage for which the style should be retrieved
@param child the child residue in the linkage
*/
abstract public boolean matches(Residue parent, Linkage link, Residue child);
}
class OperatorFactory {
static public LinkageMatcher fromString(String init) throws Exception{
init = TextUtils.trim(init);
init = TextUtils.removeTrailingParentheses(init);
init = TextUtils.trim(init);
if( init.equals("") )
return new TrueCondition();
// look for binary operators
int ind = TextUtils.findFirstOfWithParentheses(init,"&|^");
if( ind!=-1 ) {
String lop = init.substring(0,ind);
char op = init.charAt(ind);
String rop = init.substring(ind+1);
if( op=='&' )
return new AndOperator(fromString(lop),fromString(rop));
if( op=='|' )
return new OrOperator(fromString(lop),fromString(rop));
if( op=='^' )
return new XOrOperator(fromString(lop),fromString(rop));
throw new Exception("Memory error");
}
// look for unary operators
if( init.startsWith("!") )
return new NegationOperator(fromString(init.substring(1)));
// parse condition
return ConditionFactory.fromString(init);
}
}
class NegationOperator extends LinkageMatcher {
protected LinkageMatcher op;
public NegationOperator(LinkageMatcher _op) {
op = _op;
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return !op.matches(parent,link,child);
}
public String toString() {
return "!(" + op.toString() + ")";
}
}
class AndOperator extends LinkageMatcher {
protected LinkageMatcher op1;
protected LinkageMatcher op2;
public AndOperator(LinkageMatcher _op1, LinkageMatcher _op2) {
op1 = _op1;
op2 = _op2;
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (op1.matches(parent,link,child) && op2.matches(parent,link,child));
}
public String toString() {
return "(" + op1.toString() + ")&(" + op2.toString() + ")";
}
}
class OrOperator extends LinkageMatcher {
protected LinkageMatcher op1;
protected LinkageMatcher op2;
public OrOperator(LinkageMatcher _op1, LinkageMatcher _op2) {
op1 = _op1;
op2 = _op2;
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (op1.matches(parent,link,child) | op2.matches(parent,link,child));
}
public String toString() {
return "(" + op1.toString() + ")|(" + op2.toString() + ")";
}
}
class XOrOperator extends LinkageMatcher {
protected LinkageMatcher op1;
protected LinkageMatcher op2;
public XOrOperator(LinkageMatcher _op1, LinkageMatcher _op2) {
op1 = _op1;
op2 = _op2;
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (op1.matches(parent,link,child) ^ op2.matches(parent,link,child));
}
public String toString() {
return "(" + op1.toString() + ")^(" + op2.toString() + ")";
}
}
class ConditionFactory {
static public LinkageMatcher fromString(String init) throws Exception {
if( TextUtils.findFirstOf(init,"&|^!")!=-1 )
throw new Exception("Invalid condition format: " + init);
init = TextUtils.trim(init);
if( init.equals("1") || init.equals("true") )
return new TrueCondition();
if( init.equals("0") || init.equals("false") )
return new FalseCondition();
int ind = init.indexOf('=');
if( ind==-1 ) {
String attribute = init;
if( attribute.equals("re") )
return new ReducingEndCondition();
if( attribute.equals("ps") )
return new ParentIsSaccharideCondition();
if( attribute.equals("pr") )
return new ParentIsRingFragmentCondition();
if( attribute.equals("px") )
return new ParentIsSpecialCondition();
if( attribute.equals("pc") )
return new ParentIsCleavageCondition();
if( attribute.equals("pb") )
return new ParentIsBracketCondition();
if( attribute.equals("pp") )
return new ParentIsRepetitionCondition();
if( attribute.equals("pa") )
return new ParentIsAttachPointCondition();
if( attribute.equals("cs") )
return new ChildIsSaccharideCondition();
if( attribute.equals("cr") )
return new ChildIsRingFragmentCondition();
if( attribute.equals("cx") )
return new ChildIsSpecialCondition();
if( attribute.equals("cc") )
return new ChildIsCleavageCondition();
if( attribute.equals("cb") )
return new ChildIsBracketCondition();
if( attribute.equals("cp") )
return new ChildIsRepetitionCondition();
throw new Exception("Invalid attribute name: <" + attribute + ">");
}
else {
String attribute = init.substring(0,ind);
String value = init.substring(ind+1);
if( attribute.equals("pt") ) // parent type
return new ParentTypeCondition(value);
if( attribute.equals("ct") ) // child type
return new ChildTypeCondition(value);
if( attribute.equals("lp") ) // linkage position
return new LinkagePositionCondition(value);
if( attribute.equals("as") ) // child anomeric state
return new ChildAnomericStateCondition(value);
if( attribute.equals("ac") ) // child anomeric carbon
return new ChildAnomericCarbonCondition(value);
throw new Exception("Invalid attribute name: <" + attribute + ">");
}
}
}
class TrueCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return true;
}
public String toString() {
return "1";
}
}
class FalseCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return false;
}
public String toString() {
return "0";
}
}
class ReducingEndCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isReducingEnd());
}
public String toString() {
return "re";
}
}
class ParentIsSaccharideCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isSaccharide());
}
public String toString() {
return "ps";
}
}
class ParentIsRingFragmentCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isRingFragment());
}
public String toString() {
return "pr";
}
}
class ParentIsSpecialCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isSpecial());
}
public String toString() {
return "px";
}
}
class ParentIsCleavageCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isCleavage());
}
public String toString() {
return "pc";
}
}
class ParentIsBracketCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isBracket());
}
public String toString() {
return "pb";
}
}
class ParentIsRepetitionCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isRepetition());
}
public String toString() {
return "pp";
}
}
class ParentIsAttachPointCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && parent.isAttachPoint());
}
public String toString() {
return "pa";
}
}
class ChildIsSaccharideCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isSaccharide());
}
public String toString() {
return "cs";
}
}
class ChildIsRingFragmentCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isRingFragment());
}
public String toString() {
return "cr";
}
}
class ChildIsSpecialCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isSpecial());
}
public String toString() {
return "cx";
}
}
class ChildIsCleavageCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isCleavage());
}
public String toString() {
return "cc";
}
}
class ChildIsBracketCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isBracket());
}
public String toString() {
return "cb";
}
}
class ChildIsRepetitionCondition extends LinkageMatcher {
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && child.isRepetition());
}
public String toString() {
return "cp";
}
}
abstract class ValuedCondition extends LinkageMatcher {
protected String regex;
protected Pattern pattern;
ValuedCondition(String _regex) {
regex = _regex;
pattern = Pattern.compile(regex);
}
public boolean matches(String value) {
return pattern.matcher(value).matches();
}
}
class ParentTypeCondition extends ValuedCondition {
public ParentTypeCondition(String _regex) {
super(_regex);
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (parent!=null && matches(parent.getType().getName()));
}
public String toString() {
return "pt=" + regex;
}
}
class ChildTypeCondition extends ValuedCondition {
public ChildTypeCondition(String _regex) {
super(_regex);
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (child!=null && matches(child.getType().getName()));
}
public String toString() {
return "ct=" + regex;
}
}
class LinkagePositionCondition extends ValuedCondition {
public LinkagePositionCondition(String _regex) {
super(_regex);
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (link!=null && matches(""+link.getParentPositionsString()));
}
public String toString() {
return "lp=" + regex;
}
}
class ChildAnomericStateCondition extends ValuedCondition {
public ChildAnomericStateCondition(String _regex) {
super(_regex);
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (link!=null && matches(""+child.getAnomericState()));
}
public String toString() {
return "as=" + regex;
}
}
class ChildAnomericCarbonCondition extends ValuedCondition {
public ChildAnomericCarbonCondition(String _regex) {
super(_regex);
}
public boolean matches(Residue parent, Linkage link, Residue child) {
return (link!=null && matches(""+link.getChildPositionsString()));
}
public String toString() {
return "ac=" + regex;
}
}