<commit_before>=head1 LICENSE

Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
Copyright [2016-2018] EMBL-European Bioinformatics Institute

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut

package EnsEMBL::Web::Component::Variation::Mappings;

use strict;

use base qw(EnsEMBL::Web::Component::Variation);
use Bio::EnsEMBL::Variation::Utils::VariationEffect qw(overlap);
use Bio::EnsEMBL::Utils::Sequence qw(reverse_comp);

sub _init {
  my $self = shift;
  $self->cacheable(0);
  $self->ajaxable(1);
  #$self->has_image(1);
}

sub content {
  my $self   = shift;
  my $hub    = $self->hub;
  my $object = $self->object;

  my %column_flags;

  # first check we have uniquely determined variation
  return $self->_info('A unique location can not be determined for this variant', $object->not_unique_location) if $object->not_unique_location;
  return $self->detail_panel if $hub->param('allele');
  
  my %mappings = %{$object->variation_feature_mapping($hub->param('recalculate'))};

  return [] unless keys %mappings;

  my $var_styles  = $hub->species_defs->colour('variation');
  my $colourmap   = $hub->colourmap;

  my $source      = $object->source;
  my $name        = $object->name;
  my $show_scores = $hub->param('show_scores');
  my $vf          = $hub->param('vf');
  my $html        = qq{<a id="}.$self->{'id'}.qq{_top"></a>};

  # get variation feature object
  my $vf_obj = $object->get_selected_variation_feature;
  return [] unless $vf_obj;

  my ($var_start,$var_end);
  $var_start = $vf_obj->seq_region_start <= $vf_obj->seq_region_end ? $vf_obj->seq_region_start : $vf_obj->seq_region_end;
  $var_end   = $vf_obj->seq_region_start <= $vf_obj->seq_region_end ? $vf_obj->seq_region_end : $vf_obj->seq_region_start;

  if ($object->Obj->failed_description =~ /match.+reference\ allele/) {
    my $feature_slice = $object->slice;
      
    $html .= $self->_warning(
      'Warning',
      '<p>Consequences for this variant have been calculated using the Ensembl reference allele' . (defined $feature_slice ? ' (' . $feature_slice->seq .')</p>' : '</p>'),
      '50%'
    );
  }

  # HGMD & COSMIC (SNPs only)
  if (($source eq 'HGMD-PUBLIC' && $name =~ /^CM/) || ($source eq 'COSMIC' && $var_start && $var_start == $var_end)) {

    my %source_labels = ( 'HGMD-PUBLIC' => 'public HGMD',
                          'COSMIC'      => 'COSMIC' );

    if($hub->param('recalculate')) {
      
      my $url = $hub->url({
        type   => 'Variation',
        action => 'Mappings',
        recalculate => undef,
      });
      
      my $link = "<a href='$url'>Revert to original display</a>";

      $html .= $self->_info(
        'Information',
        sprintf("<p>This display shows consequence predictions in the 'Type' column for all possible alleles (A/C/G/T) at this position. Ensembl has permission to display only the %s dataset which does not include alleles.<br/><br/>%s</p>", $source_labels{$source}, $link),
        '50%',
      ); 
    }
    
    else {
      my $url = $hub->url({
        type   => 'Variation',
        action => 'Mappings',
        recalculate => 1,
      });
      
      $html .= $self->_info(
        'Information',
        sprintf("Ensembl has permission to display only the %s dataset which does not include alleles.<br /><a href='%s'>Show consequence predictions</a> (e.g. amino acid changes) for all possible alleles based only on the variant location.", $source_labels{$source}, $url),
        '50%',
      );      
    }
  }
  
  my $trans_adaptor = $hub->get_adaptor('get_TranscriptAdaptor');
  my $max_length    = 20;
  my $flag;
  my @rows;
  
  # create a regfeat table as well
  my @reg_columns = (
    { key => 'rf',       title => 'Regulatory feature',     sort => 'html'                             },
    { key => 'cell_type',title => 'Active in cell lines',   sort => 'string'                           },
    { key => 'ftype',    title => 'Feature type',           sort => 'string'                           },
    { key => 'allele',   title => 'Allele',                 sort => 'string'                           },
    { key => 'type',     title => 'Consequence type',       sort => 'position_html'                    },
    { key => 'coverage', title => 'Variant position',       sort => 'string',                          },
  );
  my $reg_table = $self->new_table(\@reg_columns, [], { data_table => 1, sorting => ['type asc'], class => 'cellwrap_inside', data_table_config => {iDisplayLength => 10} } );
  my @motif_columns = (
    { key => 'mf',       width => '10%',  title => 'Motif feature',             sort => 'html'                             },
    { key => 'bm',       width => '10%',  title => 'Binding matrix',            sort => 'html'                             },
    { key => 'allele',   width => '10%',  title => 'Allele',                    sort => 'string'                           },
    { key => 'type',     width => '10%',  title => 'Consequence type',          sort => 'position_html'                    },
    { key => 'names',    width => '40%',  title => 'Transcription factors',     sort => 'string'                           },
    { key => 'pos',      width => '10%',  title => 'Motif position',            sort => 'numeric'                          },
    { key => 'high_inf', width => '5%',  title => 'High information position',  sort => 'string'                           },
    { key => 'score',    width => '5%',  title => 'Motif score change',         sort => 'position_html', align => 'center' },
  );
  my $motif_table = $self->new_table(\@motif_columns, [], { data_table => 1, sorting => ['type asc'], class => 'cellwrap_inside' } );

  my $selected_mapping = $object->selected_variation_feature_mapping($hub->param('recalculate'));

  foreach my $transcript_data (@{$selected_mapping->{'transcript_vari'} || []}) {

    # Transcript
    my $trans_name = $transcript_data->{'transcriptname'};
    my $trans      = $trans_adaptor->fetch_by_stable_id($trans_name);
    my $trans_type = '<b>biotype: </b>' . $trans->biotype;
    my $tva        = $transcript_data->{'tva'};
    my @tva_cons   = sort {$a->rank <=> $b->rank} (values %{{map {$_->label => $_} @{$tva->get_all_OverlapConsequences || []}}});
    my $tva_colour = (scalar @tva_cons > 0) ? $colourmap->hex_by_name($var_styles->{lc $tva_cons[0]->SO_term}->{'default'}) : undef; 
    # Gene
    my $gene       = $trans->get_Gene();
    my $gene_name  = $gene ? $gene->stable_id : '';
    my @entries    = grep $_->database eq 'HGNC', @{$gene->get_all_DBEntries};
    my $gene_hgnc  = scalar @entries ? '<b>HGNC: </b>' . $entries[0]->display_id : '';

    my ($gene_url, $transcript_url);
    
    # Create links to non-LRG genes and transcripts
    if ($trans_name !~ m/^LRG/) {
      $gene_url = $hub->url({
        type   => 'Gene',
        action => $self->gene_action,
        db     => 'core',
        r      => undef,
        g      => $gene_name,
        v      => $name,
        source => $source
      });
    
      $transcript_url = $hub->url({
        type   => 'Transcript',
        action => 'Variation_Transcript/Table',
        db     => 'core',
        r      => undef,
        t      => $trans_name,
        v      => $name,
        source => $source
      });
    } else {
      $gene_url = $hub->url({
        type     => 'LRG',
        action   => 'Variation_LRG',
        function => 'Table',
        db       => 'core',
        r        => undef,
        lrg      => $gene_name,
        v        => $name,
        source   => $source,
        __clear  => 1
      });
    
      $transcript_url = $hub->url({
        type     => 'LRG',
        action   => 'Variation_LRG',
        function => 'Table',
        db       => 'core',
        r        => undef,
        lrg      => $gene_name,
        lrgt     => $trans_name,
        v        => $name,
        source   => $source,
        __clear  => 1
      });
    }
    
    # HGVS
    my $hgvs;
    
    unless ($object->is_somatic_with_different_ref_base) {
      $hgvs  = $tva->hgvs_transcript          if defined $tva->hgvs_transcript;
      $hgvs .= '<br />' .  $tva->hgvs_protein if defined $tva->hgvs_protein;
    }

    # Now need to add to data to a row, and process rows somehow so that a gene ID is only displayed once, regardless of the number of transcripts;
    
    my $codon = $transcript_data->{'codon'} || '-';
    
    if ($codon ne '-') {
      $codon =~ s/([ACGT])/<b>$1<\/b>/g;
      $codon =~ tr/acgt/ACGT/;
    }
    
    my $strand = $trans->strand < 1 ? '-' : '+';

    # consequence type
    my $type = $self->render_consequence_type($tva);
    
    # sift
    my $sift = $self->render_sift_polyphen($tva->sift_prediction, $tva->sift_score);
    my $poly = $self->render_sift_polyphen($tva->polyphen_prediction, $tva->polyphen_score);

    my $cadd = $self->render_score_prediction($tva->cadd_prediction, $tva->cadd_score);
    my $dbnsfp_revel             = $self->render_score_prediction($tva->dbnsfp_revel_prediction, $tva->dbnsfp_revel_score);
    my $dbnsfp_meta_lr          = $self->render_score_prediction($tva->dbnsfp_meta_lr_prediction, $tva->dbnsfp_meta_lr_score);
    my $dbnsfp_mutation_assessor = $self->render_score_prediction($tva->dbnsfp_mutation_assessor_prediction, $tva->dbnsfp_mutation_assessor_score);

    
    # Allele
    my $a = $transcript_data->{'vf_allele'};
    if ($trans->stable_id =~ /^LRG_\d+/) {
      # LRG allele: reverse complement if LRG maps to the reverse strand of the assembly
      my $sa = $hub->get_adaptor('get_SliceAdaptor', 'core');
      my $slice = $sa->fetch_by_region( 'LRG', $trans->get_Gene()->stable_id);
      my $strand = $slice->feature_Slice->strand;
      if ($strand == -1 and $a =~ /^[ATGCN]+$/) {
        reverse_comp(\$a);
      }
    }
    my $allele = (length($a) > $max_length) ? substr($a,0,$max_length).'...' : $a;
 
    my $html_full_tr_allele;
    
    unless ($transcript_data->{'vf_allele'} =~ /HGMD|LARGE|DEL|INS/) {
      my $tr_allele_label = ($trans->stable_id =~ /^LRG_\d+/) ? $a : $transcript_data->{'tr_allele'};
      my $tr_allele = sprintf "(%s)",$tr_allele_label;
      $allele .= " <small>".$self->trim_large_string($tr_allele,'tr_'.$transcript_data->{transcriptname},sub {
        # trim to 20 but include the brackets
        local $_ = shift;
        return $_ if(length $_ < 20);
        s/^.//; s/.$//;
        return "(".substr($_,0,20)."...)";
      })."</small>";
    }

    # Variant position
    my $trans_length = $trans->length;

    my $cds_length = 0;
    foreach my $cds (@{$trans->get_all_CDS}){
      $cds_length += $cds->length;
    }

    my $pr_length = 0;
    my $translation = $trans->translation;
    $pr_length = $translation->length if ($translation);
    
    my $cdna_overlap = $self->_overlap_glyph(1, $trans_length, $transcript_data->{'cdna_start'}, $transcript_data->{'cdna_end'}, $trans, 'Transcript', 1, $tva_colour);
    my $cds_overlap  = $self->_overlap_glyph(1, $cds_length, $transcript_data->{'cds_start'}, $transcript_data->{'cds_end'}, $trans, 'CDS', 1, $tva_colour);
    my $pr_overlap   = $self->_overlap_glyph(1, $pr_length, $transcript_data->{'translation_start'}, $transcript_data->{'translation_end'}, $trans, 'Protein', 1, $tva_colour);

    my $trans_length_label = $self->_overlap_glyph_label($transcript_data->{'cdna_start'}, $transcript_data->{'cdna_end'}, $trans_length);
    my $cds_length_label   = $self->_overlap_glyph_label($transcript_data->{'cds_start'},  $transcript_data->{'cds_end'}, $cds_length);
    my $pr_length_label    = $self->_overlap_glyph_label($transcript_data->{'translation_start'}, $transcript_data->{'translation_end'}, $pr_length);
    my $trans_display      = $trans->version ? "$trans_name.".$trans->version : $trans_name;

    my $row = {
      allele    => $allele,
      gene      => qq{<a href="$gene_url">$gene_name</a><br/><span class="small" style="white-space:nowrap;">$gene_hgnc</span>},
      trans     => qq{<a href="$transcript_url" class="mobile-nolink">$trans_display</a> ($strand)<br/><span class="small" style="white-space:nowrap;">$trans_type</span>},
      type      => $type,
      trans_pos => $trans_length_label . $cdna_overlap,
      cds_pos   => $cds_length_label . $cds_overlap,
      prot_pos  => $pr_length_label . $pr_overlap,
      aa        => $transcript_data->{'pepallele'} || '-',
      codon     => $codon,
      sift      => $sift,
      polyphen  => $poly,
      cadd      => $cadd,
      dbnsfp_revel => $dbnsfp_revel,
      dbnsfp_meta_lr => $dbnsfp_meta_lr,
      dbnsfp_mutation_assessor => $dbnsfp_mutation_assessor,
      detail    => $self->ajax_add($self->ajax_url(undef, { t => $trans_name, vf => $vf, allele => $a, update_panel => 1 }).";single_transcript=variation_feature_variation=normal", "${trans_name}_${vf}_${a}"),
    };
    
    push(@rows, $row);

    # Column flags
    foreach my $col ('sift', 'polyphen', 'cadd', 'dbnsfp_revel', 'dbnsfp_meta_lr', 'dbnsfp_mutation_assessor') {
      $column_flags{$col} = 1 if ($row->{$col} && $row->{$col} ne '-');
    }

    $flag = 1;
  }
  
  my @columns = $self->table_columns(\%column_flags);
  my $table   = $self->new_table(\@columns, \@rows, { data_table => 1, sorting => [ 'type asc', 'trans asc', 'allele asc'], class => 'cellwrap_inside' });
  
  if($hub->database('regulation')) {
      
    ## Reg feats ##
    # reset allele string if recalculating for HGMD
    $vf_obj->allele_string('A/C/G/T') if $hub->param('recalculate');

    my $rfa = $hub->get_adaptor('get_RegulatoryFeatureAdaptor', 'funcgen');
    
    for my $rfv (@{ $vf_obj->get_all_RegulatoryFeatureVariations }) {
      next unless $rfv->regulatory_feature;

      my $rf_stable_id = $rfv->regulatory_feature->stable_id;
      my $rf = $rfa->fetch_by_stable_id($rf_stable_id);
       
      # create a URL
      my $url = $hub->url({
        type   => 'Regulation',
        action => 'Summary',
        rf     => $rfv->regulatory_feature->stable_id,
        fdb    => 'funcgen',
      });
      $url .= ';regulation_view=variation_feature_variation=normal';

      my $rfv_cons   = $rfv->most_severe_OverlapConsequence;
      my $rfv_colour = ($rfv_cons) ? $colourmap->hex_by_name($var_styles->{lc $rfv_cons->SO_term}->{'default'}) : undef;

      my $regulation_overlap = $self->_overlap_glyph($rf->seq_region_start, $rf->seq_region_end, $vf_obj->seq_region_start, $vf_obj->seq_region_end , $rf, 'Regulatory feature', 1, $rfv_colour);
      my $var_pos_start = $var_start - $rf->seq_region_start + 1;
      my $var_pos_end   = $var_end - $rf->seq_region_start + 1;
      my $reg_length = $rf->seq_region_end - $rf->seq_region_start + 1;

      my $reg_length_label = $self->_overlap_glyph_label($var_pos_start, $var_pos_end, $reg_length);

      for my $rfva (@{ $rfv->get_all_alternate_RegulatoryFeatureVariationAlleles }) {
        my $type = $self->render_consequence_type($rfva);

        my $r_allele = $self->trim_large_string($rfva->variation_feature_seq,'rfva_'.$rfv->regulatory_feature->stable_id,25);

        my $row = {
            rf        => sprintf('<a href="%s">%s</a>', $url, $rfv->regulatory_feature->stable_id),
            ftype     => $rf->feature_type->so_name,
            allele    => $r_allele,
            type      => $type || '-',
            coverage  => $reg_length_label.$regulation_overlap
        };

        my @epigenomes = @{$rf->get_epigenomes_by_activity('ACTIVE')||[]};
        my $epi_string = scalar @epigenomes 
                          ? join ', ', map { $_->name} @epigenomes 
                          : 'Not active in any cell lines';

        $row->{'cell_type'} = $epi_string;

        $reg_table->add_row($row);
        $flag = 1;
      } # end rfva loop
    } # end rfv loop
    
    ## Motif feats ##
    for my $mfv (@{ $vf_obj->get_all_MotifFeatureVariations }) {
      my $mf = $mfv->motif_feature;
      next unless $mf;       
      # check that the motif has a binding matrix, if not there's not 
      # much we can do so don't return anything
      my $matrix = $mf-get_BindingMatrix;
      next unless $matrix;
      
      my $matrix_names = join(', ',  @{$matrix->get_TranscriptionFactorComplex_names||[]});
      my $matrix_link = sprintf '<a href="#" class="_motif">%s</a>', $matrix->stable_id; 
      
      my $mfv_cons   = $mfv->most_severe_OverlapConsequence;<commit_msg>Fix typo in method call<commit_after>=head1 LICENSE

Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
Copyright [2016-2018] EMBL-European Bioinformatics Institute

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

=cut

package EnsEMBL::Web::Component::Variation::Mappings;

use strict;

use base qw(EnsEMBL::Web::Component::Variation);
use Bio::EnsEMBL::Variation::Utils::VariationEffect qw(overlap);
use Bio::EnsEMBL::Utils::Sequence qw(reverse_comp);

sub _init {
  my $self = shift;
  $self->cacheable(0);
  $self->ajaxable(1);
  #$self->has_image(1);
}

sub content {
  my $self   = shift;
  my $hub    = $self->hub;
  my $object = $self->object;

  my %column_flags;

  # first check we have uniquely determined variation
  return $self->_info('A unique location can not be determined for this variant', $object->not_unique_location) if $object->not_unique_location;
  return $self->detail_panel if $hub->param('allele');
  
  my %mappings = %{$object->variation_feature_mapping($hub->param('recalculate'))};

  return [] unless keys %mappings;

  my $var_styles  = $hub->species_defs->colour('variation');
  my $colourmap   = $hub->colourmap;

  my $source      = $object->source;
  my $name        = $object->name;
  my $show_scores = $hub->param('show_scores');
  my $vf          = $hub->param('vf');
  my $html        = qq{<a id="}.$self->{'id'}.qq{_top"></a>};

  # get variation feature object
  my $vf_obj = $object->get_selected_variation_feature;
  return [] unless $vf_obj;

  my ($var_start,$var_end);
  $var_start = $vf_obj->seq_region_start <= $vf_obj->seq_region_end ? $vf_obj->seq_region_start : $vf_obj->seq_region_end;
  $var_end   = $vf_obj->seq_region_start <= $vf_obj->seq_region_end ? $vf_obj->seq_region_end : $vf_obj->seq_region_start;

  if ($object->Obj->failed_description =~ /match.+reference\ allele/) {
    my $feature_slice = $object->slice;
      
    $html .= $self->_warning(
      'Warning',
      '<p>Consequences for this variant have been calculated using the Ensembl reference allele' . (defined $feature_slice ? ' (' . $feature_slice->seq .')</p>' : '</p>'),
      '50%'
    );
  }

  # HGMD & COSMIC (SNPs only)
  if (($source eq 'HGMD-PUBLIC' && $name =~ /^CM/) || ($source eq 'COSMIC' && $var_start && $var_start == $var_end)) {

    my %source_labels = ( 'HGMD-PUBLIC' => 'public HGMD',
                          'COSMIC'      => 'COSMIC' );

    if($hub->param('recalculate')) {
      
      my $url = $hub->url({
        type   => 'Variation',
        action => 'Mappings',
        recalculate => undef,
      });
      
      my $link = "<a href='$url'>Revert to original display</a>";

      $html .= $self->_info(
        'Information',
        sprintf("<p>This display shows consequence predictions in the 'Type' column for all possible alleles (A/C/G/T) at this position. Ensembl has permission to display only the %s dataset which does not include alleles.<br/><br/>%s</p>", $source_labels{$source}, $link),
        '50%',
      ); 
    }
    
    else {
      my $url = $hub->url({
        type   => 'Variation',
        action => 'Mappings',
        recalculate => 1,
      });
      
      $html .= $self->_info(
        'Information',
        sprintf("Ensembl has permission to display only the %s dataset which does not include alleles.<br /><a href='%s'>Show consequence predictions</a> (e.g. amino acid changes) for all possible alleles based only on the variant location.", $source_labels{$source}, $url),
        '50%',
      );      
    }
  }
  
  my $trans_adaptor = $hub->get_adaptor('get_TranscriptAdaptor');
  my $max_length    = 20;
  my $flag;
  my @rows;
  
  # create a regfeat table as well
  my @reg_columns = (
    { key => 'rf',       title => 'Regulatory feature',     sort => 'html'                             },
    { key => 'cell_type',title => 'Active in cell lines',   sort => 'string'                           },
    { key => 'ftype',    title => 'Feature type',           sort => 'string'                           },
    { key => 'allele',   title => 'Allele',                 sort => 'string'                           },
    { key => 'type',     title => 'Consequence type',       sort => 'position_html'                    },
    { key => 'coverage', title => 'Variant position',       sort => 'string',                          },
  );
  my $reg_table = $self->new_table(\@reg_columns, [], { data_table => 1, sorting => ['type asc'], class => 'cellwrap_inside', data_table_config => {iDisplayLength => 10} } );
  my @motif_columns = (
    { key => 'mf',       width => '10%',  title => 'Motif feature',             sort => 'html'                             },
    { key => 'bm',       width => '10%',  title => 'Binding matrix',            sort => 'html'                             },
    { key => 'allele',   width => '10%',  title => 'Allele',                    sort => 'string'                           },
    { key => 'type',     width => '10%',  title => 'Consequence type',          sort => 'position_html'                    },
    { key => 'names',    width => '40%',  title => 'Transcription factors',     sort => 'string'                           },
    { key => 'pos',      width => '10%',  title => 'Motif position',            sort => 'numeric'                          },
    { key => 'high_inf', width => '5%',  title => 'High information position',  sort => 'string'                           },
    { key => 'score',    width => '5%',  title => 'Motif score change',         sort => 'position_html', align => 'center' },
  );
  my $motif_table = $self->new_table(\@motif_columns, [], { data_table => 1, sorting => ['type asc'], class => 'cellwrap_inside' } );

  my $selected_mapping = $object->selected_variation_feature_mapping($hub->param('recalculate'));

  foreach my $transcript_data (@{$selected_mapping->{'transcript_vari'} || []}) {

    # Transcript
    my $trans_name = $transcript_data->{'transcriptname'};
    my $trans      = $trans_adaptor->fetch_by_stable_id($trans_name);
    my $trans_type = '<b>biotype: </b>' . $trans->biotype;
    my $tva        = $transcript_data->{'tva'};
    my @tva_cons   = sort {$a->rank <=> $b->rank} (values %{{map {$_->label => $_} @{$tva->get_all_OverlapConsequences || []}}});
    my $tva_colour = (scalar @tva_cons > 0) ? $colourmap->hex_by_name($var_styles->{lc $tva_cons[0]->SO_term}->{'default'}) : undef; 
    # Gene
    my $gene       = $trans->get_Gene();
    my $gene_name  = $gene ? $gene->stable_id : '';
    my @entries    = grep $_->database eq 'HGNC', @{$gene->get_all_DBEntries};
    my $gene_hgnc  = scalar @entries ? '<b>HGNC: </b>' . $entries[0]->display_id : '';

    my ($gene_url, $transcript_url);
    
    # Create links to non-LRG genes and transcripts
    if ($trans_name !~ m/^LRG/) {
      $gene_url = $hub->url({
        type   => 'Gene',
        action => $self->gene_action,
        db     => 'core',
        r      => undef,
        g      => $gene_name,
        v      => $name,
        source => $source
      });
    
      $transcript_url = $hub->url({
        type   => 'Transcript',
        action => 'Variation_Transcript/Table',
        db     => 'core',
        r      => undef,
        t      => $trans_name,
        v      => $name,
        source => $source
      });
    } else {
      $gene_url = $hub->url({
        type     => 'LRG',
        action   => 'Variation_LRG',
        function => 'Table',
        db       => 'core',
        r        => undef,
        lrg      => $gene_name,
        v        => $name,
        source   => $source,
        __clear  => 1
      });
    
      $transcript_url = $hub->url({
        type     => 'LRG',
        action   => 'Variation_LRG',
        function => 'Table',
        db       => 'core',
        r        => undef,
        lrg      => $gene_name,
        lrgt     => $trans_name,
        v        => $name,
        source   => $source,
        __clear  => 1
      });
    }
    
    # HGVS
    my $hgvs;
    
    unless ($object->is_somatic_with_different_ref_base) {
      $hgvs  = $tva->hgvs_transcript          if defined $tva->hgvs_transcript;
      $hgvs .= '<br />' .  $tva->hgvs_protein if defined $tva->hgvs_protein;
    }

    # Now need to add to data to a row, and process rows somehow so that a gene ID is only displayed once, regardless of the number of transcripts;
    
    my $codon = $transcript_data->{'codon'} || '-';
    
    if ($codon ne '-') {
      $codon =~ s/([ACGT])/<b>$1<\/b>/g;
      $codon =~ tr/acgt/ACGT/;
    }
    
    my $strand = $trans->strand < 1 ? '-' : '+';

    # consequence type
    my $type = $self->render_consequence_type($tva);
    
    # sift
    my $sift = $self->render_sift_polyphen($tva->sift_prediction, $tva->sift_score);
    my $poly = $self->render_sift_polyphen($tva->polyphen_prediction, $tva->polyphen_score);

    my $cadd = $self->render_score_prediction($tva->cadd_prediction, $tva->cadd_score);
    my $dbnsfp_revel             = $self->render_score_prediction($tva->dbnsfp_revel_prediction, $tva->dbnsfp_revel_score);
    my $dbnsfp_meta_lr          = $self->render_score_prediction($tva->dbnsfp_meta_lr_prediction, $tva->dbnsfp_meta_lr_score);
    my $dbnsfp_mutation_assessor = $self->render_score_prediction($tva->dbnsfp_mutation_assessor_prediction, $tva->dbnsfp_mutation_assessor_score);

    
    # Allele
    my $a = $transcript_data->{'vf_allele'};
    if ($trans->stable_id =~ /^LRG_\d+/) {
      # LRG allele: reverse complement if LRG maps to the reverse strand of the assembly
      my $sa = $hub->get_adaptor('get_SliceAdaptor', 'core');
      my $slice = $sa->fetch_by_region( 'LRG', $trans->get_Gene()->stable_id);
      my $strand = $slice->feature_Slice->strand;
      if ($strand == -1 and $a =~ /^[ATGCN]+$/) {
        reverse_comp(\$a);
      }
    }
    my $allele = (length($a) > $max_length) ? substr($a,0,$max_length).'...' : $a;
 
    my $html_full_tr_allele;
    
    unless ($transcript_data->{'vf_allele'} =~ /HGMD|LARGE|DEL|INS/) {
      my $tr_allele_label = ($trans->stable_id =~ /^LRG_\d+/) ? $a : $transcript_data->{'tr_allele'};
      my $tr_allele = sprintf "(%s)",$tr_allele_label;
      $allele .= " <small>".$self->trim_large_string($tr_allele,'tr_'.$transcript_data->{transcriptname},sub {
        # trim to 20 but include the brackets
        local $_ = shift;
        return $_ if(length $_ < 20);
        s/^.//; s/.$//;
        return "(".substr($_,0,20)."...)";
      })."</small>";
    }

    # Variant position
    my $trans_length = $trans->length;

    my $cds_length = 0;
    foreach my $cds (@{$trans->get_all_CDS}){
      $cds_length += $cds->length;
    }

    my $pr_length = 0;
    my $translation = $trans->translation;
    $pr_length = $translation->length if ($translation);
    
    my $cdna_overlap = $self->_overlap_glyph(1, $trans_length, $transcript_data->{'cdna_start'}, $transcript_data->{'cdna_end'}, $trans, 'Transcript', 1, $tva_colour);
    my $cds_overlap  = $self->_overlap_glyph(1, $cds_length, $transcript_data->{'cds_start'}, $transcript_data->{'cds_end'}, $trans, 'CDS', 1, $tva_colour);
    my $pr_overlap   = $self->_overlap_glyph(1, $pr_length, $transcript_data->{'translation_start'}, $transcript_data->{'translation_end'}, $trans, 'Protein', 1, $tva_colour);

    my $trans_length_label = $self->_overlap_glyph_label($transcript_data->{'cdna_start'}, $transcript_data->{'cdna_end'}, $trans_length);
    my $cds_length_label   = $self->_overlap_glyph_label($transcript_data->{'cds_start'},  $transcript_data->{'cds_end'}, $cds_length);
    my $pr_length_label    = $self->_overlap_glyph_label($transcript_data->{'translation_start'}, $transcript_data->{'translation_end'}, $pr_length);
    my $trans_display      = $trans->version ? "$trans_name.".$trans->version : $trans_name;

    my $row = {
      allele    => $allele,
      gene      => qq{<a href="$gene_url">$gene_name</a><br/><span class="small" style="white-space:nowrap;">$gene_hgnc</span>},
      trans     => qq{<a href="$transcript_url" class="mobile-nolink">$trans_display</a> ($strand)<br/><span class="small" style="white-space:nowrap;">$trans_type</span>},
      type      => $type,
      trans_pos => $trans_length_label . $cdna_overlap,
      cds_pos   => $cds_length_label . $cds_overlap,
      prot_pos  => $pr_length_label . $pr_overlap,
      aa        => $transcript_data->{'pepallele'} || '-',
      codon     => $codon,
      sift      => $sift,
      polyphen  => $poly,
      cadd      => $cadd,
      dbnsfp_revel => $dbnsfp_revel,
      dbnsfp_meta_lr => $dbnsfp_meta_lr,
      dbnsfp_mutation_assessor => $dbnsfp_mutation_assessor,
      detail    => $self->ajax_add($self->ajax_url(undef, { t => $trans_name, vf => $vf, allele => $a, update_panel => 1 }).";single_transcript=variation_feature_variation=normal", "${trans_name}_${vf}_${a}"),
    };
    
    push(@rows, $row);

    # Column flags
    foreach my $col ('sift', 'polyphen', 'cadd', 'dbnsfp_revel', 'dbnsfp_meta_lr', 'dbnsfp_mutation_assessor') {
      $column_flags{$col} = 1 if ($row->{$col} && $row->{$col} ne '-');
    }

    $flag = 1;
  }
  
  my @columns = $self->table_columns(\%column_flags);
  my $table   = $self->new_table(\@columns, \@rows, { data_table => 1, sorting => [ 'type asc', 'trans asc', 'allele asc'], class => 'cellwrap_inside' });
  
  if($hub->database('regulation')) {
      
    ## Reg feats ##
    # reset allele string if recalculating for HGMD
    $vf_obj->allele_string('A/C/G/T') if $hub->param('recalculate');

    my $rfa = $hub->get_adaptor('get_RegulatoryFeatureAdaptor', 'funcgen');
    
    for my $rfv (@{ $vf_obj->get_all_RegulatoryFeatureVariations }) {
      next unless $rfv->regulatory_feature;

      my $rf_stable_id = $rfv->regulatory_feature->stable_id;
      my $rf = $rfa->fetch_by_stable_id($rf_stable_id);
       
      # create a URL
      my $url = $hub->url({
        type   => 'Regulation',
        action => 'Summary',
        rf     => $rfv->regulatory_feature->stable_id,
        fdb    => 'funcgen',
      });
      $url .= ';regulation_view=variation_feature_variation=normal';

      my $rfv_cons   = $rfv->most_severe_OverlapConsequence;
      my $rfv_colour = ($rfv_cons) ? $colourmap->hex_by_name($var_styles->{lc $rfv_cons->SO_term}->{'default'}) : undef;

      my $regulation_overlap = $self->_overlap_glyph($rf->seq_region_start, $rf->seq_region_end, $vf_obj->seq_region_start, $vf_obj->seq_region_end , $rf, 'Regulatory feature', 1, $rfv_colour);
      my $var_pos_start = $var_start - $rf->seq_region_start + 1;
      my $var_pos_end   = $var_end - $rf->seq_region_start + 1;
      my $reg_length = $rf->seq_region_end - $rf->seq_region_start + 1;

      my $reg_length_label = $self->_overlap_glyph_label($var_pos_start, $var_pos_end, $reg_length);

      for my $rfva (@{ $rfv->get_all_alternate_RegulatoryFeatureVariationAlleles }) {
        my $type = $self->render_consequence_type($rfva);

        my $r_allele = $self->trim_large_string($rfva->variation_feature_seq,'rfva_'.$rfv->regulatory_feature->stable_id,25);

        my $row = {
            rf        => sprintf('<a href="%s">%s</a>', $url, $rfv->regulatory_feature->stable_id),
            ftype     => $rf->feature_type->so_name,
            allele    => $r_allele,
            type      => $type || '-',
            coverage  => $reg_length_label.$regulation_overlap
        };

        my @epigenomes = @{$rf->get_epigenomes_by_activity('ACTIVE')||[]};
        my $epi_string = scalar @epigenomes 
                          ? join ', ', map { $_->name} @epigenomes 
                          : 'Not active in any cell lines';

        $row->{'cell_type'} = $epi_string;

        $reg_table->add_row($row);
        $flag = 1;
      } # end rfva loop
    } # end rfv loop
    
    ## Motif feats ##
    for my $mfv (@{ $vf_obj->get_all_MotifFeatureVariations }) {
      my $mf = $mfv->motif_feature;
      next unless $mf;       
      # check that the motif has a binding matrix, if not there's not 
      # much we can do so don't return anything
      my $matrix = $mf->get_BindingMatrix;
      next unless $matrix;
      
      my $matrix_names = join(', ',  @{$matrix->get_TranscriptionFactorComplex_names||[]});
      my $matrix_link = sprintf '<a href="#" class="_motif">%s</a>', $matrix->stable_id; 
      
      my $mfv_cons   = $mfv->most_severe_OverlapConsequence;
{'fraction_non_alphanumeric': 0.16727369636670517, 'fraction_numerical': 0.005093127239347369, 'mean_word_length': 2.6593347058186154, 'pattern_counts': {'":': 0, '<': 87, '<?xml version=': 0, '>': 718, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '2007794', 'n_tokens_mistral': 11860, 'n_tokens_neox': 11272, 'n_words': 2395}