=head1 LICENSE

  Copyright (c) 1999-2012 The European Bioinformatics Institute and
  Genome Research Limited.  All rights reserved.

  This software is distributed under a modified Apache license.
  For license details, please see

    http://www.ensembl.org/info/about/code_licence.html

=head1 CONTACT

  Please email comments or questions to the public Ensembl
  developers list at <dev@ensembl.org>.

  Questions may also be sent to the Ensembl help desk at
  <helpdesk@ensembl.org>.

=cut

=head1 NAME

Bio::EnsEMBL::Map::DBSQL::DitagFeatureAdaptor

=head1 SYNOPSIS

  my $dfa = $db->get_DitagFeatureAdaptor;
  my $ditagFeatures = $dfa->fetch_all_by_Slice( $slice, "SME005" );

  foreach my $ditagFeature (@$ditagFeatures) {
    print $ditagFeature->ditag_id . " "
      . $ditagFeature->slice . " "
      . $ditagFeature->start . "-"
      . $ditagFeature->end . " "
      . $ditagFeature->strand;
  }

=head1 DESCRIPTION

Provides database interaction for the Bio::EnsEMBL::Map::DitagFeature
object

=head1 METHODS

=cut

package Bio::EnsEMBL::Map::DBSQL::DitagFeatureAdaptor;

use strict;
use vars ('@ISA');

use Bio::EnsEMBL::Map::Ditag;
use Bio::EnsEMBL::Map::DitagFeature;
use Bio::EnsEMBL::DBSQL::BaseAdaptor;
use Bio::EnsEMBL::Utils::Exception qw( throw warning );

@ISA = qw(Bio::EnsEMBL::DBSQL::BaseAdaptor);


=head2 fetch_all

  Arg [1]    : none
  Example    : @all_tags = @{$ditagfeature_adaptor->fetch_all};
  Description: Retrieves all ditagFeatures from the database;
               Usually not a good idea, use fetch_all_by_Slice instead.
  Returntype : listref of Bio::EnsEMBL::Map::DitagFeature
  Caller     : general
  Status     : At Risk

=cut

