static char rcsid[] = "$Id: d5601f421568d795eb2b24cda81099a97a2dbdbf $";
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef HAVE_MEMCPY
#define memcpy(d,s,n) bcopy((s),(d),(n))
#endif

#include "transcriptome-search.h"

#include "assert.h"
#include "trpath.h"
#include "trpath-solve.h"

#include "path.h"
#include "path-eval.h"

#include "mem.h"
#include "types.h"
#include "chrnum.h"
#include "reader.h"
#include "oligo.h"

#ifdef LARGE_GENOMES
#include "intersect-large.h"
#endif
#include "intersect-simd.h"	/* For Intersect_exact */
#include "intersect-approx-simd.h" /* For Intersect_approx */

#ifndef LARGE_GENOMES
#include "merge-diagonals-simd-uint4.h"
#elif !defined(HAVE_AVX512) && !defined(HAVE_AVX2)
#include "merge-diagonals-heap.h" /* For Merge_diagonals_large */
#include "merge-diagonals-simd-uint4.h"
#else
#include "merge-diagonals-simd-uint8.h" /* For Merge_diagonals_large */
#include "merge-diagonals-simd-uint4.h"
#endif

#include "transcript.h"
#include "junction.h"
#include "genomebits_count.h"
#include "genomebits_kmer.h"
#include "spliceends.h"


/* Merging faster than count table */
#define USE_MERGE 1
#define SUBOPT 3


#ifdef DEBUG
#define debug(x) x
#else
#define debug(x)
#endif

/* Processing merged diagonals */
#ifdef DEBUG0
#define debug0(x) x
#else
#define debug0(x)
#endif

/* Exon and path overlap */
#ifdef DEBUG1
#define debug1(x) x
#else
#define debug1(x)
#endif

/* Searching complete */
#ifdef DEBUG2
#define debug2(x) x
#else
#define debug2(x)
#endif

/* Transcriptome alignment details*/
#ifdef DEBUG2A
#define debug2a(x) x
#else
#define debug2a(x)
#endif

/* Transcriptome_search_exact */
#ifdef DEBUG3
#define debug3(x) x
#else
#define debug3(x)
#endif

/* Transcriptome_search_approx */
#ifdef DEBUG4
#define debug4(x) x
#else
#define debug4(x)
#endif

/* convert_to_path */
#ifdef DEBUG9
#define debug9(x) x
#else
#define debug9(x)
#endif


static int index1interval_tr;
static int index1part_tr;

static Indexdb_T tr_indexdb;

static Transcriptome_T transcriptome;
static EF64_T transcript_ef64;

static Genomebits_T genomebits;
static Genomebits_T genomebits_alt;
static Genomebits_T transcriptomebits;

static int leftreadshift_tr;
static Oligospace_T oligobase_mask_tr;


/* Overwrite values array */
/* Repetitive oligos can calse false indel diagonals */
static int
most_prevalent_trcoord (int *nloci, Trcoord_T *values, int nvalues) {
  int max_count, count;
  Trcoord_T *out, *ptr, *end, *first;

  assert(nvalues > 0);

  ptr = out = &(values[0]);	/* Reset */
  end = &(values[nvalues]);

  max_count = 1;
  while (ptr < end) {
    first = ptr;
    debug0(printf("DIAGONAL %u",*first));
    if (ptr + max_count - 1 >= end) {
      /* End of list fails */
      debug0(printf(" => Goes beyond end of list\n"));
      ptr = end;

    } else if (ptr[max_count - 1] != *first) {
      /* Fails */
      debug0(printf(" => Fails\n"));
      if (ptr[max_count - 1] != ptr[max_count - 2]) {
	/* Can jump immediately */
	ptr += max_count - 1;
      } else {
	/* Advance forward until we see a new value */
	while (ptr < end && *ptr == *first) {
	  ptr++;
	}
      }

    } else {
      /* Contender */
      ptr += max_count;
      while (ptr < end && *ptr == *first) {
	ptr++;
      }
      debug0(printf(" => Count %d, index %d => printing\n",ptr - first,first - values));
      if ((count = ptr - first) > max_count) {
	out = &(values[0]);	/* Reset */
	max_count = count;
      }
      *out++ = *first;
    }
  }

  *nloci = out - &(values[0]);
  return max_count;
}


