/*
* 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: 1232 $ by $Author: glycoslave $ on $Date:: 2009-06-19 #$
*/
package org.eurocarbdb.sugar.impl;
// stdlib imports
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
// 3rd party imports - commons logging
import org.apache.log4j.Logger;
// eurocarb imports
import org.eurocarbdb.sugar.*;
import static java.util.Collections.unmodifiableList;
/**
* Implements monosaccharides.
*
* @author mjh
*/
public class ComplexMonosaccharide extends SimpleMonosaccharide
{
//~~~~~~~~~~~~~~~~~~~~~~ STATIC FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~//
public static final int UNKNOWN_RING = -1;
/** Logging instance. */
static final Logger log = Logger.getLogger( ComplexMonosaccharide.class );
//~~~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~~//
/** List of applicable basetypes for this monosac; majority will be <= 2 basetypes */
private List<Basetype> basetypes = new ArrayList<Basetype>( 2 );
private Superclass superclass;
/** The (reducing end) carbon atom that is attached to the ring oxygen.
* ringStart is always < ringEnd. ringEnd & ringStart are both set to
* {@link OPEN_CHAIN} if monosac is in open chain form. */
private int ringStart = UNKNOWN_RING;
/** The (non-reducing end) carbon atom that is attached to the ring oxygen.
* ringEnd is always > ringStart. ringEnd & ringStart are both set to
* {@link OPEN_CHAIN} if monosac is in open chain form. */
private int ringEnd = UNKNOWN_RING;
/** List of modifications to this monosaccharide. Default to a zero
* size modification list to save memory for the most common case. */
private List<Modification> modifications = new ArrayList<Modification>( 0 );
private List<Molecule> attached;
//~~~~~~~~~~~~~~~~~~~~~~ CONSTRUCTORS ~~~~~~~~~~~~~~~~~~~~~~~~~//
/**
* Creates a new Monosaccharide with the given attributes.
* It is expected that monosaccharides will generally be
* looked up, rather than created, per se.
*/
public ComplexMonosaccharide( Anomer a, Superclass s )
//throws IllegalArgumentException
{
this( a, s,
UNKNOWN_RING, UNKNOWN_RING, // ring start, end
null, // default basetypes
null // default modifications
);
}
/**
* Creates a new Monosaccharide with the given attributes.
* It is expected that monosaccharides will generally be
* looked up, rather than created, per se.
*/
public ComplexMonosaccharide( Anomer a,
Superclass s,
int ring_start,
int ring_end,
List<Basetype> basetype_list,
List<Modification> modification_list )
{
if ( a == null )
throw new IllegalArgumentException(
"Anomer can't be null");
if ( s == null )
throw new IllegalArgumentException(
"Superclass can't be null");
if ( basetype_list == null )
basetype_list = new ArrayList<Basetype>( 2 );
if ( modification_list == null )
modification_list = new ArrayList<Modification>( 0 );
setAnomer( a );
this.superclass = s;
this.ringEnd = ring_end;
this.ringStart = ring_start;
this.basetypes = basetype_list;
this.modifications = modification_list;
this.attached = new ArrayList<Molecule>( superclass.size() );
}
public ComplexMonosaccharide( Monosaccharide example )
{
// TODO here...
log.warn("zomg implement meeee!");
}
/** temp */
public ComplexMonosaccharide() {}
//~~~~~~~~~~~~~~~~~~~~~~ STATIC METHODS ~~~~~~~~~~~~~~~~~~~~~~~//
/*-*
*<p>
* Look up a Monosaccharide by a string name/descriptor only.
*</p>
*<p>
* INTEGRATION OF MONOSAC DB LOOKUP SHOULD GO HERE.
*</p>
*<p>
* The idea is that various sequence formats will be tried to
* parse the given name and the resultant monosaccharide normalised
* and returned.
*</p>
*-/
public static Monosaccharide forName( String name )
{
Monosaccharide m = new Monosaccharide();
m.name = name;
return m;
}
*/
/**
* Parse a Monosaccharide from a string name/descriptor using the
* given {@link SequenceFormat}.
*/
public static Monosaccharide forName( String name, SequenceFormat format )
{
return format.getMonosaccharide( name );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~//
public void attach( Molecule entity, int position )
{
if ( _position_occupied( position ) )
throw new PositionOccupiedException( this, position );
_set_position( position, entity );
if ( log.isDebugEnabled() )
{
log.debug("attached substituent '"
+ entity
+ "'; monosac name is now: '"
+ getName()
+ "'"
);
}
}
public String getName()
{
return null;
}
/**
* Adds the given basetype to the current list of basetypes comprising
* this monosaccharide.
*/
public void addBasetype( Basetype b )
{
if ( b == null )
throw new IllegalArgumentException(
"Basetype can't be null");
assert basetypes != null;
this.basetypes.add( b );
}
/**
* Adds the given modification to this monosaccharide.
*/
public void addModification( Modification m )
{
if ( m == null )
throw new IllegalArgumentException(
"Modification can't be null");
assert modifications != null;
this.modifications.add( m );
}
/**
* mjh2rene: needs clarification
*
* @return Positive Startposition of the ring or -1 if not validated
*/
public int getRingStart()
{
return this.ringStart;
}
/**
* mjh2rene: needs clarification
*
* @return Positive endposition of the ring or -1 if not validated
*/
public int getRingEnd()
{
return this.ringEnd;
}
@Override
public Superclass getSuperclass()
{
return superclass;
}
/**
* Sets the superclass (ring-size configuration) of this
* monosaccharide.
*/
public void setSuperclass( Superclass s )
throws IllegalArgumentException
{
if ( s == null )
throw new IllegalArgumentException(
"Superclass can't be null");
this.superclass = s;
}
/**
* Returns the number of basetypes present in this monosaccharide.
*/
public int getBasetypeCount()
{
return this.basetypes.size();
}
/**
* Returns the list of basetypes of this monosaccharide.
*/
public List<Basetype> getBasetypes()
{
return unmodifiableList( this.basetypes );
}
/**
* Returns the list of modifications to this monosaccharide.
*/
public List<Modification> getModifications()
{
return unmodifiableList( this.modifications );
}
/**
* Removes the given {@link Basetype} from the list of
* basetypes for this monosaccharide.
* @return true if basetype was removed.
*/
public boolean removeBasetype( Basetype baseType )
{
return this.basetypes.remove( baseType );
}
/**
* Removes the given {@link Basetype} from the list of
* modifications for this monosaccharide.
* @return true if modification was removed.
*/
public boolean removeModification( Modification m )
{
return this.modifications.remove( m );
}
/** Sets ring start position. */
public void setRingStart( int ringStart ) //throws IllegalArgumentException
{
_check_ring( ringStart, this.ringEnd );
this.ringStart = ringStart;
}
/** Sets ring end position. */
public void setRingEnd( int ringEnd ) //throws IllegalArgumentException
{
_check_ring( this.ringStart, ringEnd );
this.ringEnd = ringEnd;
}
/** definition to be finalised... */
public String toString()
{
return getName(); //+ "_" + Integer.toString( hashCode() & 0xFF, 16 );
}
//~~~~~~~~~~~~~~~~~~~~~~ PRIVATE METHODS ~~~~~~~~~~~~~~~~~~~~~~//
/** Validates passed ring start- and end-points. */
private final void _check_ring( int ring_start, int ring_end )
{
if ( ringStart < -1 )
throw new IllegalArgumentException(
"Ring start position must be equal or larger than -1" );
if ( ringEnd < -1 )
throw new IllegalArgumentException(
"Ring end position must be equal or larger than -1" );
if ( ringStart > ringEnd )
throw new IllegalArgumentException(
"Endpoint must be larger than startpoint");
}
private final boolean _position_occupied( int position )
{
return attached.get( position ) != null;
}
private final void _set_position( int position, Molecule m )
{
attached.set( position, m );
}
} // end class Monosaccharide