sub fetch_all {
  my $self = shift;

  my $sth = $self->prepare("SELECT df.ditag_feature_id, df.ditag_id, df.seq_region_id, 
                            df.seq_region_start, df.seq_region_end, df.seq_region_strand, 
                            df.analysis_id, df.hit_start, df.hit_end, df.hit_strand, 
                            df.cigar_line, df.ditag_side, df.ditag_pair_id, d.tag_count 
                            FROM   ditag_feature df, ditag d 
                            WHERE  df.ditag_id=d.ditag_id" );
  $sth->execute;

  my $result = $self->_fetch($sth);

  return $result;
}


=head2 fetch_by_dbID

  Arg [1]    : ditagFeature dbID
  Example    : @my_tags = @{$ditagfeature_adaptor->fetch_by_dbID($my_id)};
  Description: Retrieves a ditagFeature from the database.
  Returntype : Bio::EnsEMBL::Map::DitagFeature
  Caller     : general
  Status     : At Risk

=cut

sub fetch_by_dbID {
  my ($self, $dbid) = @_;

  my $sth = $self->prepare("SELECT df.ditag_feature_id, df.ditag_id, df.seq_region_id, 
                            df.seq_region_start, df.seq_region_end, df.seq_region_strand, 
                            df.analysis_id, df.hit_start, df.hit_end, df.hit_strand, 
                            df.cigar_line, df.ditag_side, df.ditag_pair_id, d.tag_count 
                            FROM   ditag_feature df, ditag d 
                            WHERE  df.ditag_id=d.ditag_id AND df.ditag_feature_id = ?" );
  $sth->execute($dbid);

  my $result = $self->_fetch($sth);

  return $result->[0];
}


=head2 fetch_all_by_ditagID

  Arg [1]    : ditag dbID
  Arg [2]    : (optional) ditag-pair dbID
  Arg [3]    : (optional) analysis ID
  Example    : @my_tags = @{$ditagfeature_adaptor->fetch_all_by_ditag_id($my_id)};
  Description: Retrieves all ditagFeatures from the database linking to a specific ditag-id
  Returntype : listref of Bio::EnsEMBL::Map::DitagFeature
  Caller     : general
  Status     : At Risk

=cut

sub fetch_all_by_ditagID {
  my ($self, $ditag_id, $ditag_pair_id, $analysis_id) = @_;

  my $arg = $ditag_id;
  my $sql = "SELECT df.ditag_feature_id, df.ditag_id, df.seq_region_id, 
             df.seq_region_start, df.seq_region_end, df.seq_region_strand, 
             df.analysis_id, df.hit_start, df.hit_end, df.hit_strand, 
             df.cigar_line, df.ditag_side, df.ditag_pair_id, d.tag_count 
             FROM   ditag_feature df, ditag d 
             WHERE  df.ditag_id=d.ditag_id AND df.ditag_id = ? ";
  if($ditag_pair_id){
    $sql .= "AND df.ditag_pair_id = ? ";
    $arg .= ", $ditag_pair_id";
  }
  if($analysis_id){
    $sql .= "AND df.analysis_id = ? ";
    $arg .= ", $analysis_id";
  }
  $sql   .= "ORDER BY df.ditag_pair_id";
  my $sth = $self->prepare($sql);
  $sth->execute(split(",",$arg));

  my $result = $self->_fetch($sth);

  return $result;
}


=head2 fetch_all_by_type

  Arg [1]    : ditag type
  Example    : @my_tags = @{$ditagfeature_adaptor->fetch_all_by_type($type)};
  Description: Retrieves all ditagFeatures from the database linking to a specific ditag-type
  Returntype : listref of Bio::EnsEMBL::Map::DitagFeature
  Caller     : general
  Status     : At Risk

=cut

sub fetch_all_by_type {
  my ($self, $ditag_type) = @_;

  my $sth = $self->prepare("SELECT df.ditag_feature_id, df.ditag_id, df.seq_region_id, 
                            df.seq_region_start, df.seq_region_end, df.seq_region_strand, 
                            df.analysis_id, df.hit_start, df.hit_end, df.hit_strand, 
                            df.cigar_line, df.ditag_side, df.ditag_pair_id, d.tag_count 
                            FROM   ditag_feature df, ditag d 
                            WHERE  df.ditag_id=d.ditag_id AND d.type = ? 
                            ORDER BY df.ditag_id, df.ditag_pair_id" );
  $sth->execute($ditag_type);

  my $result = $self->_fetch($sth);

  return $result;
}


=head2 fetch_all_by_Slice

  Arg [1]    : Bio::EnsEMBL::Slice
  Arg [2]    : (optional) ditag type name (specific library) or an aray ref with multiple type names
  Arg [3]    : (optional) analysis logic_name
  Example    : $tags = $ditagfeature_adaptor->fetch_all_by_Slice($slice, "SME005");
  Description: Retrieves ditagFeatures from the database overlapping a specific region
               and (optional) of a specific ditag type or analysis.
               Start & end locations are returned in slice coordinates, now.
  Returntype : listref of Bio::EnsEMBL::Map::DitagFeatures
  Caller     : general
  Status     : At Risk

=cut

sub fetch_all_by_Slice {
  my ($self, $slice, $tagtype, $logic_name) = @_;

  my @result;
  my $moresql;

  if(!ref($slice) || !$slice->isa("Bio::EnsEMBL::Slice")) {
    throw("Bio::EnsEMBL::Slice argument expected not $slice.");
  }

  #get affected ditag_feature_ids
  my $sql = "SELECT df.ditag_feature_id, df.ditag_id, df.seq_region_id, df.seq_region_start, 
             df.seq_region_end, df.seq_region_strand, df.analysis_id, df.hit_start, df.hit_end, 
             df.hit_strand, df.cigar_line, df.ditag_side, df.ditag_pair_id, 
             d.tag_count 
             FROM ditag_feature df, ditag d 
             WHERE df.ditag_id=d.ditag_id";
  if($tagtype){
    my $tagtypes = '';
    #check if array
    if(ref $tagtype eq 'ARRAY'){
      my @arraytype_mod;
      foreach my $arraytype (@$tagtype){ push @arraytype_mod, '"'.$arraytype.'"' }
      $tagtypes = join(", ", @arraytype_mod);
    }
    else{
      $tagtypes = '"'.$tagtype.'"';
    }
    $sql .= " AND d.type IN(".$tagtypes.")";
  }
  if($logic_name){
    my $analysis = $self->db->get_AnalysisAdaptor->fetch_by_logic_name($logic_name);
    if(!$analysis) {
      return undef;
    }
    $sql .= " AND df.analysis_id = ".$analysis->dbID();
  }
  $sql .= " AND df.seq_region_id = ".$slice->get_seq_region_id.
          " AND df.seq_region_start <= ".$slice->end.
	  " AND df.seq_region_end   >= ".$slice->start;

  my $sth = $self->prepare($sql);
  $sth->execute();

  my $result = $self->_fetch($sth, $slice);
  push(@result, @$result);

  return \@result;
}


=head2 fetch_pairs_by_Slice

  Arg [1]    : Bio::EnsEMBL::Slice
  Arg [2]    : (optional) ditag type (specific library)
  Arg [3]    : (optional) analysis logic_name
  Example    : my $ditagfeatures = $dfa->fetch_pairs_by_Slice($slice);
               foreach my $ditagfeature (@$ditagfeatures){
                 $minstart   = $$ditagfeature2{'start'};
                 $maxend     = $$ditagfeature2{'end'};
                 $bothstrand = $$ditagfeature2{'strand'};
                 $tag_count  = $$ditagfeature2{'tag_count'};
                 print "$minstart, $maxend, $bothstrand, $tag_count\n";
               }
  Description: Retrieves ditagFeature information in pairs from the database overlapping a specific region
               and (optional) of a specific ditag type or analysis. The absotute start and end points are
               fetched.
               Slices should be SMALL!
  Returntype : array ref with hash ref of artifical DitagFeature object
  Caller     : general
  Status     : At Risk

=cut

sub fetch_pairs_by_Slice {
  my ($self, $slice, $tagtype, $logic_name) = @_;
  my ($tag_id, $pair_id, $seq_region_id, $start, $end, $strand, $analysis_id, $tag_count);
  my @result;

  my $sql = "SELECT df.ditag_id, df.ditag_pair_id, df.seq_region_id, MIN(df.seq_region_start), ".
            "MAX(df.seq_region_end), df.seq_region_strand, df.analysis_id, d.tag_count ".
            "FROM ditag_feature df, ditag d ".
            "WHERE df.ditag_id=d.ditag_id ";
  if($tagtype){
    $sql .= "AND d.type = \"".$tagtype."\"";
  }
  $sql .= " AND df.seq_region_id = ".$slice->get_seq_region_id.
          " AND df.seq_region_start <= ".$slice->end.
	  " AND df.seq_region_end >= ".$slice->start;
  if($logic_name){
    my $analysis = $self->db->get_AnalysisAdaptor->fetch_by_logic_name($logic_name);
    if(!$analysis) {
      return undef;
    }
    $sql .= " AND df.analysis_id = ".$analysis->dbID();
  }
  $sql .= " GROUP BY df.ditag_id, df.ditag_pair_id;";
  my $sth = $self->prepare($sql);
  $sth->execute();
  $sth->bind_columns( \$tag_id, \$pair_id, \$seq_region_id, \$start, \$end, \$strand, \$analysis_id ,\$tag_count);
  while ( $sth->fetch ) {
    #convert into relative slice coordinates
    if($slice->strand == 1) {
      $start = $start - $slice->start + 1;
      $end   = $end   - $slice->start + 1;
    }
    else{
      $start  = $slice->end - $end + 1;
      $end    = $slice->end - $start + 1;
      $strand *= -1;
    }

    my %ditag_feature_pair = (
                      ditag     => $tag_id,
                      pair_id   => $pair_id,
                      region    => $seq_region_id,
                      start     => $start,
                      end       => $end,
                      strand    => $strand,
                      analysis  => $analysis_id,
                      tag_count => $tag_count
                     );
    push(@result, \%ditag_feature_pair);
  }

  return \@result;
}


=head2 _fetch

  Arg [1]    : statement handler
  Arg [2]    : (optional) target-slice for the feature
  Description: generic sql-fetch function for the DitagFeature fetch methods
  Returntype : listref of Bio::EnsEMBL::Map::DitagFeatures
  Caller     : private
  Status     : At Risk

=cut

sub _fetch {
  my ($self, $sth, $dest_slice) = @_;

  my ( $tag_id, $mothertag_id, $seqreg, $seqstart, $seqend, $strand, $analysis_id, $hit_start,
       $hit_end, $hit_strand, $cigar_line, $ditag_side, $ditag_pair_id, $tag_count );
  $sth->bind_columns( \$tag_id,        \$mothertag_id, \$seqreg,
                      \$seqstart,      \$seqend,       \$strand,
                      \$analysis_id,   \$hit_start,    \$hit_end,
                      \$hit_strand,    \$cigar_line,   \$ditag_side,
                      \$ditag_pair_id, \$tag_count );

  my @ditag_features;
  my $dest_slice_start;
  my $dest_slice_end;
  my $dest_slice_strand;
  if($dest_slice) {
    $dest_slice_start   = $dest_slice->start();
    $dest_slice_end     = $dest_slice->end();
    $dest_slice_strand  = $dest_slice->strand();
  }

  while ( $sth->fetch ) {
    my $analysis_obj = $self->db->get_AnalysisAdaptor->fetch_by_dbID($analysis_id);
    my $slice        = $self->db->get_SliceAdaptor->fetch_by_seq_region_id($seqreg);

    if($dest_slice) {
      if($dest_slice_start != 1 || $dest_slice_strand != 1) {
        if($dest_slice_strand == 1) {
          $seqstart    = $seqstart  - $dest_slice_start + 1;
          $seqend      = $seqend    - $dest_slice_start + 1;
        } else {
          my $tmp_seq_region_start = $seqstart;
          $seqstart    = $dest_slice_end - $seqend + 1;
          $seqend      = $dest_slice_end - $tmp_seq_region_start + 1;
          $strand     *= -1;
        }
	$slice = $dest_slice;
      }
    }

    push @ditag_features,
      Bio::EnsEMBL::Map::DitagFeature->new( -dbid          => $tag_id,
                                            -slice         => $slice,
                                            -start         => $seqstart,
                                            -end           => $seqend,
                                            -strand        => $strand, 
                                            -analysis      => $analysis_obj,
                                            -hit_start     => $hit_start,
                                            -hit_end       => $hit_end,
                                            -hit_strand    => $hit_strand,
                                            -ditag_id      => $mothertag_id,
                                            -cigar_line    => $cigar_line,
                                            -ditag_side    => $ditag_side,
					    -ditag_pair_id => $ditag_pair_id,
					    -ditag         => undef,
					    -tag_count     => $tag_count,
                                            -adaptor       => $self,
                                            );
  }

  return \@ditag_features;
}


=head2 sequence

  Arg [1]    : dbID of DitagFeature
  Example    : $ditagfeature_adaptor->get_sequence($ditagFeature->dbID)
  Description: get the part of the sequence of a ditag,
               that is actully aligned to the genome.
  Returntype : string
  Exceptions : thrown if not all data needed for storing is populated in the
               ditag features
  Caller     : Bio::EnsEMBL::Map::DitagFeature
  Status     : At Risk

=cut

sub sequence {
  my ($self, $dbID) = @_;

  my $sequence = undef;
  my $db  = $self->db() or throw "Couldn t get database connection.";
  my $sql = "SELECT d.sequence, df.hit_start, df.hit_end, df.hit_strand ".
            "FROM ditag d, ditag_feature df ".
	    "WHERE df.ditag_id=d.ditag_id and df.ditag_feature_id = ?";
  my $sth = $db->dbc->prepare($sql);
  $sth->execute( $dbID );
  my ($seq, $start, $end, $strand) = $sth->fetchrow_array();
  if($seq and $start and $end and $strand){
    $sequence = substr($seq, ($start-1), ($end-$strand));
    if($strand == -1) {
      $sequence =~ tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/;
    }
  }

  return $sequence;
}


=head2 store

  Arg [1]    : (Array ref of) Bio::EnsEMBL::Map::DitagFeature
  Example    : $ditagfeature_adaptor->store(@ditag_features);
  Description: Stores a single ditagFeature or
               a list of ditagFeatures in this database.
  Returntype : none
  Exceptions : thrown if not all data needed for storing is populated in the
               ditag features
  Caller     : general
  Status     : At Risk

=cut

sub store {
  my ( $self, $ditag_features ) = @_;

  if ( ref $ditag_features eq 'ARRAY' ) {
    if ( scalar(@$ditag_features) == 0 ) {
      throw( "Must call store with ditag_feature or list ref of ditags_features" );
    }
  } elsif ($ditag_features) {
    my @ditag_features;
    push @ditag_features, $ditag_features;
    $ditag_features = \@ditag_features;
  } else {
    throw( "Must call store with ditag_feature or list ref of ditag_features." );
  }

  my $db = $self->db() or throw "Couldn t get database connection.";

  my $sth1 = $self->prepare( "INSERT INTO ditag_feature( ditag_id, seq_region_id, seq_region_start, 
                              seq_region_end, seq_region_strand, analysis_id, hit_start, hit_end, 
                              hit_strand, cigar_line, ditag_side, ditag_pair_id ) 
                              VALUES( ?,?,?,?,?,?,?,?,?,?,?,? )" );
  my $sth2 = $self->prepare( "INSERT INTO ditag_feature( ditag_feature_ID, ditag_id, seq_region_id, 
                              seq_region_start, seq_region_end, seq_region_strand, analysis_id, hit_start, 
                              hit_end, hit_strand, cigar_line, ditag_side, ditag_pair_id ) 
                              VALUES( ?,?,?,?,?,?,?,?,?,?,?,?,? )" );
#  my $sth3 = $self->prepare( "SELECT COUNT(*) FROM ditag_feature 
#                              WHERE ditag_id = ?" );

TAG:
  foreach my $ditag_feature (@$ditag_features) {

    if ( !ref $ditag_feature || !$ditag_feature->isa("Bio::EnsEMBL::Map::DitagFeature") ) {
      throw(   "Object must be an Ensembl DitagFeature, "
             . "not a " . ref($ditag_feature) );
    }
    if ( $ditag_feature->is_stored($db) ) {
      warning(   "DitagFeature " . $ditag_feature->dbID .
                 " is already stored in this database,".
                 " maybe you need to use the update() method?" );
      next TAG;
    }
    if(!$ditag_feature->ditag_id or !($self->db->get_DitagAdaptor->fetch_by_dbID($ditag_feature->ditag_id))){
      throw("DitagFeature must be supplied with the id of a corresponding Ditag object.");
    }
    if(!$ditag_feature->ditag or !$ditag_feature->ditag->isa("Bio::EnsEMBL::Map::Ditag")){
      throw("DitagFeature must be linked to a valid Ditag object.");
    }


#    #check if more than x tags with this ditag id exist
#    $sth3->execute( $ditag_feature->ditag_id );
#    my ($num) = $sth3->fetchrow_array();
#    if ( ($num) and ($num > 1) ) {
#      warning( "There are already at least 2 DitagFeatures relating to Ditag ".
#                 $ditag->ditag_id." stored in this database." );
#      if ( $num > 4 ) {
#        warning( "not storing" );
#        next TAG;
#      }
#    }

    if ( $ditag_feature->dbID ) {
      $sth2->bind_param( 1,  $ditag_feature->dbID,                      SQL_INTEGER );
      $sth2->bind_param( 2,  $ditag_feature->ditag_id,                  SQL_INTEGER );
      $sth2->bind_param( 3, ($ditag_feature->slice->get_seq_region_id), SQL_INTEGER );
      $sth2->bind_param( 4,  $ditag_feature->start,                     SQL_INTEGER );
      $sth2->bind_param( 5,  $ditag_feature->end,                       SQL_INTEGER );
      $sth2->bind_param( 6,  $ditag_feature->strand,                    SQL_VARCHAR );
      $sth2->bind_param( 7,  $ditag_feature->analysis->dbID,            SQL_INTEGER );
      $sth2->bind_param( 8,  $ditag_feature->hit_start,                 SQL_INTEGER );
      $sth2->bind_param( 9,  $ditag_feature->hit_end,                   SQL_INTEGER );
      $sth2->bind_param( 10, $ditag_feature->hit_strand,                SQL_VARCHAR );
      $sth2->bind_param( 11, $ditag_feature->cigar_line,                SQL_VARCHAR );
      $sth2->bind_param( 12, $ditag_feature->ditag_side,                SQL_VARCHAR );
      $sth2->bind_param( 13, $ditag_feature->ditag_pair_id,             SQL_VARCHAR );
      $sth2->execute();
    }
    else{
      $sth1->bind_param( 1,  $ditag_feature->ditag_id,                  SQL_INTEGER );
      $sth1->bind_param( 2, ($ditag_feature->slice->get_seq_region_id), SQL_INTEGER );
      $sth1->bind_param( 3,  $ditag_feature->start,                     SQL_INTEGER );
      $sth1->bind_param( 4,  $ditag_feature->end,                       SQL_INTEGER );
      $sth1->bind_param( 5,  $ditag_feature->strand,                    SQL_VARCHAR );
      $sth1->bind_param( 6,  $ditag_feature->analysis->dbID,            SQL_INTEGER );
      $sth1->bind_param( 7,  $ditag_feature->hit_start,                 SQL_INTEGER );
      $sth1->bind_param( 8,  $ditag_feature->hit_end,                   SQL_INTEGER );
      $sth1->bind_param( 9,  $ditag_feature->hit_strand,                SQL_VARCHAR );
      $sth1->bind_param( 10, $ditag_feature->cigar_line,                SQL_VARCHAR );
      $sth1->bind_param( 11, $ditag_feature->ditag_side,                SQL_VARCHAR );
      $sth1->bind_param( 12, $ditag_feature->ditag_pair_id,             SQL_VARCHAR );
      $sth1->execute();
      my $dbID = $sth1->{'mysql_insertid'};
      $ditag_feature->dbID($dbID);
      $ditag_feature->adaptor($self);
    }

  }
}


=head2 batch_store

  Arg [1]    : (Array ref of) Bio::EnsEMBL::Map::DitagFeatures
  Arg [2]    : bool have_dbIDs
  Example    : $ditagfeature_adaptor->batch_store(\@ditag_features);
  Description: Stores a list of ditagFeatures in this database.
               DitagFeatures are expected to have no dbID yet unless flag "have_dbIDs" is true.
               They are inserted in one combined INSERT for better performance.
  Returntype : none
  Exceptions : thrown if not all data needed for storing is given for the
               ditag features
  Caller     : general
  Status     : At Risk

=cut

sub batch_store {
  my ( $self, $ditag_features, $have_dbIDs ) = @_;

  my @good_ditag_features;
  my ($sql, $sqladd);
  my $inserts = 0;

  if ( ref $ditag_features eq 'ARRAY' ) {
    if ( scalar(@$ditag_features) == 0 ) {
      throw( "Must call store with ditag_feature or list ref of ditag_features." );
    }
  } elsif ($ditag_features) {
    my @ditag_features;
    push @ditag_features, $ditag_features;
    $ditag_features = \@ditag_features;
  } else {
    throw( "Must call store with ditag_feature or list ref of ditag_features." );
  }

  my $db = $self->db() or throw "Couldn t get database connection.";

  #check whether it s a DitagFeature object and is not stored already
  foreach my $ditag_feature (@$ditag_features) {

    if ( !ref $ditag_feature || !$ditag_feature->isa("Bio::EnsEMBL::Map::DitagFeature") ) {
      throw(   "Object must be an Ensembl DitagFeature, "
             . "not a " . ref($ditag_feature) );
    }
    if(!$ditag_feature->ditag_id or !($self->db->get_DitagAdaptor->fetch_by_dbID($ditag_feature->ditag_id))){
      throw("DitagFeature must be supplied with the id of a corresponding Ditag object.");
    }

    if(!$ditag_feature->ditag or !$ditag_feature->ditag->isa("Bio::EnsEMBL::Map::Ditag")){
      throw("DitagFeature must be linked to a valid Ditag object.");
    }
    if ( $ditag_feature->is_stored($db) ) {
      warning(   "DitagFeature " . $ditag_feature->dbID
                 . " is already stored in this database." );
      next;
    }
    push(@good_ditag_features, $ditag_feature);
  }
  $ditag_features = undef;

  #create batch INSERT
  if($have_dbIDs){
    $sql = "INSERT INTO ditag_feature ( ditag_feature_id, ditag_id, seq_region_id, seq_region_start, ".
           "seq_region_end, seq_region_strand, analysis_id, hit_start, hit_end, ".
           "hit_strand, cigar_line, ditag_side, ditag_pair_id ) VALUES ";
    foreach my $ditag_feature (@good_ditag_features) {
      $sqladd = "";
      if($inserts){ $sqladd = ", " }
      $sqladd .= "(". $ditag_feature->ditag_feature_id.", ".$ditag_feature->ditag_id.", ".
	         ($ditag_feature->slice->get_seq_region_id).", ". $ditag_feature->start.", ".
		 $ditag_feature->end.", '".$ditag_feature->strand."', ".$ditag_feature->analysis->dbID.", ".
                 $ditag_feature->hit_start.", ".$ditag_feature->hit_end.", '".$ditag_feature->hit_strand.
		 "', '".$ditag_feature->cigar_line."', '".$ditag_feature->ditag_side."', ".
		 $ditag_feature->ditag_pair_id.")";
      $sql .= $sqladd;
      $inserts++;
    }
  }
  else{
    $sql = "INSERT INTO ditag_feature ( ditag_id, seq_region_id, seq_region_start, ".
           "seq_region_end, seq_region_strand, analysis_id, hit_start, hit_end, ".
           "hit_strand, cigar_line, ditag_side, ditag_pair_id ) VALUES ";
    foreach my $ditag_feature (@good_ditag_features) {
      $sqladd = "";
      if($inserts){ $sqladd = ", " }
      $sqladd .= "(". $ditag_feature->ditag_id.", ".($ditag_feature->slice->get_seq_region_id).", ".
	         $ditag_feature->start.", ".$ditag_feature->end.", '".$ditag_feature->strand."', ".
		 $ditag_feature->analysis->dbID.", ".$ditag_feature->hit_start.", ".$ditag_feature->hit_end.
		 ", '".$ditag_feature->hit_strand."', '".$ditag_feature->cigar_line."', '".
		 $ditag_feature->ditag_side."', ".$ditag_feature->ditag_pair_id.")";
      $sql .= $sqladd;
      $inserts++;
    }
  }

  #STORE
  if($inserts){
    print STDERR "\nHave $inserts Features.\n";
    eval{
      $db->dbc->do($sql);
    };
    if($@){
      warning("Problem inserting ditag feature batch!".$@."\n");
    }
  }
  else{
    warn "Nothing stored!";
  }

}


=head2 update

  Arg [1]    : ditagFeature to update
  Description: update an existing ditagFeature with new values
  Returntype : 1 on success
  Status     : At Risk

=cut

sub update {
  my ($self, $ditagFeature) = @_;

  my $sth = $self->prepare( "UPDATE ditag_feature
                             SET ditag_id=?, seq_region_id=?, seq_region_start=?, seq_region_end=?,
                             seq_region_strand=?, analysis_id=?, hit_start=?, hit_end=?, hit_strand=?,
                             cigar_line=?, ditag_side=?, ditag_pair_id=?
                             where ditag_feature_id=?;" );

  $sth->bind_param(1, $ditagFeature->ditag_id, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->seq_region_id, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->seq_region_start, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->seq_region_end, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->seq_region_strand, SQL_TINYINT);
  $sth->bind_param(1, $ditagFeature->hit_start, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->hit_end, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->hit_strand, SQL_TINYINT);
  $sth->bind_param(1, $ditagFeature->cigar_line, SQL_LONGVARCHAR);
  $sth->bind_param(1, $ditagFeature->ditag_side, SQL_VARCHAR);
  $sth->bind_param(1, $ditagFeature->ditag_pair_id, SQL_INTEGER);
  $sth->bind_param(1, $ditagFeature->dbID, SQL_INTEGER);

  my $result =$sth->execute();

  return $result;
}


=head2 list_dbIDs

  Args       : None
  Example    : my @feature_ids = @{$dfa->list_dbIDs()};
  Description: Gets an array of internal IDs for all DitagFeature objects in
               the current database.
  Arg[1]     : <optional> int. not 0 for the ids to be sorted by the seq_region.
  Returntype : List of ints
  Exceptions : None
  Status     : Stable

=cut

sub list_dbIDs {
  my ($self, $ordered) = shift;
	
  return $self->_list_dbIDs('ditag_feature', undef, $ordered);
}

1;
