/*
* 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: 1870 $ by $Author: david@nixbioinf.org $ on $Date:: 2010-02-23 #$
*/
package org.eurocarbdb.application.glycanbuilder;
import java.util.*;
/**
Store a pattern defined by a certain number of objects of different
types. Each object type is identified by a string.
@author Alessio Ceroni (a.ceroni@imperial.ac.uk)
*/
public class TypePattern implements Comparable<TypePattern> {
private TreeMap<String,Integer> pattern = new TreeMap<String,Integer>();
private int count = 0;
/**
Empty constructor
*/
public TypePattern() {
}
/**
Return a copy of this object
*/
public TypePattern clone() {
TypePattern ret = new TypePattern();
ret.pattern = (TreeMap<String,Integer>)pattern.clone();
ret.count = count;
return ret;
}
public boolean equals(Object other) {
if( !(other instanceof TypePattern) )
return false;
return toString().equals(other.toString());
}
public int hashCode() {
return toString().hashCode();
}
/**
Return <code>true<code> if the other pattern is contained in
this one. Inclusion is defined by the quantities of each typed
object.
*/
public boolean contains(TypePattern other) {
if( other==null )
return true;
if( count<other.count )
return false;
for(Map.Entry<String,Integer> entry : other.pattern.entrySet() ) {
Integer value = pattern.get(entry.getKey());
if( value==null || value.intValue()<entry.getValue().intValue() )
return false;
}
return true;
}
public int compareTo(TypePattern other) {
if( other==null )
return +1;
if( count<other.count )
return -1;
for(Map.Entry<String,Integer> entry : other.pattern.entrySet() ) {
Integer value = pattern.get(entry.getKey());
if( value==null || value.intValue()<entry.getValue().intValue() )
return -1;
}
if( count==other.count )
return 0;
return 1;
}
/**
Return the total number of typed objects in this pattern
*/
public int size() {
return count;
}
/**
Add a typed object to the pattern
@param type the string representing the object type
*/
public void add(String type) {
add(type,1);
}
/**
Add a typed object to the pattern
@param type the string representing the object type
@param num the number of objects to add
*/
public void add(String type, int num) {
if( num==0 )
return;
Integer old_num = pattern.get(type);
if( old_num==null )
pattern.put(type,num);
else {
if( (old_num+num)==0 )
pattern.remove(type);
else
pattern.put(type,old_num+num);
}
count +=num;
}
/**
Return a copy of this object to which another typed object has
been added
@param type the string representing the object type
*/
public TypePattern and(String type) {
return and(type,1);
}
/**
Return a copy of this object to which another typed object has
been added
@param num the number of objects to add
@param type the string representing the object type
*/
public TypePattern and(String type, int num) {
TypePattern ret = this.clone();
ret.add(type,num);
return ret;
}
/**
Return the list of the types of all objects in the pattern
*/
public Collection<String> getTypes() {
Vector<String> types = new Vector<String>();
for( Map.Entry<String,Integer> e : pattern.entrySet() )
for( int i=0; i<e.getValue(); i++ )
types.add(e.getKey());
return types;
}
/**
Return all subpatterns of this pattern with a certain size. A
sub-pattern is a combination of the typed objects which is
included in this pattern
@see #contains
*/
public Collection<TypePattern> subPatterns(int size) {
Vector<TypePattern> sub_patterns = new Vector<TypePattern>();
subPatterns(new TypePattern(),pattern.entrySet().iterator(),size,sub_patterns);
return sub_patterns;
}
private void subPatterns(TypePattern toadd, Iterator<Map.Entry<String,Integer>> current, int size, Vector<TypePattern> buffer) {
if( size==0 )
buffer.add(toadd);
else if( current.hasNext() ) {
Map.Entry<String,Integer> type_num = current.next();
for( int i=0; i<=type_num.getValue() && i<=size; i++ )
subPatterns(toadd.and(type_num.getKey(),i),current,size-i,buffer);
}
}
/**
Subtract another object from the current one. Subtraction is
performed by computing the differences in quantities for each
typed object
*/
public TypePattern subtract(TypePattern other) {
TypePattern ret = this.clone();
for( Map.Entry<String,Integer> e : other.pattern.entrySet() )
ret.add(e.getKey(),-e.getValue());
return ret;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for( Map.Entry<String,Integer> e : pattern.entrySet() ) {
if( e.getValue()>0 )
sb.append("+");
else if( e.getValue()==-1 )
sb.append("-");
if( e.getValue()!=1 && e.getValue()!=-1 )
sb.append(e.getValue());
sb.append(e.getKey());
}
return sb.toString();
}
}