package Bio::EnsEMBL::GlyphSet::_alignment;
use strict;
use base qw(Bio::EnsEMBL::GlyphSet);

#==============================================================================
# The following functions can be over-riden if the class does require
# something diffirent - main one to be over-riden is probably the
# features call - as it will need to take different parameters...
#==============================================================================
sub _das_link {
## Returns the 'group' that a given feature belongs to. Features in the same
## group are linked together via an open rectangle. Can be subclassed.
  my $self = shift;
  return de_camel( $self->my_config('object_type') || 'dna_align_feature' );
}

sub feature_group {
  my( $self, $f ) = @_;
  #this regexp will remove the differences in names between the ends of BACs.
  #Only a start in getting the display accurate however - (i) seperate glyph, (ii) only one strand,
  #(iii) distinguish between multiple mappings of the same end and the different ends
#  (my $name = $f->hseqname) =~ s/(\.?[xyz][abc]|T7|SP6)$//;;
#   return $name;
  return $f->hseqname;    ## For core features this is what the sequence name is...
}

sub feature_label {
  my( $self, $f, $db_name ) = @_;
  return $f->hseqname;
}

sub feature_title {
  my( $self, $f,$db_name ) = @_;
  $db_name ||= 'External Feature';
  return "$db_name ".$f->hseqname;
}

sub features {
  my ($self) = @_;
  my $method      = 'get_all_'.( $self->my_config('object_type') || 'DnaAlignFeature' ).'s';
  my $db          = $self->my_config('db');
  my @logic_names = @{ $self->my_config( 'logicnames' )||[] };
  $self->timer_push( 'Initializing don', undef, 'fetch' );
  my @results = map { $self->{'container'}->$method($_,undef,$db)||() } @logic_names;
  $self->timer_push( 'Retrieved features', undef, 'fetch' );
  my %results = ( $self->my_config('name') => [@results] );
  return %results;
}

sub href {
### Links to /Location/Genome
  my( $self, $f ) = @_;
  my $r = $f->seq_region_name.':'.$f->seq_region_start.'-'.$f->seq_region_end;
  return $self->_url({
    'action' => 'Genome',
    'ftype'  => $self->my_config('object_type') || 'DnaAlignFeature',
    'r'      => $r,
    'id'     => $f->display_id,
    'db'     => $self->my_config('db'),
  });
}

#==============================================================================
# Next we have the _init function which chooses how to render the
# features...
#==============================================================================

sub render_unlimited {
  my $self = shift;
  $self->render_normal( 1, 1000 );
}

sub render_stack {
  my $self = shift;
  $self->render_normal( 1, 40 );
}

sub render_half_height {
  my $self = shift;
  $self->render_normal( $self->my_config('height')/2 || 4);
}

sub colour_key {
  my( $self, $feature_key ) = @_;
  return $self->my_config( 'sub_type' );
}

sub render_labels {
  my $self = shift;
  $self->{'show_labels'} = 1;
  $self->render_normal();
}