#define T Trpath_T


/* Expecting transcriptome to not be a large genome */
/* Use oligos computed by Stage1_fill_all_oligos_tr */
/* Assigns own positions, so does not need a procedure for Stage1_fill_all_positions_tr */
void
Transcriptome_search_complete (int *found_score, bool *found_transcriptp,

			       List_T *sense_trpaths, List_T *antisense_trpaths,

			       Stage1_T stage1, int querylength, Indelinfo_T indelinfo,

			       Mergeinfo_uint4_T mergeinfo,
			       Trcoord_T **tplus_stream_array, int *tplus_streamsize_array, int *tplus_diagterm_array,
			       Trcoord_T **tminus_stream_array, int *tminus_streamsize_array, int *tminus_diagterm_array,
			       int *mismatch_positions_alloc, Compress_T query_compress_fwd, Compress_T query_compress_rev,
			       int max_insertionlen, int max_deletionlen,
			       Intlistpool_T intlistpool, Uintlistpool_T uintlistpool,
			       Listpool_T listpool, Trpathpool_T trpathpool, Pathpool_T pathpool,
			       Hitlistpool_T hitlistpool, Method_T method) {
  Trpath_T trpath;

  int max_tplus_count, max_tminus_count;

  Trcoord_T trdiagonal;
  Trcoord_T *tplus_diagonals, *tminus_diagonals;
  int n_tplus_loci, n_tminus_loci, n_tplus_diagonals, n_tminus_diagonals,
    total_ndiagonals_tplus = 0, total_ndiagonals_tminus = 0, i;
  
  Trcoord_T *positions;
  int npositions;
  int tplus_streami = 0, tminus_streami = 0;

  int querypos, query_lastpos;

  Trnum_T trnum;
  Trcoord_T troffset, trhigh;


  query_lastpos = querylength - index1part_tr;
  for (querypos = 0; querypos <= query_lastpos; querypos++) {
    if (stage1->tr_validp[querypos] == false) {
      /* Skip */
    } else {
      if (stage1->tr_plus_retrievedp[querypos] == true) {
	positions = stage1->tr_plus_positions[querypos];
	npositions = stage1->tr_plus_npositions[querypos];
      } else {
	npositions = stage1->tr_plus_npositions[querypos] =
	  Indexdb_ptr(&stage1->tr_plus_positions[querypos],tr_indexdb,stage1->tr_forward_oligos[querypos]);
	positions = stage1->tr_plus_positions[querypos];
	stage1->tr_plus_retrievedp[querypos] = true;
      }
      if (npositions > 0) {
	tplus_stream_array[tplus_streami] = positions;
	tplus_streamsize_array[tplus_streami] = npositions;
	tplus_diagterm_array[tplus_streami] = querylength - querypos;
	total_ndiagonals_tplus += npositions;
	tplus_streami++;
      }

      if (stage1->tr_minus_retrievedp[querypos] == true) {
	positions = stage1->tr_minus_positions[querypos];
	npositions = stage1->tr_minus_npositions[querypos];
      } else {
	npositions = stage1->tr_minus_npositions[querypos] =
	  Indexdb_ptr(&stage1->tr_minus_positions[querypos],tr_indexdb,stage1->tr_revcomp_oligos[querypos]);
	positions = stage1->tr_minus_positions[querypos];
	stage1->tr_minus_retrievedp[querypos] = true;
      }
      if (npositions > 0) {
	tminus_stream_array[tminus_streami] = positions;
	tminus_streamsize_array[tminus_streami] = npositions;
	tminus_diagterm_array[tminus_streami] = querypos + index1part_tr;
	total_ndiagonals_tminus += npositions;
	tminus_streami++;
      }
    }
  }


  tplus_diagonals = Merge_diagonals(&n_tplus_diagonals,tplus_stream_array,
				    tplus_streamsize_array,tplus_diagterm_array,/*nstreams*/tplus_streami,
				    mergeinfo);

  if (n_tplus_diagonals == 0) {
    max_tplus_count = 0;
    n_tplus_loci = 0;
  } else {
    max_tplus_count = most_prevalent_trcoord(&n_tplus_loci,tplus_diagonals,n_tplus_diagonals);
  }

#ifdef DEBUG2
  printf("max_tplus_count: %d\n",max_tplus_count);
  for (i = 0; i < n_tplus_loci; i++) {
    printf("PLUS_LOCUS %u\n",tplus_diagonals[i]);
  }
#endif

  tminus_diagonals = Merge_diagonals(&n_tminus_diagonals,tminus_stream_array,
				     tminus_streamsize_array,tminus_diagterm_array,/*nstreams*/tminus_streami,
				     mergeinfo);

  if (n_tminus_diagonals == 0) {
    max_tminus_count = 0;
    n_tminus_loci = 0;
  } else {
    max_tminus_count = most_prevalent_trcoord(&n_tminus_loci,tminus_diagonals,n_tminus_diagonals);
  }


#ifdef DEBUG2
  printf("max_tminus_count: %d\n",max_tminus_count);
  for (i = 0; i < n_tminus_loci; i++) {
    printf("MINUS_LOCUS %u\n",tminus_diagonals[i]);
  }
#endif

  /* tplusp == true */
  if (max_tplus_count < (querylength - index1part_tr)/5 &&
      max_tplus_count < max_tminus_count - SUBOPT) {
    /* Not enough kmers match or less than minus */
    debug2(printf("Not enough tplus kmers match (%d)\n",max_tplus_count));

  } else {
    for (i = 0; i < n_tplus_loci; i++) {
      trdiagonal = tplus_diagonals[i];
      if (trdiagonal /*+qstart:0*/ < (Trcoord_T) querylength) {
	/* Skip */
      } else {
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonal - querylength,trdiagonal);
	if ((trpath = Trpath_solve_from_diagonals(&(*found_score),&(*found_transcriptp),trdiagonal,
						  /*middle_trdiagonal_qstart*/0,/*middle_trdiagonal_qend*/querylength,
						  /*middle_nmismatches*/0,/*qstart_trdiag*/NULL,/*qend_trdiag*/NULL,
						  /*tplusp*/true,querylength,/*query_compress_tr*/query_compress_fwd,
						  mismatch_positions_alloc,trnum,troffset,trhigh,
						  /*want_lowest_coordinate_p*/false,
						  indelinfo,max_insertionlen,max_deletionlen,
						  intlistpool,uintlistpool,listpool,
						  trpathpool,pathpool,method)) != NULL) {
	  *sense_trpaths = Hitlist_push(*sense_trpaths,hitlistpool,(void *) trpath
					hitlistpool_trace(__FILE__,__LINE__));
	}
      }
    }

    debug2(printf("tplus loci %d\n",n_tplus_loci));
  }
