package Bio::EnsEMBL::GlyphSet::_alignment_multiple;

=head1 NAME

EnsEMBL::Web::GlyphSet::multiple_alignment;

=head1 SYNOPSIS

The multiple_alignment object handles the display of multiple alignment regions in contigview.

=head1 LICENCE

This code is distributed under an Apache style licence:
Please see http://www.ensembl.org/code_licence.html for details

=head1 CONTACT

Eugene Kulesha - ek@ebi.ac.uk
Fiona Cunningham - fc1@sanger.ac.uk

=cut

use strict;

use Sanger::Graphics::Bump;
use Bio::EnsEMBL::DnaDnaAlignFeature;

use Time::HiRes qw(time);

use base qw(Bio::EnsEMBL::GlyphSet_wiggle_and_block );

sub colour   { return $_[0]->{'feature_colour'}, $_[0]->{'label_colour'}, $_[0]->{'part_to_colour'}; }
sub draw_features {

  ### Called from {{ensembl-draw/modules/Bio/EnsEMBL/GlyphSet_wiggle_and_block.pm}}
  ### Arg 2 : draws wiggle plot if this is true
  ### Returns 0 if all goes well.  
  ### Returns error message to print if there are features missing (string)

  my( $self, $wiggle ) = @_;
  my $strand = $self->strand;
  my $strand_flag    = $self->my_config( 'strand' );
  my $drawn_block    = 0;
  my $caption        = $self->my_config('caption');
  my %highlights;      @highlights{$self->highlights()} = ();
  my $length         = $self->{'container'}->length;
  my $pix_per_bp     = $self->scalex;
  my $DRAW_CIGAR     = $pix_per_bp > 0.2 ;

  my $feature_type   = $self->my_config( 'constrained_element' ) ?  'element' : 'feature';

  my $feature_colour = $self->my_colour( $feature_type );
  my $feature_text   = $self->my_colour( $feature_type, 'text' );
  my $name           = $self->my_config('short_name') || $self->my_config('name');
     $feature_text   =~ s/\[\[name\]\]/$name/;
  my $h              = $self->get_parameter( 'opt_halfheight') ? 4 : 8;
  my $chr            = $self->{'container'}->seq_region_name;
  my $chr_start      = $self->{'container'}->start;
  my $other_species  = $self->my_config( 'species' );
  my $short_other    = $self->species_defs->ENSEMBL_SHORTEST_ALIAS->{ $other_species };
  my $self_species   = $self->species;
  my $short_self     = $self->species_defs->ENSEMBL_SHORTEST_ALIAS->{ $self_species };
  my $jump_to_alignslice = $self->my_config( 'jump_to_alignslice');
  my $METHOD_ID      = $self->my_config( 'method_link_species_set_id' );
  my $zmenu = {
      'type'   => 'Location',
      'action' => 'Compara_Alignments',
      'align'  => $METHOD_ID,
  };

  my $C = 0;
  my $X = -1e8;

  $self->timer_push('setup');
  unless( $wiggle eq 'wiggle' ) {
    my $els = $self->element_features;
    $self->timer_push('got features',undef,'fetch');
    my @T = 
      sort { $a->[0] <=> $b->[0] }
      map {
        ( $strand_flag ne 'b' || $strand == $_->{strand} ) && $_->{start} <= $length && $_->{end}>=1 ?
        [ $_->{start}, $_ ] : ()
      } @$els;
    $self->timer_push('sorted features');

    foreach (@T) {
      my($START,$f) = @$_;
      my $END       = $f->{end};
      ($START,$END) = ($END, $START) if $END<$START; # Flip start end YUK!
      my( $rs,$re ) = ($f->{hstart}, $f->{hend});
      $START        = 1 if $START < 1;
      $END          = $length if $END > $length;

      next if int( $END * $pix_per_bp ) == int( $X * $pix_per_bp );
      $drawn_block = 1;
      $X = $START;

      # Don't link to AlignSliceView from constrained elements! - doesn't work in 51
      if ($jump_to_alignslice) {
	$zmenu->{'align'}  => $METHOD_ID,
      }

      my $block_start = $rs;
      my $block_end   = $re;

      #use 'score' param to identify constrained elements track - 
      #in which case we show coordinates just for the block
      if ($self->my_config('constrained_element')) {
	  $zmenu->{'score'} = $f->{'score'};
	  $zmenu->{'ftype'} = "ConstrainedElement";
          $zmenu->{'id'} = $f->{'dbID'};
	  $block_start = $START+$chr_start-1;
	  $block_end   = $END  +$chr_start-1;
      } else {
	  my $class = $self->my_config( 'class' );
          $zmenu->{'ftype'} = "GenomicAlignBlock";
	  $zmenu->{'id'} = $f->{'dbID'};
          $zmenu->{'ref_id'} = $f->{'ref_id'} if ($f->{'ref_id'});
      }
      $zmenu->{'r'}     = "$chr:$block_start-$block_end";

      my $id = 10; 
      my $max_contig = 250000;

      if($DRAW_CIGAR) {
        my $TO_PUSH = $self->Composite({
          'href'  => $self->_url($zmenu),
          'x'     => $START-1,
          'width' => 0,
          'y'     => 0,
	  'bordercolour' => $feature_colour
        });
        $self->draw_cigar_feature( $TO_PUSH, $f, $h, $feature_colour, 'black', $pix_per_bp, 1 );
        $self->push( $TO_PUSH );
      } else {
        $self->push( $self->Rect({
          'x'         => $START-1,
          'y'         => 0,
          'width'     => $END-$START+1,
          'height'    => $h,
          'colour'    => $feature_colour,
          'absolutey' => 1,
          '_feature'  => $f, 
          'href'      => $self->_url($zmenu),
        }));
      }
    }
    $self->timer_push( 'drawn features' );
    $self->_offset($h);
    $self->draw_track_name($feature_text, $feature_colour) if $drawn_block;
  }
  my $drawn_wiggle = $wiggle ? $self->wiggle_plot : 1;
  return 0 if $drawn_block && $drawn_wiggle;

  # Work out error message if some data is missing
  my @errors = ();

  push @errors, $self->my_colour($feature_type,'text' ) if !$drawn_block;
  push @errors, $self->my_colour('score',      'text' ) if $wiggle && !$drawn_wiggle;
  return join ' and ',@errors;
}

