/*
 *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.alignment; // Package name inserted by JPack
import uk.ac.man.bioinf.sequence.AbstractMutableSequence;
import uk.ac.man.bioinf.sequence.Element;
import uk.ac.man.bioinf.sequence.SequenceType;
import uk.ac.man.bioinf.sequence.event.VetoableSequenceEvent;
import uk.ac.man.bioinf.sequence.event.SequenceVetoException;
import uk.ac.man.bioinf.sequence.event.SequenceEventType;
import uk.ac.man.bioinf.sequence.NoSuchSequenceElementException;


/**
 * AbstractGappedSequence.java
 *
 *
 * Created: Sat Mar  4 12:17:02 2000
 *
 * @author Phillip Lord
 * @version $Id: AbstractGappedSequence.java,v 1.5 2001/04/11 17:04:43 lord Exp $
 */

public abstract class AbstractGappedSequence extends AbstractMutableSequence
  implements GappedSequence
{
  public AbstractGappedSequence( SequenceType type )
  {
    super( type );
  }
  
  protected abstract void insertGapAtQuietly( int index );
  
  public void insertGapAt( int index ) throws SequenceVetoException
  {
    boolean fireEventP = hasListeners();
    
    if( fireEventP ){
      VetoableSequenceEvent event =  new VetoableSequenceEvent
	( this, index, SequenceEventType.GAPINSERT );
      
      fireVetoableSequenceEvent( event );
      insertGapAtQuietly( index );
      fireSequenceEvent( event );
    }
    else{
      // premature optimization is the root of all evil. 
      insertGapAtQuietly( index );
    }
  }
  
  public void insertGapAt( int index, int length ) throws SequenceVetoException
  {
    boolean fireEventP = hasListeners();
    
    if( fireEventP ){
      VetoableSequenceEvent event =  new VetoableSequenceEvent
	( this, index, length, SequenceEventType.GAPINSERT );
      fireVetoableSequenceEvent( event );

      for( int i = 0; i < length; i++ ){
	insertGapAtQuietly( index + i );
      } //end for( i < length )
      
      fireSequenceEvent( event );
    }
    else{
      // premature optimization is the root of all evil. 
      for( int i = 0; i < length; i++ ){
	insertGapAtQuietly( index + i );
      } //end 
    }
    
  }
  
  protected abstract void deleteGapAtQuietly( int index );
  
  public void deleteGapAt( int index ) throws SequenceVetoException
  {
    // delegate function
    this.deleteGapAt(index, 1);
  }
  
  public void deleteGapAt( int index, int length ) throws SequenceVetoException
  {
    boolean fireEventP = hasListeners();
    
    if( fireEventP ){
      VetoableSequenceEvent event =  new VetoableSequenceEvent
	( this, index, length, SequenceEventType.GAPDELETE );
      fireVetoableSequenceEvent( event );
      
      for( int i = 0; i < length; i++ ){
	deleteGapAtQuietly( index );
      } //end for( i < length )
      
      fireSequenceEvent( event );
    }
    else{
      for( int i = 0; i < length; i++ ){
	deleteGapAtQuietly( index + i );
      } //end for( i < length )
    }
  }
  
  public char getGappedElementAtAsChar( int index )
  {
    return getGappedElementAt( index ).toChar();
  }
  
  public char[] getGappedSequenceAsChars()
  {
    char[] retn = new char[ getGappedLength() ];
    
    Element[] elements = getGappedSequenceAsElements();
    
    for( int i = 0; i < elements.length; i++ ){
      retn[ i ] = elements[ i ].toChar();
    } //end for( i < elements.length )
    
    return retn;
  }

    
  // protected utility methods
  protected void checkGappedRange( int index )
  {
    if( index < 1 || index > getGappedLength() ){
      throw getGappedSequenceIndexException( index );
    }
  }
  
  protected void checkGappedRangeForInsert( int index )
  {
    if( index < 1 || index > getGappedLength() + 1 ){
      throw new NoSuchSequenceElementException( "Attempt to insert gapped element " +
						index + " in sequence " + this + " illegally" );
    }
  }

  protected NoSuchSequenceElementException getGappedSequenceIndexException( int index )
  {
    return new NoSuchSequenceElementException( "Attempt to access gapped element " +
						index + " in sequence " + this + " which doesnt exist" );
  }
} // AbstractGappedSequence



/*
 * ChangeLog
 * $Log: AbstractGappedSequence.java,v $
 * Revision 1.5  2001/04/11 17:04:43  lord
 * Added License agreements to all code
 *
 * Revision 1.4  2000/11/02 14:55:17  jns
 * o made deleteGapAt(int) call its sister deleteGapAt(int, int) to save
 * on code usage
 * o made deleteGapAt actually function correctly - previously I had
 * forgotten that the delete function is as the DEL key works, not as the
 * BACK_SPACE key works (i.e., deletion works from left -> right, not
 * right -> left).
 *
 * Revision 1.3  2000/09/15 16:34:14  lord
 * Now only instantiates events when there are actually listeners. This
 * small change can actually save the creation of a vast number of events
 * in practice, as many gaps are often removed when parsing an
 * SequenceAlignment from file
 *
 * Revision 1.2  2000/03/23 19:51:36  lord
 * Improved range checking for efficiency of access to elements
 *
 * Revision 1.1  2000/03/08 17:26:35  lord
 * To many changes to document
 *
 */