#if !defined(LARGE_GENOMES) || defined(HAVE_AVX512) || defined(HAVE_AVX2)
  FREE_ALIGN(tplus_diagonals);
#else
  FREE(tplus_diagonals);
#endif


  /* tplusp == false */
  if (max_tminus_count < (querylength - index1part_tr)/5 &&
      max_tminus_count < max_tplus_count - SUBOPT) {
    /* Not enough kmers match or less than plus */
    debug2(printf("Not enough tminus kmers match (%d)\n",max_tminus_count));

  } else {
    for (i = 0; i < n_tminus_loci; i++) {
      trdiagonal = tminus_diagonals[i];
      if (trdiagonal /*+qstart:0*/ < (Trcoord_T) querylength) {
	/* Skip */
      } else {
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonal - querylength,trdiagonal);
	if ((trpath = Trpath_solve_from_diagonals(&(*found_score),&(*found_transcriptp),trdiagonal,
						  /*middle_trdiagonal_qstart*/0,/*middle_trdiagonal_qend*/querylength,
						  /*middle_nmismatches*/0,/*qstart_trdiag*/NULL,/*qend_trdiag*/NULL,
						  /*tplusp*/false,querylength,/*query_compress_tr*/query_compress_rev,
						  mismatch_positions_alloc,trnum,troffset,trhigh,
						  /*want_lowest_coordinate_p*/false,
						  indelinfo,max_insertionlen,max_deletionlen,
						  intlistpool,uintlistpool,listpool,
						  trpathpool,pathpool,method)) != NULL) {
	  *antisense_trpaths = Hitlist_push(*antisense_trpaths,hitlistpool,(void *) trpath
					    hitlistpool_trace(__FILE__,__LINE__));
	}
      }
    }

    debug2(printf("tminus loci %d\n",n_tminus_loci));
  }