## Now generate the feature array refs...

sub element_features {
  ### Retrieves block features for constrained elements
  ### Returns arrayref of features
  my $self = shift;

  my $slice = $self->{'container'};
  my $features;
  if ($slice->isa("Bio::EnsEMBL::Compara::AlignSlice::Slice")) {
    $features = $slice->get_all_constrained_elements();
  } else {
$self->timer_push('STARTING_API_CALL',5,'fetch');
    my $db   = $self->dbadaptor( 'multi', $self->my_config('db') );
## Get the Elements
    if ($self->my_config('constrained_element')) {
      $features = $db->get_adaptor("ConstrainedElement")->fetch_all_by_MethodLinkSpeciesSet_Slice(
        $db->get_adaptor("MethodLinkSpeciesSet")->fetch_by_dbID(
          $self->my_config('constrained_element')),
          $slice
        )||[];
    } else {
      $features = $db->get_adaptor("GenomicAlignBlock")->fetch_all_by_MethodLinkSpeciesSet_Slice(
        $db->get_adaptor("MethodLinkSpeciesSet")->fetch_by_dbID(
          $self->my_config('method_link_species_set_id')),
          $slice
        )||[];
    }
$self->timer_push('ENDING_API_CALL',5,'fetch');
  }

  my $T = [];
  foreach my $feature (@$features) {
    my $fragments;
if(0){
    my $all_gas = $feature->get_all_GenomicAligns;
    foreach (@$all_gas) {
      push(@{$fragments->{$_->dnafrag->genome_db->name}}, [
        $_->dnafrag->name,
        $_->dnafrag_start,
        $_->dnafrag_end,
        $_->dnafrag_strand
      ]);
    }
}
    my ($rtype, $gpath, $rname, $rstart, $rend, $rstrand) = split(':',$feature->slice->name);
    push @$T, Bio::EnsEMBL::DnaDnaAlignFeature->new_fast ({
      'dbID'      => $feature->{dbID},
      'ref_id'    => $feature->{reference_genomic_align_id},

      'seqname'   => $feature->slice->name,
      'start'     => $feature->start,
      'end'       => $feature->end,
      'strand'    => 0,

      'hseqname'  => $rname,
      'hstart'    => $rstart,
      'hend'      => $rend,
      'hstrand'   => $rstrand,

      'score'     => $feature->score,
      'fragments' => $fragments
    });
  }

  return $T;
}

sub score_features {
  my $self = shift;
  my $K  = $self->my_config('conservation_score');
  my $db = $self->dbadaptor( 'multi', $self->my_config('db') );
  return [] unless $K && $db;
  $self->timer_push( 'preped score fetch' );

  my $method_link_species_set = $db->get_MethodLinkSpeciesSetAdaptor->fetch_by_dbID($K);
  return [] unless $method_link_species_set;
  $self->timer_push( 'got mlss' );

  return $db->get_ConservationScoreAdaptor()->fetch_all_by_MethodLinkSpeciesSet_Slice(
    $method_link_species_set,
    $self->{'container'},
    $self->image_width  ## bins - size of track in pixels!
  ) || [];

}

sub wiggle_plot {

  ### Wiggle_plot
  ### Description: gets features for wiggle plot and passes to render_wiggle_plot
  ### Returns 1 if draws wiggles. Returns 0 if no wiggles drawn
  my $self = shift;

  $self->timer_push( 'score prefetch',undef,'draw');
  my $features = $self->score_features;
  $self->timer_push( 'got score features',undef,'fetch');
  return 0 unless scalar @$features;

  $self->draw_space_glyph();
  my $min_score = 0;
  my $max_score = 0;
  foreach (@$features) {
    my $s = $_->score;
    $min_score = $s if $s < $min_score;
    $max_score = $s if $s > $max_score;
  }
  $self->draw_wiggle_plot(
    $features,                      ## Features array
    { 'min_score' => $min_score, 'max_score' => $max_score }
  );
  return 1;
  $self->timer_push( 'wiggle drawn');
}

sub export_feature {
  my $self = shift;
  my ($feature, $feature_type, $extra, $default) = @_;
  my $species = $self->species;
  my $sp = $self->species_defs->multi_hash->{'DATABASE_COMPARA'}{'ALIGNMENTS'}{$self->my_config('method_link_species_set_id')}{'species'};

  return $self->_render_text($feature, $feature_type, $extra, $default);
}

1;