sub render_normal {
  my $self = shift;
  return $self->render_text if $self->{'text_export'};
  my $tfh    = $self->{'config'}->texthelper()->height($self->{'config'}->species_defs->ENSEMBL_STYLE->{'GRAPHIC_FONT'});
  my $h      = @_ ? shift : ($self->my_config('height') || 8);
  my $dep    = @_ ? shift : ($self->my_config('dep'   ) || 6);
  my $gap    = $h<2 ? 1 : 2;   
## Information about the container...
  my $strand = $self->strand;
  my $strand_flag    = $self->my_config('strand');

  my $length = $self->{'container'}->length();
## And now about the drawing configuration
  my $pix_per_bp     = $self->scalex;
  my $DRAW_CIGAR     = ( $self->my_config('force_cigar') eq 'yes' )|| ($pix_per_bp > 0.2) ;
## Highlights...
  my %highlights = map { $_,1 } $self->highlights;
  my $hi_colour = 'highlight1';

  if( $self->{'extras'} && $self->{'extras'}{'height'} ) {
    $h = $self->{'extras'}{'height'};
  }

## Get array of features and push them into the id hash...
  my %features = $self->features;

  #get details of external_db - currently only retrieved from core since they should be all the same
  my $db = 'DATABASE_CORE';
#  my $db = 'DATABASE_'.uc($self->my_config('db'));
  my $extdbs = $self->species_defs->databases->{$db}{'tables'}{'external_db'}{'entries'};

  my $y_offset = 0;

  my $features_drawn = 0;
  my $features_bumped = 0;
    my $label_h = 0;
  my( $fontname, $fontsize ) ;
  if( $self->{'show_labels'} ) {
    ( $fontname, $fontsize ) = $self->get_font_details( 'outertext' );
    my( $txt, $bit, $w,$th ) = $self->get_text_width( 0, 'X', '', 'ptsize' => $fontsize, 'font' => $fontname );
    $label_h = $th;
  }
  foreach my $feature_key ( $strand < 0 ? sort keys %features : reverse sort keys %features ) {
    $self->_init_bump( undef, $dep );
    my %id             = ();
    $self->{'track_key'} = $feature_key;
    foreach my $features ( @{$features{$feature_key}} ) {
      foreach my $f (
        map { $_->[2] }
        sort{ $a->[0] <=> $b->[0] }
        map { [$_->start,$_->end, $_ ] }
        @{$features || []}
      ){
        my $hstrand  = $f->can('hstrand')  ? $f->hstrand : 1;
        my $fgroup_name = $self->feature_group( $f );
        my $s =$f->start;
        my $e =$f->end;
        my $db_name = $f->can('external_db_id') ? $extdbs->{$f->external_db_id}{'db_name'} : 'OLIGO';
        next if $strand_flag eq 'b' && $strand != ( ($hstrand||1)*$f->strand || -1 ) || $e < 1 || $s > $length ;
        push @{$id{$fgroup_name}}, [$s,$e,$f,int($s*$pix_per_bp),int($e*$pix_per_bp),$db_name];
      }
    }
## Now go through each feature in turn, drawing them
    my $y_pos;
    my $colour_key     = $self->colour_key( $feature_key );
    my $feature_colour = $self->my_colour( $self->my_config( 'sub_type' ), undef  );
    my $join_colour    = $self->my_colour( $self->my_config( 'sub_type' ), 'join' );

    my $regexp = $pix_per_bp > 0.1 ? '\dI' : ( $pix_per_bp > 0.01 ? '\d\dI' : '\d\d\dI' );

    next unless keys %id;
    foreach my $i ( sort {
      $id{$a}[0][3] <=> $id{$b}[0][3]  ||
      $id{$b}[-1][4] <=> $id{$a}[-1][4]
    } keys %id){
      my @F          = @{$id{$i}}; # sort { $a->[0] <=> $b->[0] } @{$id{$i}};
      my $START      = $F[0][0] < 1 ? 1 : $F[0][0];
      my $END        = $F[-1][1] > $length ? $length : $F[-1][1];
      my $db_name    = $F[0][5];
      my( $txt, $bit, $w, $th );
      my $bump_start = int($START * $pix_per_bp) - 1;
      my $bump_end   = int($END * $pix_per_bp);

      if( $self->{'show_labels'} ) {
        my $title = $self->feature_label( $F[0][2],$db_name );
        my( $txt, $bit, $tw,$th ) = $self->get_text_width( 0, $title, '', 'ptsize' => $fontsize, 'font' => $fontname );
        my $text_end = $bump_start + $tw + 1;
        $bump_end = $text_end if $text_end > $bump_end;
      }
      my $row        = $self->bump_row( $bump_start, $bump_end );
      if( $row > $dep ) {
        $features_bumped++;
        next;
      }
      $y_pos = $y_offset - $row * int( $h + $gap * $label_h ) * $strand;

      my $Composite = $self->Composite({
        'href'  => $self->href( $F[0][2] ),
        'x'     => $F[0][0]> 1 ? $F[0][0]-1 : 0,
        'width' => 0,
        'y'     => 0,
        'title' => $self->feature_title($F[0][2],$db_name)
      });
      my $X = -1e8;
      foreach my $f ( @F ){ ## Loop through each feature for this ID!
        my( $s, $e, $feat ) = @$f;
        next if int($e * $pix_per_bp) <= int( $X * $pix_per_bp );
        $features_drawn++;
        my $cigar;
        eval { $cigar = $feat->cigar_string; };
        if($DRAW_CIGAR || $cigar =~ /$regexp/ ) {
           my $START = $s < 1 ? 1 : $s;
           my $END   = $e > $length ? $length : $e;
           $X = $END;
           $Composite->push($self->Space({
             'x'          => $START-1,
             'y'          => 0, # $y_pos,
             'width'      => $END-$START+1,
             'height'     => $h,
             'absolutey'  => 1,
          }));
          $self->draw_cigar_feature($Composite, $feat, $h, $feature_colour, 'black', $pix_per_bp, $strand_flag eq 'r'  );
        } else {
          my $START = $s < 1 ? 1 : $s;
          my $END   = $e > $length ? $length : $e;
          $X = $END;
          $Composite->push($self->Rect({
            'x'          => $START-1,
            'y'          => 0, # $y_pos,
            'width'      => $END-$START+1,
            'height'     => $h,
            'colour'     => $feature_colour,
            'absolutey'  => 1,
          }));
        }
      }
      if( $h > 1 ) {
        $Composite->bordercolour($feature_colour);
      } else {
        $Composite->unshift( $self->Rect({
          'x'         => $Composite->{'x'},
          'y'         => $Composite->{'y'},
        	'width'     => $Composite->{'width'},
        	'height'    => $h,
        	'colour'    => $join_colour,
        	'absolutey' => 1
        }));
      }
      $Composite->y( $Composite->y + $y_pos );
      $self->push( $Composite );
      if( $self->{'show_labels'} ) {
        $self->push( $self->Text({
          'font'      => $fontname,
          'colour'    => $feature_colour,
          'height'    => $fontsize,
          'ptsize'    => $fontsize,
          'text'      => $self->feature_label($F[0][2],$db_name),
          'title'     => $self->feature_title($F[0][2],$db_name),
          'halign'    => 'left',
          'valign'    => 'center',
          'x'         => $Composite->{'x'},
          'y'         => $Composite->{'y'} + $h + 2,
          'width'     => $Composite->{'x'} + ($bump_end-$bump_start) / $pix_per_bp,
          'height'    => $label_h,
          'absolutey' => 1
        }));
      }
      if(exists $highlights{$i}) {
        $self->unshift( $self->Rect({
          'x'         => $Composite->{'x'} - 1/$pix_per_bp,
          'y'         => $Composite->{'y'} - 1,
          'width'     => $Composite->{'width'} + 2/$pix_per_bp,
          'height'    => $h + 2,
          'colour'    => 'highlight1',
          'absolutey' => 1,
        }));
      }
    }
    $y_offset -= $strand * ( ($self->_max_bump_row ) * ( $h + $gap + $label_h ) + 6 );
  }
  $self->errorTrack( "No features from '".$self->my_config('name')."' in this region" )
    unless( $features_drawn || $self->get_parameter( 'opt_empty_tracks')==0 );

  if( $self->get_parameter( 'opt_show_bumped') && $features_bumped ) {
    my $y_pos = $strand < 0
              ? $y_offset
              : 2 + $self->{'config'}->texthelper()->height($self->{'config'}->species_defs->ENSEMBL_STYLE->{'GRAPHIC_FONT'})
              ;
    $self->errorTrack( sprintf( q(%s features from '%s' omitted), $features_bumped, $self->my_config('name')), undef, $y_offset );
  }
  $self->timer_push( 'Features drawn' );
## No features show "empty track line" if option set....
}