#if !defined(LARGE_GENOMES) || defined(HAVE_AVX512) || defined(HAVE_AVX2)
  FREE_ALIGN(tminus_diagonals);
#else
  FREE(tminus_diagonals);
#endif

  return;
}


void
Transcriptome_search_exact (int *found_score, bool *found_transcriptp,

			    List_T *sense_trpaths, List_T *antisense_trpaths,
				  
			    Stage1_T stage1, int querylength,

			    Compress_T query_compress_fwd, Compress_T query_compress_rev,
			    Intlistpool_T intlistpool, Uintlistpool_T uintlistpool,
			    Trpathpool_T trpathpool, Hitlistpool_T hitlistpool, Method_T method) {
  Trpath_T trpath;
  
  Trcoord_T *tplus_positions_end5 = NULL, *tminus_positions_end5 = NULL,
    *tplus_positions_end3 = NULL, *tminus_positions_end3 = NULL;
  int n_tplus_positions_end5 = 0, n_tminus_positions_end5 = 0,
    n_tplus_positions_end3 = 0, n_tminus_positions_end3 = 0;
  int tplus_diagterm_end5, tminus_diagterm_end5, tplus_diagterm_end3, tminus_diagterm_end3;

  Trcoord_T trdiagonal;
  Trcoord_T *tplus_trdiagonals, *tminus_trdiagonals;
  int n_tplus_trdiagonals, n_tminus_trdiagonals, i;

  int query_lastpos;

  Trnum_T trnum;
  Trcoord_T troffset, trhigh;

  int nmismatches, ref_nmismatches;


#if 0
  *tplus_positions_5 = *tminus_positions_5 = *tplus_positions_3 = *tminus_positions_3 = (Trcoord_T *) NULL;
  *n_tplus_positions_5 = *n_tminus_positions_5 = *n_tplus_positions_3 = *n_tminus_positions_3 = 0;
#endif
			
  debug3(printf("\n\n***Transcriptome_search_exact\n"));

  query_lastpos = querylength - index1part_tr;
  if (stage1->tr_validp[0] == false || stage1->tr_validp[query_lastpos] == false) {
    return;
  } else {
    tplus_positions_end5 = stage1->tr_plus_positions[0];
    n_tplus_positions_end5 = stage1->tr_plus_npositions[0];
    tplus_diagterm_end5 = querylength /* - 0, querypos */;

    tminus_positions_end5 = stage1->tr_minus_positions[0];
    n_tminus_positions_end5 = stage1->tr_minus_npositions[0];
    tminus_diagterm_end5 = /* 0, querypos + */ index1part_tr;

    tplus_positions_end3 = stage1->tr_plus_positions[query_lastpos];
    n_tplus_positions_end3 = stage1->tr_plus_npositions[query_lastpos];
    tplus_diagterm_end3 = index1part_tr /* querylength - querypos */;

    tminus_positions_end3 = stage1->tr_minus_positions[query_lastpos];
    n_tminus_positions_end3 = stage1->tr_minus_npositions[query_lastpos];
    tminus_diagterm_end3 = querylength /* querypos + index1part_tr */;
  }

  tplus_trdiagonals = Intersect_exact(&n_tplus_trdiagonals,
				      tplus_positions_end5,n_tplus_positions_end5,tplus_diagterm_end5,
				      tplus_positions_end3,n_tplus_positions_end3,tplus_diagterm_end3);
  tminus_trdiagonals = Intersect_exact(&n_tminus_trdiagonals,
				       tminus_positions_end5,n_tminus_positions_end5,tminus_diagterm_end5,
				       tminus_positions_end3,n_tminus_positions_end3,tminus_diagterm_end3);

  debug3(printf("***Transcriptome exact: %d plus and %d minus trdiagonals\n",
		n_tplus_trdiagonals,n_tminus_trdiagonals));
	 
  for (i = 0; i < n_tplus_trdiagonals; i++) {
    trdiagonal = tplus_trdiagonals[i];
    debug3(printf("tplus trdiagonal: %u\n",trdiagonal));
    if (trdiagonal /*+qtart:0*/ < (Trcoord_T) querylength) {
      /* Skip */
    } else {
      trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonal - querylength,trdiagonal);
      nmismatches = Genomebits_count_mismatches_substring(&ref_nmismatches,transcriptomebits,/*ome_alt*/NULL,
							  /*query_compress_tr*/query_compress_fwd,
							  /*univdiagonal*/(Univcoord_T) trdiagonal,querylength,
							  /*pos5*/0,/*pos3*/querylength,/*tplusp*/true,/*genestrand*/0);
      trpath = Trpath_new_exact(trdiagonal,/*tstart*/0,/*tend*/querylength,
				nmismatches,/*tplusp*/true,trnum,troffset,trhigh,
				intlistpool,uintlistpool,trpathpool,
				/*found_score*/nmismatches,method);

      if (trpath->found_score < *found_score) {
	*found_score = trpath->found_score;
      }
      *found_transcriptp = true;
      *sense_trpaths = Hitlist_push(*sense_trpaths,hitlistpool,(void *) trpath
				    hitlistpool_trace(__FILE__,__LINE__));
    }
  }
  /* Intersect procedures can allocate memory even if n_trdiagonals == 0 */
  FREE(tplus_trdiagonals);
    

  for (i = 0; i < n_tminus_trdiagonals; i++) {
    trdiagonal = tminus_trdiagonals[i];
    debug3(printf("tminus trdiagonal: %u\n",trdiagonal));
    if (trdiagonal /*+qstart:0*/ < (Trcoord_T) querylength) {
      /* Skip */
    } else {
      trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonal - querylength,trdiagonal);
      nmismatches = Genomebits_count_mismatches_substring(&ref_nmismatches,transcriptomebits,/*ome_alt*/NULL,
							  /*query_compress_tr*/query_compress_rev,
							  /*univdiagonal*/(Univcoord_T) trdiagonal,querylength,
							  /*pos5*/0,/*pos3*/querylength,/*tplusp*/false,/*genestrand*/0);
      trpath = Trpath_new_exact(trdiagonal,/*tstart*/0,/*tend*/querylength,
				nmismatches,/*tplusp*/false,trnum,troffset,trhigh,
				intlistpool,uintlistpool,trpathpool,
				/*found_score*/nmismatches,method);
      if (trpath->found_score < *found_score) {
	*found_score = trpath->found_score;
      }
      *found_transcriptp = true;
      *antisense_trpaths = Hitlist_push(*antisense_trpaths,hitlistpool,(void *) trpath
					hitlistpool_trace(__FILE__,__LINE__));
    }
  }
  /* Intersect procedures can allocate memory even if n_trdiagonals == 0 */
  FREE(tminus_trdiagonals);

  return;
}


