<commit_before>package EnsEMBL::Web::Component::Tools::BlastAlignment;

use strict;
use warnings;
no warnings 'uninitialized';

use base qw(EnsEMBL::Web::Component::TextSequence EnsEMBL::Web::Component::Tools);

use Bio::EnsEMBL::Slice;
use Bio::EnsEMBL::CoordSystem;
use Bio::EnsEMBL::MappedSliceContainer;
use Bio::EnsEMBL::MappedSlice;
use Bio::EnsEMBL::Mapper;
use Bio::Seq;

sub _init {
  my $self = shift;
  my $hub = $self->hub;
  
  $self->cacheable(0);
  $self->ajaxable(1);
  
  $self->{'subslice_length'} = $hub->param('force') || 5000 * ($hub->param('display_width') || 60)
};

sub initialize {
  my ($self, $slice, $start, $end) = @_;
}

sub content {
  my $self = shift;
  my $object = $self->object;
  my $hub = $self->hub;
  my $species_defs = $hub->species_defs;
  my $ticket = $object->ticket;
  my $ticket_id = $ticket->ticket_id;
  my $hit_id = $hub->param('hit');
  my $result_id = $hub->param('res');
  my $species = $object->get_hit_species($result_id);
  my $genomic_hit = $object->fetch_blast_hit_by_id($result_id);
  my $blast_method = $object->get_blast_method;
  my $protein = $blast_method =~/[blastx]|[blastp]/i ? 1 : undef;

  my $html;

  my $config = {
    display_width   => $hub->param('display_width') || 60,
    species         => $species,
    comparison      => 1,
    blast_alignment => 1,
  };


  foreach ('exon_ori', 'match_display', 'snp_display', 'line_numbering', 'codons_display', 'title_display', 'exon_display'){
    $config->{$_} = $hub->param($_) unless $hub->param($_) eq 'off' || $hub->param($_) eq 'no';
  }

  $config->{'end_number'}      = $config->{'number'} = 1 if $config->{'line_numbering'};
  $config->{'exon_display'}    = 'selected' if $config->{'exon_ori'};
  $config->{'query_seq'}       = 'on';

  $config->{'slices'} = $self->get_alignment_slices($genomic_hit, $species, $config);

  my ($sequence, $markup) = $self->get_sequence_data($config->{'slices'}, $config);
  $self->markup_codons($sequence, $markup, $config)         if $config->{'codons_display'};
  $self->markup_exons($sequence, $markup, $config)          if $config->{'exon_display'};
  $self->markup_variation($sequence, $markup, $config)      if $config->{'snp_display'};
  $self->markup_comparisons($sequence, $markup, $config); # Always called in this view
  $self->markup_blast_line_numbers($sequence, $config)      if $config->{'line_numbering'};

  $html  .= sprintf('<div class="sequence_key">%s</div>', $self->get_key($config));
  $html .= $self->build_sequence($sequence, $config);
  return $html;
}