sub render_ungrouped_labels {
  my $self = shift;
  $self->{'show_labels'} = 1;
  $self->render_ungrouped(@_);
}

sub render_ungrouped {
  my $self        = shift;
  my $strand      = $self->strand;
  my $strand_flag = $self->my_config('strand');

  my $length      = $self->{'container'}->length();
  my $pix_per_bp  = $self->scalex;
  my $DRAW_CIGAR  = ( $self->my_config('force_cigar') eq 'yes' )|| ($pix_per_bp > 0.2) ;
  my $h           = $self->my_config('height')||8;
  my $regexp = $pix_per_bp > 0.1 ? '\dI' : ( $pix_per_bp > 0.01 ? '\d\dI' : '\d\d\dI' );
  my $features_drawn = 0;
  my $X             = -1e8; ## used to optimize drawing!
  my %features = $self->features;

## Grab all the features;
## Remove those not on this display strand
## Create an array of arrayrefs [start,end,feature]
## Sort according to start of feature....

  my $y_offset = 0;

  my $label_h = 0;
  my( $fontname, $fontsize ) ;

  if( $self->{'show_labels'} ) {
    ( $fontname, $fontsize ) = $self->get_font_details( 'outertext' );
    my( $txt, $bit, $w,$th ) = $self->get_text_width( 0, 'X', '', 'ptsize' => $fontsize, 'font' => $fontname );
    $label_h = $th;
  }

  foreach my $feature_key ( $strand < 0 ? sort keys %features : reverse sort keys %features ) {
    my $flag = 0;
    $self->{'track_key'} = $feature_key;
    my $colour_key     = $self->colour_key( $feature_key );
    my $feature_colour = $self->my_colour( $self->my_config( 'sub_type' ), undef  );

    $self->_init_bump( undef, '0.5' );
    foreach my $f (
      sort { $a->[0] <=> $b->[0]      }
      map  { [$_->start, $_->end,$_ ] }
      grep { !($strand_flag eq 'b' && $strand != ( ( $_->can('hstrand') ? 1 : 1 ) * $_->strand||-1) || $_->start > $length || $_->end < 1) } 
      map  { @$_                      } @{$features{$feature_key}}
    ) {
      my($start,$end,$feat) = @$f;
      ($start,$end)         = ($end, $start) if $end<$start; # Flip start end YUK!
      $start                = 1 if $start < 1;
      $end                  = $length if $end > $length;
      ### This is where we now grab the colours
      next if( $end * $pix_per_bp ) == int( $X * $pix_per_bp );
      $X                    = $start;
      $features_drawn++;
      my $cigar;
      eval { $cigar = $feat->cigar_string; };
$flag++;
      if($DRAW_CIGAR || $cigar =~ /$regexp/ ) {
        $self->draw_cigar_feature( $self, $feat, $h, $feature_colour, 'black', $pix_per_bp, $strand_flag eq 'r' );
      } else {
        $self->push($self->Rect({
          'x'          => $X-1,
          'y'          => $y_offset, # $y_pos,
          'width'      => $end-$X+1,
          'height'     => $h,
          'colour'     => $feature_colour,
          'absolutey'  => 1,
        }));
      }
      if( $self->{'show_labels'} ) {
        my( $txt, $bit, $w, $th );
        my $bump_start = int($X * $pix_per_bp) - 1;
        my $title = $self->feature_label( $f->[2] );
        my( $txt, $bit, $tw,$th ) = $self->get_text_width( 0, $title, '', 'ptsize' => $fontsize, 'font' => $fontname );
        my $bump_end = $bump_start + $tw + 1;
        my $row        = $self->bump_row( $bump_start, $bump_end );
        if( $row < 0.5 ) {
          $self->push( $self->Text({
            'font'      => $fontname,
            'colour'    => $feature_colour,
            'height'    => $fontsize,
            'ptsize'    => $fontsize,
            'text'      => $title,
            'title'     => $title,
            'halign'    => 'left',
            'valign'    => 'center',
            'x'         => $X,
            'y'         => $y_offset + $h,
            'width'     => ($bump_end-$bump_start) / $pix_per_bp,
            'height'    => $label_h,
            'absolutey' => 1
          }));
        }
      }
    }
    $y_offset -= $strand * ($h+2);# + ( $self->{'show_labels'} ? $label_h+2 : 0 ) ) if $flag;
  }
  $self->errorTrack( "No ".$self->my_config('name')." features in this region" )
    unless( $features_drawn || $self->get_parameter( 'opt_empty_tracks')==0 );
}

sub render_text {
  my $self = shift;
  my $strand = $self->strand;
  my %features = $self->features;
  my $method = $self->can('export_feature') ? 'export_feature' : '_render_text';
  my $export;
  foreach my $feature_key ($strand < 0 ? sort keys %features : reverse sort keys %features) {
    foreach my $f (@{$features{$feature_key}}) {
      foreach (map { $_->[2] } sort { $a->[0] <=> $b->[0] } map { [ $_->start, $_->end, $_ ] } @{$f||[]}) {
        $export .= $self->$method($_, $self->my_config('caption'), { 'headers' => [ 'id' ], 'values' => [ $_->can('hseqname') ? $_->hseqname : $_->can('id') ? $_->id : '' ] });
      }
    }
  }
  return $export;
}

1;