/*
 *This library is free software; you can redistribute it and/or
 *modify it under the terms of the GNU Lesser General Public
 *License as published by the Free Software Foundation; either
 *version 2.1 of the License, or (at your option) any later version.
 *
 *This library 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.
 *
 *You should have received a copy of the GNU Lesser General Public
 *License along with this library; if not, write to the Free Software
 *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* 
 * This software was written by Phillip Lord (p.lord@hgmp.mrc.ac.uk)
 * whilst at the University of Manchester as a Pfizer post-doctoral 
 * Research Fellow. 
 *
 * The initial code base is copyright by Pfizer, or the University
 * of Manchester. Modifications to the initial code base are copyright
 * of their respective authors, or their employers as appropriate. 
 * Authorship of the modifications may be determined from the ChangeLog
 * placed at the end of this file
 */

package uk.ac.man.bioinf.sequence; // Package name inserted by JPack
import uk.ac.man.bioinf.sequence.Sequence;
import uk.ac.man.bioinf.sequence.SequenceType;
import uk.ac.man.bioinf.sequence.Element;


/**
 * AbstractSequence.java
 *
 * Provides some of the methods for sequence. It assumes that the
 * sequence is stored internally as a list of Residues and does all
 * the mapping into chars.
 *
 * Created: Thu Mar  2 16:10:51 2000
 *
 * @author Phillip Lord
 * @version $Id: AbstractSequence.java,v 1.7 2001/04/11 17:04:43 lord Exp $
 */

public abstract class AbstractSequence implements Sequence
{
  private SequenceType type;
  
  public AbstractSequence( SequenceType type )
  {
    this.type = type;
  }
  
  public SequenceType getSequenceType()
  {
    return type;
  }
   
  public Sequence getSubSequence( int position, int length )
  {
    checkRange( position );
    checkRange( position + length - 1);
    
    int end = position + length;
    
    Element[] subsequence = new Element[ length ];
    for( int i = position; i < end; i++ ){
      subsequence[ i - position ] = getElementAt( i );
    }
    
    return new DefaultSequence( subsequence, getSequenceType() );
  }

  public char[] getSequenceAsChars()
  {
    Element[] seq = getSequenceAsElements();
    char[] seqChars = new char[ seq.length ];
    SequenceType type = getSequenceType();

    for( int i = 0 ; i < seq.length ; i++ ){
      seqChars[ i ] = seq[ i ].toChar();
    } //end for( i < seq.length )
    return seqChars;
  }
    
  public char getElementAtAsChar( int index )
  {
    return getElementAt( index ).toChar();
  }

  // some utility methods which may be useful for subclasses
  /**
   * Check if all these elements are of a valid type
   * @throws InvalidSequenceTypeException if an element is not of a
   * valid type
   * @param elements the elements
   * @param type the sequence type
   */
  protected void checkSequenceType( Element[] elements ) throws InvalidSequenceTypeException
  {
    // do some type checking to make sure all of the elements are of
    // the correct type
    for( int i = 0; i < elements.length; i++ ){
      if( !type.isElement( elements[ i ] ) ){
	throw new InvalidSequenceTypeException
	  ( "Element " + elements[ i ] + " at " + ( i + 1 ) + " is not part of the sequence type " +
	    type.toString() );
      }
    }
  }
  
  protected InvalidSequenceTypeException getSequenceTypeException( Element element )
  {
    return new InvalidSequenceTypeException
      ( "Element " + element + " is not part of the sequence type " +
	type.toString() );
  }
  
  protected void checkSequenceType( Element element ) throws InvalidSequenceTypeException
  {
    if( !type.isElement( element ) ){
      throw getSequenceTypeException( element );
    }
  }
  
  protected NoSuchSequenceElementException getSequenceIndexException( int index )
  {
    return  new NoSuchSequenceElementException
      ( "Attempt to access element at " + index + " in sequence " + this + " which does not exist" );
  }
  
  protected void checkRange( int index )
  {
    if( index < 1 || index > getLength() ){
      throw getSequenceIndexException( index );
    }
  }
} // AbstractSequence



/*
 * ChangeLog
 * $Log: AbstractSequence.java,v $
 * Revision 1.7  2001/04/11 17:04:43  lord
 * Added License agreements to all code
 *
 * Revision 1.6  2000/05/30 16:04:18  lord
 * Have rationalised and sorted all the import statements
 *
 * Revision 1.5  2000/03/23 19:51:36  lord
 * Improved range checking for efficiency of access to elements
 *
 * Revision 1.4  2000/03/16 16:12:40  lord
 * Fixed bug in subsequence ranges
 *
 * Revision 1.3  2000/03/14 19:42:51  jns
 * o editing a problem that was to do with the translation of gapped indecies and
 * ungapped indicies and vica-versa.
 *
 * Revision 1.2  2000/03/08 17:26:35  lord
 * To many changes to document
 *
 * Revision 1.1  2000/03/02 17:45:55  lord
 * Initial checkin
 *
 */