sub get_alignment_slices {
  my ($self, $hit, $species, $config) = @_;
  my $object = $self->object;
  my $result_id = $self->hub->param('res');
  my $homology_string;
  my $blast_method = $object->get_blast_method;
  my $protein = $blast_method =~/(blastx)|(blastp)/i ? 1 : undef;

  my $query_seq = $self->query_sequence($hit, $blast_method);
  my $hit_seq   = $query_seq;
  my $aln_summary = $hit->{'aln'};
  $aln_summary =~s/\s+//g;
  $homology_string = "|" x $hit->{'len'};

  # take into account alignments that do not start with a match
  $aln_summary = $aln_summary =~/^\d+/ ? $aln_summary : '0' .$aln_summary;

  if ($aln_summary =~/\D/){
    # process BTOP alignment to allow for gaps and missmatches
    $aln_summary =~ s/(\d+)/:$1:/g;
    $aln_summary =~ s/^:|:$//g;
    my @alignment_features = split (/:/, $aln_summary);
    my $index = 0;

    while ( scalar @alignment_features > 1){  
      my $seq_index = shift @alignment_features;  
      $index += $seq_index;
      my $edit_string = shift @alignment_features;
      my @edits = split (//, $edit_string);

      while (@edits){
        my $query_edit = shift @edits;
        my $hit_edit = shift @edits;
      
        my $length = $query_edit eq '-' ? 0 : 1;
        substr($query_seq, $index, $length) = $query_edit;
        substr($hit_seq, $index, $length) = $hit_edit;
        substr($homology_string, $index, 1) = ' ';
        $index++;
      }
    }
  }

 
  my $ref_slice = $object->get_hit_genomic_slice($hit, $species);
  my $target_object = $object->get_target_object($hit);
  my $mapping_orientation = $hit->{'gori'};
  if ($target_object){
    my $object_strand = $target_object->isa('Bio::EnsEMBL::Translation') ? $target_object->translation->start_Exon->strand :
                        $target_object->strand;
    $mapping_orientation = $hit->{'tori'} eq $object_strand ? 1 : -1; 
  }
 
  my $spacer = " " x (length($homology_string));

  my $query_slice = $self->create_slice($hit->{'qid'}, $hit->{'qstart'}, $hit->{'qori'}, $query_seq, $ref_slice);
  my $hit_slice   = $self->create_slice($hit->{'tid'}, $hit->{'tstart'}, $hit->{'tori'}, $hit_seq, $ref_slice);
  my @slices;

  if ($protein){
    @slices = (
      { name => 'Query', slice => $query_slice, no_markup => 1},
      { name => '', slice => $query_slice, seq => $homology_string, no_markup => 1, no_numbers => 1},
      { name => 'Subjct', slice => $hit_slice, },<commit_msg>fix bug with protein alignments<commit_after>package EnsEMBL::Web::Component::Tools::BlastAlignment;

use strict;
use warnings;
no warnings 'uninitialized';

use base qw(EnsEMBL::Web::Component::TextSequence EnsEMBL::Web::Component::Tools);

use Bio::EnsEMBL::Slice;
use Bio::EnsEMBL::CoordSystem;
use Bio::EnsEMBL::MappedSliceContainer;
use Bio::EnsEMBL::MappedSlice;
use Bio::EnsEMBL::Mapper;
use Bio::Seq;

sub _init {
  my $self = shift;
  my $hub = $self->hub;
  
  $self->cacheable(0);
  $self->ajaxable(1);
  
  $self->{'subslice_length'} = $hub->param('force') || 5000 * ($hub->param('display_width') || 60)
};

sub initialize {
  my ($self, $slice, $start, $end) = @_;
}

sub content {
  my $self = shift;
  my $object = $self->object;
  my $hub = $self->hub;
  my $species_defs = $hub->species_defs;
  my $ticket = $object->ticket;
  my $ticket_id = $ticket->ticket_id;
  my $hit_id = $hub->param('hit');
  my $result_id = $hub->param('res');
  my $species = $object->get_hit_species($result_id);
  my $genomic_hit = $object->fetch_blast_hit_by_id($result_id);
  my $blast_method = $object->get_blast_method;
  my $protein = $blast_method =~/[blastx]|[blastp]/i ? 1 : undef;

  my $html;

  my $config = {
    display_width   => $hub->param('display_width') || 60,
    species         => $species,
    comparison      => 1,
    blast_alignment => 1,
  };


  foreach ('exon_ori', 'match_display', 'snp_display', 'line_numbering', 'codons_display', 'title_display', 'exon_display'){
    $config->{$_} = $hub->param($_) unless $hub->param($_) eq 'off' || $hub->param($_) eq 'no';
  }

  $config->{'end_number'}      = $config->{'number'} = 1 if $config->{'line_numbering'};
  $config->{'exon_display'}    = 'selected' if $config->{'exon_ori'};
  $config->{'query_seq'}       = 'on';

  $config->{'slices'} = $self->get_alignment_slices($genomic_hit, $species, $config);

  my ($sequence, $markup) = $self->get_sequence_data($config->{'slices'}, $config);
  $self->markup_codons($sequence, $markup, $config)         if $config->{'codons_display'};
  $self->markup_exons($sequence, $markup, $config)          if $config->{'exon_display'};
  $self->markup_variation($sequence, $markup, $config)      if $config->{'snp_display'};
  $self->markup_comparisons($sequence, $markup, $config); # Always called in this view
  $self->markup_blast_line_numbers($sequence, $config)      if $config->{'line_numbering'};

  $html  .= sprintf('<div class="sequence_key">%s</div>', $self->get_key($config));
  $html .= $self->build_sequence($sequence, $config);
  return $html;
}

sub get_alignment_slices {
  my ($self, $hit, $species, $config) = @_;
  my $object = $self->object;
  my $result_id = $self->hub->param('res');
  my $homology_string;
  my $blast_method = $object->get_blast_method;
  my $protein = $blast_method =~/(blastx)|(blastp)/i ? 1 : undef;

  my $query_seq = $self->query_sequence($hit, $blast_method);
  my $hit_seq   = $query_seq;
  my $aln_summary = $hit->{'aln'};
  $aln_summary =~s/\s+//g;
  $homology_string = "|" x $hit->{'len'};

  # take into account alignments that do not start with a match
  $aln_summary = $aln_summary =~/^\d+/ ? $aln_summary : '0' .$aln_summary;

  if ($aln_summary =~/\D/){
    # process BTOP alignment to allow for gaps and missmatches
    $aln_summary =~ s/(\d+)/:$1:/g;
    $aln_summary =~ s/^:|:$//g;
    my @alignment_features = split (/:/, $aln_summary);
    my $index = 0;

    while ( scalar @alignment_features > 1){  
      my $seq_index = shift @alignment_features;  
      $index += $seq_index;
      my $edit_string = shift @alignment_features;
      my @edits = split (//, $edit_string);

      while (@edits){
        my $query_edit = shift @edits;
        my $hit_edit = shift @edits;
      
        my $length = $query_edit eq '-' ? 0 : 1;
        substr($query_seq, $index, $length) = $query_edit;
        substr($hit_seq, $index, $length) = $hit_edit;
        substr($homology_string, $index, 1) = ' ';
        $index++;
      }
    }
  }

 
  my $ref_slice = $object->get_hit_genomic_slice($hit, $species);
  my $target_object = $object->get_target_object($hit);
  my $mapping_orientation = $hit->{'gori'};
  if ($target_object){
    my $object_strand = $target_object->isa('Bio::EnsEMBL::Translation') ? $target_object->start_Exon->strand :
                        $target_object->strand;
    $mapping_orientation = $hit->{'tori'} eq $object_strand ? 1 : -1; 
  }
 
  my $spacer = " " x (length($homology_string));

  my $query_slice = $self->create_slice($hit->{'qid'}, $hit->{'qstart'}, $hit->{'qori'}, $query_seq, $ref_slice);
  my $hit_slice   = $self->create_slice($hit->{'tid'}, $hit->{'tstart'}, $hit->{'tori'}, $hit_seq, $ref_slice);
  my @slices;

  if ($protein){
    @slices = (
      { name => 'Query', slice => $query_slice, no_markup => 1},
      { name => '', slice => $query_slice, seq => $homology_string, no_markup => 1, no_numbers => 1},
      { name => 'Subjct', slice => $hit_slice, },
{'fraction_non_alphanumeric': 0.1978066203843445, 'fraction_numerical': 0.005433142167220043, 'mean_word_length': 3.9256689791873143, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 168, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5215333', 'n_tokens_mistral': 3834, 'n_tokens_neox': 3622, 'n_words': 732}