/* Intersect_approx does not seem to reduce speed and can find some
   alignments that Intersect_exact cannot.  However, this was before
   we implemented a SIMD version of Intersect_exact. */
void
Transcriptome_search_approx (int *found_score, bool *found_transcriptp,

			     List_T *sense_trpaths, List_T *antisense_trpaths,
				  
			     Stage1_T stage1, int querylength,

			     Compress_T query_compress_fwd, Compress_T query_compress_rev,
			     int max_insertionlen, int max_deletionlen,
			     Intlistpool_T intlistpool, Uintlistpool_T uintlistpool,
			     Listpool_T listpool, Trpathpool_T trpathpool, Pathpool_T pathpool,
			     Hitlistpool_T hitlistpool, Method_T method) {
  Trpath_T trpath;
  
  Trcoord_T *tplus_positions_end5 = NULL, *tminus_positions_end5 = NULL,
    *tplus_positions_end3 = NULL, *tminus_positions_end3 = NULL;
  int n_tplus_positions_end5 = 0, n_tminus_positions_end5 = 0,
    n_tplus_positions_end3 = 0, n_tminus_positions_end3 = 0;
  int tplus_diagterm_end5, tminus_diagterm_end5, tplus_diagterm_end3, tminus_diagterm_end3;

  Trcoord_T trdiagonala, trdiagonalb;
  Trcoord_T min_distance, distance;

  Trcoord_T *tplus_diagpairs, *tminus_diagpairs;
  int n_tplus_diagpairs, n_tminus_diagpairs, k, j;
#ifdef INCLUDE_EXACT
  bool tplus_exactp, tminus_exactp;
#endif
  int pos5a, pos3a, pos5b, pos3b;
  int nmismatches_a5, nmismatches_a3, nmismatches_b5, nmismatches_b3;

  int query_lastpos;

  Trnum_T trnum;
  Trcoord_T troffset, trhigh;


#if 0
  *tplus_positions_5 = *tminus_positions_5 = *tplus_positions_3 = *tminus_positions_3 = (Trcoord_T *) NULL;
  *n_tplus_positions_5 = *n_tminus_positions_5 = *n_tplus_positions_3 = *n_tminus_positions_3 = 0;
#endif
			
  debug4(printf("\n\n***Transcriptome_search_approx\n"));

  /* Stage1_dump_tr(stage1,querylength); */

  query_lastpos = querylength - index1part_tr;
  if (stage1->tr_validp[0] == false || stage1->tr_validp[query_lastpos] == false) {
    return;
  } else {
    tplus_positions_end5 = stage1->tr_plus_positions[0];
    n_tplus_positions_end5 = stage1->tr_plus_npositions[0];
    tplus_diagterm_end5 = querylength /* - 0, querypos */;

    tminus_positions_end5 = stage1->tr_minus_positions[0];
    n_tminus_positions_end5 = stage1->tr_minus_npositions[0];
    tminus_diagterm_end5 = /* 0, querypos + */ index1part_tr;

    tplus_positions_end3 = stage1->tr_plus_positions[query_lastpos];
    n_tplus_positions_end3 = stage1->tr_plus_npositions[query_lastpos];
    tplus_diagterm_end3 = index1part_tr /* querylength - querypos */;

    tminus_positions_end3 = stage1->tr_minus_positions[query_lastpos];
    n_tminus_positions_end3 = stage1->tr_minus_npositions[query_lastpos];
    tminus_diagterm_end3 = querylength /* querypos + index1part_tr */;
  }

  tplus_diagpairs = Intersect_approx(&n_tplus_diagpairs,
				     tplus_positions_end5,n_tplus_positions_end5,tplus_diagterm_end5,
				     tplus_positions_end3,n_tplus_positions_end3,tplus_diagterm_end3,
				     /*maxdistance*/3);
  tminus_diagpairs = Intersect_approx(&n_tminus_diagpairs,
				      tminus_positions_end5,n_tminus_positions_end5,tminus_diagterm_end5,
				      tminus_positions_end3,n_tminus_positions_end3,tminus_diagterm_end3,
				      /*maxdistance*/3);

  debug4(printf("***Transcriptome approx: %d plus and %d minus diagpairs\n",
		n_tplus_diagpairs,n_tminus_diagpairs));

  k = 0;
  while (k < 2*n_tplus_diagpairs) {
    trdiagonala = tplus_diagpairs[k];
    trdiagonalb = tplus_diagpairs[k+1];
    if (trdiagonalb <= trdiagonala) {
      min_distance = trdiagonala - trdiagonalb;
    } else {
      min_distance = trdiagonalb - trdiagonala;
    }

    /* Pick the closest pair */
    j = k + 2;
    while (j < n_tplus_diagpairs && tplus_diagpairs[j] == trdiagonala) {
      if (tplus_diagpairs[j+1] <= trdiagonala) {
	distance = trdiagonala - tplus_diagpairs[j+1];
      } else {
	distance = tplus_diagpairs[j+1] - trdiagonala;
      }
      if (distance < min_distance) {
	min_distance = distance;
	trdiagonalb = tplus_diagpairs[j+1];
      }
      j += 2;
    }

    debug4(printf("tplus diagpairs: %u and %u\n",trdiagonala,trdiagonalb));
    if (trdiagonalb == trdiagonala) {
      /* Skip exact results, which were covered by TR_EXACT */
    } else {
      pos5a = Genomebits_first_kmer_left(&nmismatches_a5,transcriptomebits,query_compress_fwd,
					 /*univdiagonal*/(Univcoord_T) trdiagonala,querylength,
					 /*pos5*/0,/*pos3*/querylength,/*plusp*/true,/*genestrand*/0,
					 /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
      pos3a = Genomebits_first_kmer_right(&nmismatches_a3,transcriptomebits,query_compress_fwd,
					  /*univdiagonal*/(Univcoord_T) trdiagonala,querylength,
					  /*pos5*/0,/*pos3*/querylength,/*plusp*/true,/*genestrand*/0,
					  /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);

      pos5b = Genomebits_first_kmer_left(&nmismatches_b5,transcriptomebits,query_compress_fwd,
					 /*univdiagonal*/(Univcoord_T) trdiagonalb,querylength,
					 /*pos5*/0,/*pos3*/querylength,/*plusp*/true,/*genestrand*/0,
					 /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
      pos3b = Genomebits_first_kmer_right(&nmismatches_b3,transcriptomebits,query_compress_fwd,
					  /*univdiagonal*/(Univcoord_T) trdiagonalb,querylength,
					  /*pos5*/0,/*pos3*/querylength,/*plusp*/true,/*genestrand*/0,
					  /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
	  
      if (trdiagonala /*+qstart:0*/ < (Trcoord_T) querylength) {
	/* Skip */

      } else if (pos5a == 0 || pos3b == querylength) {
	/* Setting a first, b second */
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonala - querylength,trdiagonala);
	if ((trpath = Trpath_solve_from_ends(&(*found_score),&(*found_transcriptp),
					     trdiagonala,pos5a,pos3a,trdiagonalb,pos5b,pos3b,
					     /*tplusp*/true,querylength,/*query_compress_tr*/query_compress_fwd,
					     trnum,troffset,trhigh,/*want_lowest_coordinate_p*/false,
					     stage1->indelinfo,max_insertionlen,max_deletionlen,
					     intlistpool,uintlistpool,listpool,
					     trpathpool,pathpool,method)) != NULL) {
	  *sense_trpaths = Hitlist_push(*sense_trpaths,hitlistpool,(void *) trpath
					hitlistpool_trace(__FILE__,__LINE__));
	}

      } else if (pos5b == 0 || pos3a == querylength) {
	/* Setting b first, a second */
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonala - querylength,trdiagonala);
	if ((trpath = Trpath_solve_from_ends(&(*found_score),&(*found_transcriptp),
					     trdiagonalb,pos5b,pos3b,trdiagonala,pos5a,pos3a,
					     /*tplusp*/true,querylength,/*query_compress_tr*/query_compress_fwd,
					     trnum,troffset,trhigh,/*want_lowest_coordinate_p*/false,
					     stage1->indelinfo,max_insertionlen,max_deletionlen,
					     intlistpool,uintlistpool,listpool,
					     trpathpool,pathpool,method)) != NULL) {
	  debug4(printf("Created trpath\n"));
	  *sense_trpaths = Hitlist_push(*sense_trpaths,hitlistpool,(void *) trpath
					hitlistpool_trace(__FILE__,__LINE__));
	}

      } else {
	/* Skip.  Alignment does not go to the ends of the read */
      }
    }

    k = j;
  }

  /* Case for n_tminus_diagpairs == 0 already handled above */
  k = 0;
  while (k < 2*n_tminus_diagpairs) {
    trdiagonala = tminus_diagpairs[k];
    trdiagonalb = tminus_diagpairs[k+1];
    if (trdiagonalb <= trdiagonala) {
      min_distance = trdiagonala - trdiagonalb;
    } else {
      min_distance = trdiagonalb - trdiagonala;
    }

    /* Pick the closest pair */
    j = k + 2;
    while (j < n_tminus_diagpairs && tminus_diagpairs[j] == trdiagonala) {
      if (tminus_diagpairs[j+1] <= trdiagonala) {
	distance = trdiagonala - tminus_diagpairs[j+1];
      } else {
	distance = tminus_diagpairs[j+1] - trdiagonala;
      }
      if (distance < min_distance) {
	min_distance = distance;
	trdiagonalb = tminus_diagpairs[j+1];
      }
      j += 2;
    }

    debug4(printf("tminus diagpairs: %u and %u\n",trdiagonala,trdiagonalb));
    if (trdiagonalb == trdiagonala) {
      /* Skip exact results, which were covered by TR_EXACT */
    } else {
      pos5a = Genomebits_first_kmer_left(&nmismatches_a5,transcriptomebits,query_compress_rev,
					 /*univdiagonal*/(Univcoord_T) trdiagonala,querylength,
					 /*pos5*/0,/*pos3*/querylength,/*plusp*/false,/*genestrand*/0,
					 /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
      pos3a = Genomebits_first_kmer_right(&nmismatches_a3,transcriptomebits,query_compress_rev,
					  /*univdiagonal*/(Univcoord_T) trdiagonala,querylength,
					  /*pos5*/0,/*pos3*/querylength,/*plusp*/false,/*genestrand*/0,
					  /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
	  
      pos5b = Genomebits_first_kmer_left(&nmismatches_b5,transcriptomebits,query_compress_rev,
					 /*univdiagonal*/(Univcoord_T) trdiagonalb,querylength,
					 /*pos5*/0,/*pos3*/querylength,/*plusp*/false,/*genestrand*/0,
					 /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);
      pos3b = Genomebits_first_kmer_right(&nmismatches_b3,transcriptomebits,query_compress_rev,
					  /*univdiagonal*/(Univcoord_T) trdiagonalb,querylength,
					  /*pos5*/0,/*pos3*/querylength,/*plusp*/false,/*genestrand*/0,
					  /*query_unk_mismatch_local_p*/false,/*kmer*/index1part_tr);

      if (trdiagonala /*+qstart:0*/ < (Trcoord_T) querylength) {
	/* Skip */

      } else if (pos5a == 0 || pos3b == querylength) {
	/* Setting a first, b second */
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonala - querylength,trdiagonala);
	if ((trpath = Trpath_solve_from_ends(&(*found_score),&(*found_transcriptp),
					     trdiagonala,pos5a,pos3a,trdiagonalb,pos5b,pos3b,
					     /*tplusp*/false,querylength,/*query_compress_tr*/query_compress_rev,
					     trnum,troffset,trhigh,/*want_lowest_coordinate_p*/false,
					     stage1->indelinfo,max_insertionlen,max_deletionlen,
					     intlistpool,uintlistpool,listpool,
					     trpathpool,pathpool,method)) != NULL) {
	  debug4(printf("Created trpath\n"));
	  *antisense_trpaths = Hitlist_push(*antisense_trpaths,hitlistpool,(void *) trpath
					    hitlistpool_trace(__FILE__,__LINE__));
	}

      } else if (pos5b == 0 || pos3a == querylength) {
	/* Setting b first, a second */
	trnum = EF64_trnum(&troffset,&trhigh,transcript_ef64,trdiagonala - querylength,trdiagonala);
	if ((trpath = Trpath_solve_from_ends(&(*found_score),&(*found_transcriptp),
					     trdiagonalb,pos5b,pos3b,trdiagonala,pos5a,pos3a,
					     /*tplusp*/false,querylength,/*query_compress_tr*/query_compress_rev,
					     trnum,troffset,trhigh,/*want_lowest_coordinate_p*/false,
					     stage1->indelinfo,max_insertionlen,max_deletionlen,
					     intlistpool,uintlistpool,listpool,
					     trpathpool,pathpool,method)) != NULL) {
	  debug4(printf("Created trpath\n"));
	  *antisense_trpaths = Hitlist_push(*antisense_trpaths,hitlistpool,(void *) trpath
					    hitlistpool_trace(__FILE__,__LINE__));
	}

      } else {
	/* Skip.  Read does not extend to the ends, so this method is not applicable */
      }
    }

    k = j;
  }

  FREE(tminus_diagpairs);
  FREE(tplus_diagpairs);

  return;
}


void
Transcriptome_search_setup (int index1part_tr_in, int index1interval_tr_in,
			    Indexdb_T tr_indexdb_in, Transcriptome_T transcriptome_in,
			    EF64_T transcript_ef64_in, Genomebits_T genomebits_in,
			    Genomebits_T genomebits_alt_in, Genomebits_T transcriptomebits_in) {

  index1interval_tr = index1interval_tr_in;
  index1part_tr = index1part_tr_in;
  
  tr_indexdb = tr_indexdb_in;

  transcriptome = transcriptome_in;
  transcript_ef64 = transcript_ef64_in;

  genomebits = genomebits_in;
  genomebits_alt = genomebits_alt_in;
  transcriptomebits = transcriptomebits_in;

#ifdef HAVE_64_BIT
  leftreadshift_tr = 64 - index1part_tr - index1part_tr;
  oligobase_mask_tr = ~(~ (Oligospace_T) 0 << 2*index1part_tr);
#else
  leftreadshift_tr = 32 - index1part_tr - index1part_tr;
  oligobase_mask_tr = ~(~ (Oligospace_T) 0 << 2*index1part_tr);
#endif

  return;
}


