static char rcsid[] = "$Id: 94c8d04b5f148996484569fe00fa850819423516 $";
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "spliceends.h"

#include <stdio.h>
#include <string.h>

#include "mem.h"
#include "assert.h"
#include "sense.h"
#include "genomebits_count.h"
#include "genomebits_mismatches.h"
#include "maxent.h"
#include "maxent_hr.h"
#include "univcoord.h"

/* Trimming at chromosome bounds can cause problems with endpoints, so
   do all trimming later */
/* #define TRIM_AT_CHROMOSOME_BOUNDS 1 */

#define MAX_NSPLICEENDS 30
#define ALLOW_DISTAL_PARTNER 1

#define ACCEPTABLE_TRIM 3

#define DEFAULT_MEDIAL_SPLICESITE_PROB 0.90
#define DEFAULT_DISTAL_SPLICESITE_PROB 0.90

#define SALVAGE_MEDIAL_SPLICESITE_PROB 0.80
#define SALVAGE_DISTAL_SPLICESITE_PROB 0.80

#define MAX_NCONSECUTIVE_CLOSE 6
#define MAX_NCONSECUTIVE_FAR 20	/* Needs to be generous to find splices */

#define END_SPLICESITE_SEARCH_MM 1 /* Amount to search in the trimmed area */
#define END_SPLICESITE_SEARCH 10   /* Amount to search in the matching area (beyond the correct splice site) */

#define MIN_EXON_LENGTH 20	/* Minimum length from the exon_origin before we accept a splice site */
#define MIN_INTRON_LENGTH 9

/* Designed to allow 1 match to offset 1 mismatch.  To handle 2 matches vs 2 mismatches, penalize for multiple mismatches */
#define TRIM_MATCH_SCORE 1
#define TRIM_MISMATCH_SCORE_LAST -1 /* Requires 1 match to compensate */
#define TRIM_MISMATCH_SCORE_MULT -4 /* Requires 4 matches to compensate */


/* Known and novel splicing at ends */
#ifdef DEBUG1
#define debug1(x) x
#else
#define debug1(x)
#endif

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

/* Trimming nosplice */
#ifdef DEBUG6
#define debug6(x) x
#else
#define debug6(x)
#endif

/* Trimming at ends */
#ifdef DEBUG8
#define debug8(x) x
#else
#define debug8(x)
#endif

/* Do need to trim univdiagonals at chromosome bounds, but not pos5 or pos3 */
#define add_bounded(x,plusterm,highbound) ((x + (plusterm) >= highbound) ? (highbound - 1) : x + (plusterm))
#define subtract_bounded(x,minusterm,lowbound) ((x < lowbound + (minusterm)) ? lowbound : x - (minusterm))


static bool *circularp;

static Genomebits_T genomebits;
static Genomebits_T genomebits_alt;
static Univcoord_T genomelength;

static Localdb_T localdb;

/* Needs to be < 65536 for Mergeinfo_T not to overflow */
static Chrpos_T shortsplicedist_novelend;
static bool allow_soft_clips_p;

static int distal_nmismatches_allowed = 1;

#define T Spliceends_T

void
Spliceends_setup (bool *circularp_in,
		  Genomebits_T genomebits_in, Genomebits_T genomebits_alt_in,
		  Univcoord_T genomelength_in,
		  Localdb_T localdb_in, Chrpos_T shortsplicedist_novelend_in,
		  bool allow_soft_clips_p_in) {

  circularp = circularp_in;
  genomebits = genomebits_in;
  genomebits_alt = genomebits_alt_in;
  genomelength = genomelength_in;
  localdb = localdb_in;
  shortsplicedist_novelend = shortsplicedist_novelend_in;
  allow_soft_clips_p = allow_soft_clips_p_in;

  return;
}


void
Spliceends_free (T *old) {
  if (*old) {
    FREE((*old)->distal_probs);
    FREE((*old)->ambig_probs);

    FREE((*old)->distal_nmismatches);
    FREE((*old)->medial_nmismatches);
    FREE((*old)->partners);
    FREE((*old)->trimends);
    FREE((*old)->matchlengths);

    FREE((*old)->mismatch_positions_left);
    FREE((*old)->mismatch_positions_right);

    FREE(*old);
  }

  return;
}


T
Spliceends_new (int id, int querylength) {
  T new = (T) MALLOC(sizeof(*new));

  new->id = id;		    /* For debugging of Spliceendsgen_T */
  new->checkedout_p = true;	/* Because created by Spliceendsgen_T only when needed */

  /* Computed later */
  /* new->nspliceends = nspliceends; */
  /* new->splicetype = splicetype; */
  /* new->sensedir = sensedir; */

  /* MISMATCH_EXTRA defined in genomebits_mismatches.h */

  new->mismatch_positions_left = (int *) MALLOC((querylength + MISMATCH_EXTRA)*sizeof(int));
  new->mismatch_positions_right = (int *) MALLOC((querylength + MISMATCH_EXTRA)*sizeof(int));

  new->matchlengths = (int *) MALLOC((MAX_NSPLICEENDS + 1)*sizeof(int));
  new->trimends = (int *) MALLOC((MAX_NSPLICEENDS + 1)*sizeof(int));
  new->partners = (Univcoord_T *) MALLOC((MAX_NSPLICEENDS + 1)*sizeof(Univcoord_T));

  new->medial_nmismatches = (int *) MALLOC((MAX_NSPLICEENDS + 1)*sizeof(int));
  new->distal_nmismatches = (int *) MALLOC((MAX_NSPLICEENDS + 1)*sizeof(int));

  new->ambig_probs = (double *) MALLOC(MAX_NSPLICEENDS * sizeof(double));
  new->distal_probs = (double *) MALLOC(MAX_NSPLICEENDS * sizeof(double));
  
  return new;
}


static inline int
min_spliceend (int *trimends, int nspliceends) {
  int min;
  int i;

  min = trimends[0];
  for (i = 1; i < nspliceends; i++) {
    if (trimends[i] < min) {
      min = trimends[i];
    }
  }
  return min;
}

static inline int
max_spliceend (int *trimends, int nspliceends) {
  int max;
  int i;

  max = trimends[0];
  for (i = 1; i < nspliceends; i++) {
    if (trimends[i] > max) {
      max = trimends[i];
    }
  }
  return max;
}


/* Stores information in qpos_alloc, partners, and ambig_probs */
static int
known_spliceends_trim5_sense (T this, Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, int qstart, int qend,
			      Compress_T query_compress, Univcoord_T univdiagonal, int querylength,
			      Knownsplicing_T knownsplicing, bool plusp, int genestrand) {
  int nspliceends = 0, i, k;
  Univcoord_T *endpoints;
  uint64_t low_rank, high_rank, rank;

  int *mismatch_positions_left, pos5;
  int ref_distal_nmismatches, splice_qpos;
  int nmismatches_left, lefti;
  int best_adj_support, adj_support;
  Univcoord_T left = univdiagonal - querylength;

  assert(start_genomicpos < end_genomicpos);

  if (plusp) {
    debug1(printf("known_spliceends_trim5_sense, plus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_acceptors(&low_rank,&high_rank,knownsplicing,
					univdiagonal,querylength,start_genomicpos - left,end_genomicpos - left);
    debug1(printf("Knownsplicing acceptors at %u..%u yields low_rank %lu to high_rank %lu\n",
		   start_genomicpos,end_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if (high_rank - low_rank > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      for (rank = low_rank; rank < high_rank; rank++) { /* For qstart, want lower qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank] - endpoints[2*rank+1])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
      }
    }

  } else {
    debug1(printf("known_spliceends_trim5_sense, minus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_antidonors(&low_rank,&high_rank,knownsplicing,
					 univdiagonal,querylength,start_genomicpos - left,end_genomicpos - left);
    debug1(printf("Knownsplicing antidonors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  start_genomicpos,end_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if (high_rank - low_rank > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      for (rank = low_rank; rank < high_rank; rank++) { /* For qstart, want lower qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank] - endpoints[2*rank+1])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
      }
    }
  }

  if (nspliceends > 0) {
    /* Refine results based on distal mismatches and return univdiagonals */

    /* Need to compute mismatch_positions_left because we are returning medial_nmismatches */
    pos5 = min_spliceend(this->trimends,nspliceends); /* Need to cover all possible splice ends */
    mismatch_positions_left = this->mismatch_positions_left; /* Use allocated memory */
    nmismatches_left = Genomebits_mismatches_fromleft(mismatch_positions_left,/*nmismatches_allowed*/querylength,
						      /*ome*/genomebits,/*ome_alt*/genomebits_alt,query_compress,
						      univdiagonal,querylength,pos5,/*pos3*/qend,
						      plusp,genestrand);
    debug1(
	    printf("(1) %d mismatches on left from %d to %d at:",nmismatches_left,pos5,qend);
	    for (i = 0; i <= nmismatches_left; i++) {
	      printf(" %d",mismatch_positions_left[i]);
	    }
	    printf("\n");
	    );
    
    debug1(printf("Writing to medial_nmismatches and distal_nmismatches\n"));
    best_adj_support = 0;
    
    for (i = 0; i < nspliceends; i++) {
      splice_qpos = this->trimends[i];
      this->distal_nmismatches[i] =
	Genomebits_count_mismatches_substring(&ref_distal_nmismatches,genomebits,genomebits_alt,query_compress,
					      /*univdiagonal*/this->partners[i] - splice_qpos + querylength,querylength,
					      /*pos5*/0,/*pos3*/splice_qpos,plusp,genestrand);
      debug1(printf("%d mismatches in distal substring at %u from %d to %d\n",
		    this->distal_nmismatches[i],this->partners[i] - splice_qpos,0,splice_qpos));
      if ((adj_support = splice_qpos - 3*this->distal_nmismatches[i]) > best_adj_support) {
	best_adj_support = adj_support;
      }
    }
    
    if (best_adj_support == 0) {
      debug1(printf("Insufficient distal support\n"));
      nspliceends = 0;

    } else {
      debug1(printf("Sufficient distal support of %d\n",best_adj_support));
      k = 0;
      lefti = 0;
      for (i = 0; i < nspliceends; i++) {
	splice_qpos = this->trimends[i];
	if (splice_qpos - 3*this->distal_nmismatches[i] < best_adj_support) {
	  /* Skip */
	} else {
	  while (lefti < nmismatches_left && mismatch_positions_left[lefti] < splice_qpos) {
	    lefti++;
	  }
	  debug1(printf("(1) For splice_qpos %d, advanced to lefti %d, so computing medial_nmismatches as %d - %d = %d\n",
			splice_qpos,lefti,nmismatches_left,lefti,nmismatches_left - lefti));
	  
	  this->medial_nmismatches[k] = nmismatches_left - lefti;
	  this->matchlengths[k] = splice_qpos;
	  this->trimends[k] = splice_qpos;
	  this->partners[k] = this->partners[i];
	  this->distal_nmismatches[k] = this->distal_nmismatches[i];
	  this->ambig_probs[k] = 1.0;
	  this->distal_probs[k] = 1.0;

	  k++;
	}
      }
      
      nspliceends = k;
    }
  }

  debug1(printf("knownsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}

static int
novel_spliceends_trim5_sense (double *max_prob, bool *partnerp, T this,
			      Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, Univcoord_T middle_genomicpos,
			      int *mismatch_positions, int total_nmismatches,
			      Univcoord_T univdiagonal, int querylength,
			      Compress_T query_compress, char *queryptr, Univcoord_T chroffset,
			      Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			      int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			      Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			      double medial_splicesite_prob, double distal_splicesite_prob, int max_nconsecutive,
			      bool plusp, int genestrand, int localdb_nmismatches_allowed,
			      bool search_localdb_p, bool innerp, bool salvagep) {
  int nspliceends = 0, k = 0;
  Univcoord_T genomicpos, distal_genomicpos, low_univdiagonal, high_univdiagonal;

  int local_nmismatches, matchlength;
  double donor_prob, acceptor_prob;
  int querypos, pos5, splice_qpos;
  int mismatchi = total_nmismatches;
  int nconsecutive;
  int novel_ndiagonals, i;
  Univcoord_T left = univdiagonal - querylength;

  *max_prob = 0.0;
  *partnerp = false;

  assert(start_genomicpos < end_genomicpos);

  debug1(printf("Start with univdiagonal %u\n",univdiagonal));
  high_univdiagonal = univdiagonal - MIN_INTRON_LENGTH; /* Subtract so we don't return a continuation */
  debug1(printf("Subtract %d to yield high_univdiagonal %u\n",MIN_INTRON_LENGTH,high_univdiagonal));
#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos5 = (high_univdiagonal >= chroffset + (Univcoord_T) querylength) ? 0 : (int) (chroffset - left);
#else
  pos5 = 0;
#endif
  low_univdiagonal = subtract_bounded(high_univdiagonal,shortsplicedist_novelend,chroffset);
  debug1(printf("Subtract %d (bounded by %u) to yield low_univdiagonal %u\n",
		shortsplicedist_novelend,chroffset,low_univdiagonal));
  debug1(printf("  (1) shortsplicedist_novelend %u, low %u, high %u\n",
		shortsplicedist_novelend,low_univdiagonal,high_univdiagonal));

  genomicpos = start_genomicpos;
  querypos = genomicpos - left;
  while (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] < querypos) {
    mismatchi--;
  }

  if (low_univdiagonal > high_univdiagonal) {
    /* Skip */

  } else if (plusp) {
    debug1(printf("novel_spliceends_trim5_sense, plus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos < middle_genomicpos) {
      acceptor_prob = Maxent_hr_acceptor_prob(genomicpos,chroffset); /* Case 2 */
      debug1(printf("5' plus, sense forward %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,acceptor_prob));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else {
	  debug1(printf("(1) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_donor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
      querypos++;
      genomicpos++;
    }
      
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos < end_genomicpos && nconsecutive < max_nconsecutive) {
      acceptor_prob = Maxent_hr_acceptor_prob(genomicpos,chroffset); /* Case 2 */
      debug1(printf("5' plus, sense forward %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,acceptor_prob,nconsecutive));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
	    
	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else {
	  debug1(printf("(2) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_donor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
      querypos++;
      genomicpos++;
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));

  } else {
    debug1(printf("novel_spliceends_trim5_sense, minus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos < middle_genomicpos) {
      donor_prob = Maxent_hr_antidonor_prob(genomicpos,chroffset); /* Case 6 */
      debug1(printf("5' minus, sense forward %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,donor_prob));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else {
	  debug1(printf("(3) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_antiacceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
      querypos++;
      genomicpos++;
    }
    
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos < end_genomicpos && nconsecutive < max_nconsecutive) {
      donor_prob = Maxent_hr_antidonor_prob(genomicpos,chroffset); /* Case 6 */
      debug1(printf("5' minus, sense forward %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,donor_prob,nconsecutive));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else {
	  debug1(printf("(4) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_antiacceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
      querypos++;
      genomicpos++;
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));
  }

  debug1(printf("k = %d\n",k));
  if (k == 0) {
    /* Skip */
    nspliceends = 0;

  } else if (innerp == false) {
    /* Keep only the best spliceends (max_prob should distinguish partner from non-partner) */
    for (i = 0; i < k; i++) {
      if (this->ambig_probs[i] + this->distal_probs[i] == *max_prob) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else if (*partnerp == true) {
    /* Keep all partner ends for later resolving of ambiguity */
    for (i = 0; i < k; i++) {
      if (this->partners[i] != 0) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else {
    /* Keep the most distal inner splice end */
    nspliceends = 1;
  }
	
  debug1(printf("novelsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


/* Stores information in trimends and partners */
static int
known_spliceends_trim5_anti (T this, Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, int qstart, int qend,
			     Compress_T query_compress, Univcoord_T univdiagonal, int querylength,
			     Knownsplicing_T knownsplicing, bool plusp, int genestrand) {
  int nspliceends = 0, i, k;
  Univcoord_T *endpoints;
  uint64_t low_rank, high_rank, rank;

  int *mismatch_positions_left, pos5;
  int ref_distal_nmismatches, splice_qpos;
  int nmismatches_left, lefti;
  int best_adj_support, adj_support;
  Univcoord_T left = univdiagonal - querylength;

  assert(start_genomicpos < end_genomicpos);

  if (plusp) {
    debug1(printf("known_spliceends_trim5_anti, plus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_antidonors(&low_rank,&high_rank,knownsplicing,
					 univdiagonal,querylength,start_genomicpos - left,end_genomicpos - left);
    debug1(printf("Knownsplicing antidonors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  start_genomicpos,end_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if (high_rank - low_rank > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      for (rank = low_rank; rank < high_rank; rank++) { /* For qstart, want lower qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank] - endpoints[2*rank+1])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
      }
    }

  } else {
    debug1(printf("known_spliceends_trim5_anti, minus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_acceptors(&low_rank,&high_rank,knownsplicing,
					univdiagonal,querylength,start_genomicpos - left,end_genomicpos - left);
    debug1(printf("Knownsplicing acceptors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  start_genomicpos,end_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if (high_rank - low_rank > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      for (rank = low_rank; rank < high_rank; rank++) { /* For qstart, want lower qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank] - endpoints[2*rank+1])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
      }
    }
  }
    
  if (nspliceends > 0) {
    /* Refine results based on distal mismatches and return univdiagonals */

    /* Need to compute mismatch_positions_left because we are returning medial_nmismatches */
    pos5 = min_spliceend(this->trimends,nspliceends); /* Need to cover all possible splice ends */
    mismatch_positions_left = this->mismatch_positions_left; /* Use allocated memory */
    nmismatches_left = Genomebits_mismatches_fromleft(mismatch_positions_left,/*nmismatches_allowed*/querylength,
						      /*ome*/genomebits,/*ome_alt*/genomebits_alt,query_compress,
						      univdiagonal,querylength,pos5,/*pos3*/qend,
						      plusp,genestrand);
    debug1(
	    printf("(2) %d mismatches on left from %d to %d at:",nmismatches_left,pos5,qend);
	    for (i = 0; i <= nmismatches_left; i++) {
	      printf(" %d",mismatch_positions_left[i]);
	    }
	    printf("\n");
	    );
    
    debug1(printf("Writing to medial_nmismatches and distal_nmismatches\n"));
    best_adj_support = 0;
    
    for (i = 0; i < nspliceends; i++) {
      splice_qpos = this->trimends[i];
      this->distal_nmismatches[i] =
	Genomebits_count_mismatches_substring(&ref_distal_nmismatches,genomebits,genomebits_alt,query_compress,
					      /*univdiagonal*/this->partners[i] - splice_qpos + querylength,querylength,
					      /*pos5*/0,/*pos3*/splice_qpos,plusp,genestrand);
      if ((adj_support = splice_qpos - 3*this->distal_nmismatches[i]) > best_adj_support) {
	best_adj_support = adj_support;
      }
    }
    
    if (best_adj_support == 0) {
      debug1(printf("Insufficient distal support\n"));
      nspliceends = 0;

    } else {
      debug1(printf("Sufficient distal support of %d\n",best_adj_support));
      k = 0;
      lefti = 0;
      for (i = 0; i < nspliceends; i++) {
	splice_qpos = this->trimends[i];
	if (splice_qpos - 3*this->distal_nmismatches[i] < best_adj_support) {
	  /* Skip */
	} else {
	  while (lefti < nmismatches_left && mismatch_positions_left[lefti] < splice_qpos) {
	    lefti++;
	  }
	  debug1(printf("(2) For splice_qpos %d, advanced to lefti %d, so computing medial_nmismatches as %d - %d = %d\n",
			splice_qpos,lefti,nmismatches_left,lefti,nmismatches_left - lefti));
	
	  this->medial_nmismatches[k] = nmismatches_left - lefti;
	  this->matchlengths[k] = splice_qpos;
	  this->trimends[k] = splice_qpos;
	  this->partners[k] = this->partners[i];
	  this->distal_nmismatches[k] = this->distal_nmismatches[i];
	  this->ambig_probs[k] = 1.0;
	  this->distal_probs[k] = 1.0;

	  k++;
	}
      }
    
      nspliceends = k;
    }
  }

  debug1(printf("knownsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


static int
novel_spliceends_trim5_anti (double *max_prob, bool *partnerp, T this,
			     Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, Univcoord_T middle_genomicpos,
			     int *mismatch_positions, int total_nmismatches,
			     Univcoord_T univdiagonal, int querylength,
			     Compress_T query_compress, char *queryptr, Univcoord_T chroffset,
			     Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			     int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			     Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			     double medial_splicesite_prob, double distal_splicesite_prob, int max_nconsecutive,
			     bool plusp, int genestrand, int localdb_nmismatches_allowed,
			     bool search_localdb_p, bool innerp, bool salvagep) {
  int nspliceends = 0, k = 0;
  Univcoord_T genomicpos, distal_genomicpos, low_univdiagonal, high_univdiagonal;

  int local_nmismatches, matchlength;
  double donor_prob, acceptor_prob;
  int querypos, pos5, splice_qpos;
  int mismatchi = total_nmismatches;
  int nconsecutive;
  int novel_ndiagonals, i;
  Univcoord_T left = univdiagonal - querylength;

  *max_prob = 0.0;
  *partnerp = false;

  assert(start_genomicpos < end_genomicpos);

  debug1(printf("Start with univdiagonal %u\n",univdiagonal));
  high_univdiagonal = univdiagonal - MIN_INTRON_LENGTH; /* Subtract so we don't return a continuation */
  debug1(printf("Subtract %d to yield high_univdiagonal %u\n",MIN_INTRON_LENGTH,high_univdiagonal));
#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos5 = (high_univdiagonal >= chroffset + (Univcoord_T) querylength) ? 0 : (int) (chroffset - left);
#else
  pos5 = 0;
#endif
  low_univdiagonal = subtract_bounded(high_univdiagonal,shortsplicedist_novelend,chroffset);
  debug1(printf("Subtract %d (bounded by %u) to yield low_univdiagonal %u\n",
		shortsplicedist_novelend,chroffset,low_univdiagonal));
  debug1(printf("  (2) shortsplicedist_novelend %u, low %u, high %u\n",
		shortsplicedist_novelend,low_univdiagonal,high_univdiagonal));

  genomicpos = start_genomicpos;
  querypos = genomicpos - left;
  while (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] < querypos) {
    mismatchi--;
  }

  if (low_univdiagonal > high_univdiagonal) {
    /* Skip */

  } else if (plusp) {
    debug1(printf("novel_spliceends_trim5_anti, plus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos < middle_genomicpos) {
      donor_prob = Maxent_hr_antidonor_prob(genomicpos,chroffset); /* Case 6 */
      debug1(printf("5' plus, sense anti %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,donor_prob));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif
	  
	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else {
	  debug1(printf("(5) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_antiacceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
      querypos++;
      genomicpos++;
    }
    
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos < end_genomicpos && nconsecutive < max_nconsecutive) {
      donor_prob = Maxent_hr_antidonor_prob(genomicpos,chroffset); /* Case 6 */
      debug1(printf("5' plus, sense anti %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,donor_prob,nconsecutive));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else {
	  debug1(printf("(6) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_antiacceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
      querypos++;
      genomicpos++;
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));

  } else {
    debug1(printf("novel_spliceends_trim5_anti, minus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos < middle_genomicpos) {
      acceptor_prob = Maxent_hr_acceptor_prob(genomicpos,chroffset); /* Case 2 */
      debug1(printf("5' minus, sense anti %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,acceptor_prob));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else {
	  debug1(printf("(7) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_donor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
      querypos++;
      genomicpos++;
    }
    
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos < end_genomicpos && nconsecutive < max_nconsecutive) {
      acceptor_prob = Maxent_hr_acceptor_prob(genomicpos,chroffset); /* Case 2 */
      debug1(printf("5' minus, sense anti %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,acceptor_prob,nconsecutive));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,pos5,/*pos3*/splice_qpos,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else {
	  debug1(printf("(8) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_donor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
      querypos++;
      genomicpos++;
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));
  }

  debug1(printf("k = %d\n",k));
  if (k == 0) {
    /* Skip */
    nspliceends = 0;

  } else if (innerp == false) {
    /* Keep only the best spliceends (max_prob should distinguish partner from non-partner) */
    for (i = 0; i < k; i++) {
      if (this->ambig_probs[i] + this->distal_probs[i] == *max_prob) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else if (*partnerp == true) {
    /* Keep all partner ends for later resolving of ambiguity */
    for (i = 0; i < k; i++) {
      if (this->partners[i] != 0) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else {
    /* Keep the most distal inner splice end */
    nspliceends = 1;
  }

  debug1(printf("novelsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}



/* TODO: Consider whether there is a conflict between the regular prob
   and mismatch prob, and if so, set splicedir to be SENSE_NULL */
static T
trim_5 (bool *partnerp, Compress_T query_compress, char *queryptr,
	Knownsplicing_T knownsplicing, int try_sensedir,
	Univcoord_T univdiagonal, int querylength,
	int pos5, int qstart, int qend, int exon_origin, Univcoord_T chroffset,
	int *mismatch_positions, int total_nmismatches,
	Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
	int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
	Univcoord_T **streamptr_alloc, int *streamsize_alloc,
	Mergeinfo_T mergeinfo, Spliceendsgen_T spliceendsgen,
	int max_nconsecutive, bool plusp, int genestrand, int localdb_nmismatches_allowed,
	bool search_localdb_p, bool innerp, bool salvagep) {
  T new, anti;
  int found_sensedir;
  int qdistal;
  int mismatchi;
  int nspliceends = 0, n_sense_spliceends, n_anti_spliceends;
  Univcoord_T start_genomicpos, middle_genomicpos, end_genomicpos;
  double max_sense_prob = 0.0, max_antisense_prob = 0.0;
  bool sense_partnerp, antisense_partnerp;
  double medial_splicesite_prob, distal_splicesite_prob;
  Univcoord_T left = univdiagonal - querylength;


  debug1(printf("\nEntered trim_5 with try_sensedir %d, qstart %d to qend %d\n",
		 try_sensedir,qstart,qend));

  if (salvagep == true) {
    medial_splicesite_prob = SALVAGE_MEDIAL_SPLICESITE_PROB;
    distal_splicesite_prob = SALVAGE_DISTAL_SPLICESITE_PROB;
  } else {
    medial_splicesite_prob = DEFAULT_MEDIAL_SPLICESITE_PROB;
    distal_splicesite_prob = DEFAULT_DISTAL_SPLICESITE_PROB;
  }

  /* Search from qstart - END_SPLICESITE_SEARCH_MM to qstart +
     END_SPLICESITE_SEARCH, but not past qend */

  middle_genomicpos = left + qstart;

  debug1(
	 printf("%d mismatches from qend %d down to pos5 %d:",total_nmismatches,qend,pos5);
	 for (int i = 0; i <= total_nmismatches; i++) {
	   printf(" %d",mismatch_positions[i]);
	 }
	 printf("\n");
	 );

  /* middle_genomicpos is where the current trim is.  Previously
     subtracted END_SPLICESITE_SEARCH_MM, but now allowing some number
     of mismatches distally to get to start_genomicpos */
  mismatchi = 0;
  while (mismatchi < total_nmismatches && mismatch_positions[mismatchi] >= qstart) {
    mismatchi++;
  }

  if (mismatchi + distal_nmismatches_allowed >= total_nmismatches) {
    qdistal = pos5;
    debug1(printf("qdistal = pos5 %d\n",qdistal));
  } else {
    qdistal = mismatch_positions[mismatchi + distal_nmismatches_allowed];
    debug1(printf("qdistal = mismatch position %d\n",qdistal));
  }
  if (qdistal == 0) {
    /* Don't need to evaluate at the end of the read */
    qdistal = 1;
  }

#if 0
  if (middle_genomicpos < left + END_SPLICESITE_SEARCH_MM) {
    start_genomicpos = left;
  } else {
    start_genomicpos = middle_genomicpos - END_SPLICESITE_SEARCH_MM;
  }
#else
  start_genomicpos = left + qdistal;
#endif

  if ((end_genomicpos = middle_genomicpos + END_SPLICESITE_SEARCH) > left + qend) {
    end_genomicpos = left + qend;
  }

  if (left + exon_origin < MIN_EXON_LENGTH) {
    /* At beginning of genome, so don't subtract MIN_EXON_LENGTH */
  } else if (end_genomicpos > left + exon_origin - MIN_EXON_LENGTH) {
    end_genomicpos = left + exon_origin - MIN_EXON_LENGTH;
  }

  debug1(printf("\n1 Set end points for 5' trim to be %u..%u..%u\n",
		start_genomicpos,middle_genomicpos,end_genomicpos));

  if (start_genomicpos >= end_genomicpos) {
    debug1(printf("Got no spliceends\n"));
    return (T) NULL;
  } else {
    new = Spliceendsgen_checkout(spliceendsgen,querylength);
  }

  if (try_sensedir == SENSE_FORWARD) {
    if (knownsplicing != NULL &&
	(nspliceends = known_spliceends_trim5_sense(new,end_genomicpos,start_genomicpos,qstart,qend,
						    query_compress,univdiagonal,querylength,
						    knownsplicing,plusp,genestrand)) > 0) {
      *partnerp = true;
      max_sense_prob = 1.0;
    } else {
      nspliceends = novel_spliceends_trim5_sense(&max_sense_prob,&(*partnerp),new,
						 end_genomicpos,start_genomicpos,middle_genomicpos,
						 mismatch_positions,total_nmismatches,univdiagonal,querylength,
						 query_compress,queryptr,chroffset,
						 novel_diagonals_alloc,localdb_alloc,
						 streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						 medial_splicesite_prob,distal_splicesite_prob,
						 max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						 search_localdb_p,innerp,salvagep);
    }
    found_sensedir = SENSE_FORWARD;

  } else if (try_sensedir == SENSE_ANTI) {
    if (knownsplicing != NULL &&
	(nspliceends = known_spliceends_trim5_anti(new,end_genomicpos,start_genomicpos,qstart,qend,
						   query_compress,univdiagonal,querylength,
						   knownsplicing,plusp,genestrand)) > 0) {
      *partnerp = true;
      max_antisense_prob = 1.0;
    } else {
      nspliceends = novel_spliceends_trim5_anti(&max_antisense_prob,&(*partnerp),new,
						end_genomicpos,start_genomicpos,middle_genomicpos,
						mismatch_positions,total_nmismatches,univdiagonal,querylength,
						query_compress,queryptr,chroffset,
						novel_diagonals_alloc,localdb_alloc,
						streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						medial_splicesite_prob,distal_splicesite_prob,
						max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						search_localdb_p,innerp,salvagep);
    }
    found_sensedir = SENSE_ANTI;

  } else {
    /* SENSE_NULL */
    anti = Spliceendsgen_checkout(spliceendsgen,querylength);
    if (knownsplicing != NULL &&
	(n_sense_spliceends = known_spliceends_trim5_sense(new,end_genomicpos,start_genomicpos,qstart,qend,
							   query_compress,univdiagonal,querylength,
							   knownsplicing,plusp,genestrand)) > 0) {
      sense_partnerp = true;
      max_sense_prob = 1.0;
    } else {
      n_sense_spliceends = novel_spliceends_trim5_sense(&max_sense_prob,&sense_partnerp,new,
							end_genomicpos,start_genomicpos,middle_genomicpos,
							mismatch_positions,total_nmismatches,univdiagonal,querylength,
							query_compress,queryptr,chroffset,
							novel_diagonals_alloc,localdb_alloc,
							streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
							medial_splicesite_prob,distal_splicesite_prob,
							max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
							search_localdb_p,innerp,salvagep);
    }

    if (knownsplicing != NULL &&
	(n_anti_spliceends = known_spliceends_trim5_anti(anti,end_genomicpos,start_genomicpos,qstart,qend,
							 query_compress,univdiagonal,querylength,
							 knownsplicing,plusp,genestrand)) > 0) {
      antisense_partnerp = true;
      max_antisense_prob = 1.0;
    } else {
      n_anti_spliceends = novel_spliceends_trim5_anti(&max_antisense_prob,&antisense_partnerp,anti,
						      end_genomicpos,start_genomicpos,middle_genomicpos,
						      mismatch_positions,total_nmismatches,univdiagonal,querylength,
						      query_compress,queryptr,chroffset,
						      novel_diagonals_alloc,localdb_alloc,
						      streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						      medial_splicesite_prob,distal_splicesite_prob,
						      max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						      search_localdb_p,innerp,salvagep);
    }

    if (max_sense_prob > max_antisense_prob) {
      /* Keep information in trimends and partners */
      *partnerp = sense_partnerp;
      nspliceends = n_sense_spliceends;
      found_sensedir = SENSE_FORWARD;
      Spliceendsgen_return(spliceendsgen,&anti);
    } else if (max_antisense_prob > max_sense_prob) {
      /* Copy information into trimends and partners */
      *partnerp = antisense_partnerp;
      nspliceends = n_anti_spliceends;
      found_sensedir = SENSE_ANTI;
      Spliceendsgen_return(spliceendsgen,&new);
      new = anti;
    } else {
      debug1(printf("Cannot distinguish between sense and antisense at end\n"));
      Spliceendsgen_return(spliceendsgen,&anti);
      Spliceendsgen_return(spliceendsgen,&new);
      return (T) NULL;
    }
  }


  if (nspliceends == 0) {
    debug1(printf("Got no spliceends\n"));
    Spliceendsgen_return(spliceendsgen,&new);
    return (T) NULL;

  } else {
    new->nspliceends = nspliceends;
    new->sensedir = found_sensedir;
    if (found_sensedir == SENSE_FORWARD) {
      if (plusp) {
	new->splicetype = ACCEPTOR;
      } else {
	new->splicetype = ANTIDONOR;
      }

    } else {
      /* SENSE_ANTI */
      if (plusp) {
	new->splicetype = ANTIDONOR;
      } else {
	new->splicetype = ACCEPTOR;
      }
    }

    debug1(printf("trim_5 got %d spliceends\n",nspliceends));
    return new;
  }
}


/* Stores information in trimends and partners */
static int
known_spliceends_trim3_sense (T this, Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, int qstart, int qend,
			      Compress_T query_compress, Univcoord_T univdiagonal, int querylength,
			      Knownsplicing_T knownsplicing, bool plusp, int genestrand) {
  int nspliceends = 0, n, i, k;
  Univcoord_T *endpoints;
  uint64_t low_rank, high_rank, rank;

  int *mismatch_positions_right, pos3;
  int ref_distal_nmismatches, splice_qpos;
  int nmismatches_right, righti;
  int best_adj_support, adj_support;
  Univcoord_T left = univdiagonal - querylength;

  assert(start_genomicpos > end_genomicpos);

  if (plusp) {
    debug1(printf("known_spliceends_trim3_sense, plus\n"));
    
    endpoints = Knownsplicing_donors(&low_rank,&high_rank,knownsplicing,
				     univdiagonal,querylength,end_genomicpos - left,start_genomicpos - left);
    debug1(printf("Knownsplicing donors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  end_genomicpos,start_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if ((n = (int) (high_rank - low_rank)) > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      /* Use n, since we cannot test for unsigned rank >= low_rank when low_rank is 0 */
      rank = high_rank - 1;
      while (--n >= 0) { /* For qend, want higher qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank+1] - endpoints[2*rank])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
	rank--;
      }
    }

  } else {
    debug1(printf("known_spliceends_trim3_sense, minus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_antiacceptors(&low_rank,&high_rank,knownsplicing,
					    univdiagonal,querylength,end_genomicpos - left,start_genomicpos - left);
    debug1(printf("Knownsplicing antiacceptors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  end_genomicpos,start_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if ((n = (int) (high_rank - low_rank)) > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      /* Use n, since we cannot test for unsigned rank >= low_rank when low_rank is 0 */
      rank = high_rank - 1;
      while (--n >= 0) { /* For qend, want higher qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank+1] - endpoints[2*rank])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
	rank--;
      }
    }
  }

  if (nspliceends > 0) {
    /* Refine results based on distal mismatches and return univdiagonals */

    /* Need to compute mismatch_positions_right because we are returning medial_nmismatches */
    pos3 = max_spliceend(this->trimends,nspliceends); /* Need to cover all possible splice ends */
    mismatch_positions_right = this->mismatch_positions_right; /* Use allocated memory */
    nmismatches_right = Genomebits_mismatches_fromright(mismatch_positions_right,/*nmismatches_allowed*/querylength,
							/*ome*/genomebits,/*ome_alt*/genomebits_alt,query_compress,
							univdiagonal,querylength,/*pos5*/qstart,pos3,
							plusp,genestrand);
    debug1(
	    printf("(1) %d mismatches on right from %d to %d at:",nmismatches_right,pos3,qstart);
	    for (i = 0; i <= nmismatches_right; i++) {
	      printf(" %d",mismatch_positions_right[i]);
	    }
	    printf("\n");
	    );
    
    debug1(printf("Writing to medial_nmismatches and distal_nmismatches\n"));
    best_adj_support = 0;
    
    for (i = 0; i < nspliceends; i++) {
      splice_qpos = this->trimends[i];
      this->distal_nmismatches[i] =
	Genomebits_count_mismatches_substring(&ref_distal_nmismatches,genomebits,genomebits_alt,query_compress,
					      /*univdiagonal*/this->partners[i] - splice_qpos + querylength,querylength,
					      /*pos5*/splice_qpos,/*pos3*/querylength,plusp,genestrand);
      if ((adj_support = querylength - splice_qpos - 3*this->distal_nmismatches[i]) > best_adj_support) {
	best_adj_support = adj_support;
      }
    }
    
    if (best_adj_support == 0) {
      debug1(printf("Insufficient distal support\n"));
      nspliceends = 0;

    } else {
      debug1(printf("Sufficient distal support of %d\n",best_adj_support));
      k = 0;
      righti = 0;
      for (i = 0; i < nspliceends; i++) {
	splice_qpos = this->trimends[i];
	if (querylength - splice_qpos - 3*this->distal_nmismatches[i] < best_adj_support) {
	  /* Skip */
	} else {
	  while (righti < nmismatches_right && mismatch_positions_right[righti] >= splice_qpos) {
	    righti++;
	  }
	  debug1(printf("(1) For splice_qpos %d, advanced to righti %d, so computing medial_nmismatches as %d - %d = %d\n",
			splice_qpos,righti,nmismatches_right,righti,nmismatches_right - righti));
	
	  this->medial_nmismatches[k] = nmismatches_right - righti;
	  this->matchlengths[k] = querylength - splice_qpos;
	  this->trimends[k] = splice_qpos;
	  this->partners[k] = this->partners[i];
	  this->distal_nmismatches[k] = this->distal_nmismatches[i];
	  this->ambig_probs[k] = 1.0;
	  this->distal_probs[k] = 1.0;

	  k++;
	}
      }
    
      nspliceends = k;
    }
  }

  debug1(printf("knownsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


static int
novel_spliceends_trim3_sense (double *max_prob, bool *partnerp, T this,
			      Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, Univcoord_T middle_genomicpos,
			      int *mismatch_positions, int total_nmismatches,
			      Univcoord_T univdiagonal, int querylength,
			      Compress_T query_compress, char *queryptr,
			      Univcoord_T chroffset, Univcoord_T chrhigh,
			      Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			      int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			      Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			      double medial_splicesite_prob, double distal_splicesite_prob, int max_nconsecutive,
			      bool plusp, int genestrand, int localdb_nmismatches_allowed,
			      bool search_localdb_p, bool innerp, bool salvagep) {
  int nspliceends = 0, k = 0;
  Univcoord_T genomicpos, distal_genomicpos, low_univdiagonal, high_univdiagonal;

  int local_nmismatches, matchlength;
  double donor_prob, acceptor_prob;
  int querypos, pos3, splice_qpos;
  int mismatchi = total_nmismatches;
  int nconsecutive;
  int novel_ndiagonals, i;
  Univcoord_T left = univdiagonal - querylength;

  *max_prob = 0.0;
  *partnerp = false;

  assert(start_genomicpos > end_genomicpos);

  debug1(printf("Start with univdiagonal %u\n",univdiagonal));
  low_univdiagonal = univdiagonal + MIN_INTRON_LENGTH; /* Add so we don't return a continuation */
  debug1(printf("Add %d to yield low_univdiagonal %u\n",MIN_INTRON_LENGTH,low_univdiagonal));
#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos3 = (low_univdiagonal <= chrhigh) ? querylength : (int) (chrhigh - left);
#else
  pos3 = querylength;
#endif
  high_univdiagonal = add_bounded(low_univdiagonal,shortsplicedist_novelend,chrhigh);
  debug1(printf("Add %d (bounded by %u) to yield high_univdiagonal %u\n",
		shortsplicedist_novelend,chrhigh,high_univdiagonal));
  debug1(printf("  (3) shortsplicedist_novelend %u, low %u, high %u\n",
		shortsplicedist_novelend,low_univdiagonal,high_univdiagonal));

  genomicpos = start_genomicpos;
  querypos = genomicpos - left;
  while (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] >= querypos) {
    mismatchi--;
  }

  if (low_univdiagonal > high_univdiagonal) {
    /* Skip */

  } else if (plusp) {
    debug1(printf("novel_spliceends_trim3_sense, plus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos > middle_genomicpos) {
      donor_prob = Maxent_hr_donor_prob(genomicpos,chroffset); /* Case 1 */
      debug1(printf("3' plus, sense forward %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,donor_prob));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0.0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0.0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else {
	  debug1(printf("(9) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_acceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
    }
      
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos > end_genomicpos && nconsecutive < max_nconsecutive) {
      donor_prob = Maxent_hr_donor_prob(genomicpos,chroffset); /* Case 1 */
      debug1(printf("3' plus, sense forward %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,donor_prob,nconsecutive));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else {
	  debug1(printf("(10) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_acceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));

  } else {
    debug1(printf("novel_spliceends_trim3_sense, minus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos > middle_genomicpos) {
      acceptor_prob = Maxent_hr_antiacceptor_prob(genomicpos,chroffset); /* Case 5 */
      debug1(printf("3' minus, sense forward %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,acceptor_prob));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else {
	  debug1(printf("(11) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_antidonor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
    }
    
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos > end_genomicpos && nconsecutive < max_nconsecutive) {
      acceptor_prob = Maxent_hr_antiacceptor_prob(genomicpos,chroffset); /* Case 5 */
      debug1(printf("3' minus, sense forward %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,acceptor_prob,nconsecutive));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else {
	  debug1(printf("(12) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_antidonor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));
  }

  debug1(printf("k = %d\n",k));
  if (k == 0) {
    /* Skip */
    nspliceends = 0;

  } else if (innerp == false) {
    /* Keep only the best spliceends (max_prob should distinguish partner from non-partner) */
    for (i = 0; i < k; i++) {
      if (this->ambig_probs[i] + this->distal_probs[i] == *max_prob) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else if (*partnerp == true) {
    /* Keep all partner ends for later resolving of ambiguity */
    for (i = 0; i < k; i++) {
      if (this->partners[i] != 0) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else {
    /* Keep the most distal inner splice end */
    nspliceends = 1;
  }

  debug1(printf("novelsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


/* Stores information in trimends and partners */
static int
known_spliceends_trim3_anti (T this, Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, int qstart, int qend,
			     Compress_T query_compress, Univcoord_T univdiagonal, int querylength,
			     Knownsplicing_T knownsplicing, bool plusp, int genestrand) {
  int nspliceends = 0, n, i, k;
  Univcoord_T *endpoints;
  uint64_t low_rank, high_rank, rank;

  int *mismatch_positions_right, pos3;
  int ref_distal_nmismatches, splice_qpos;
  int nmismatches_right, righti;
  int best_adj_support, adj_support;
  Univcoord_T left = univdiagonal - querylength;

  assert(start_genomicpos > end_genomicpos);

  if (plusp) {
    debug1(printf("known_spliceends_trim3_anti, plus\n"));
    
    endpoints = Knownsplicing_antiacceptors(&low_rank,&high_rank,knownsplicing,
					    univdiagonal,querylength,end_genomicpos - left,start_genomicpos - left);
    debug1(printf("Knownsplicing antiacceptors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  end_genomicpos,start_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if ((n = (int) (high_rank - low_rank)) > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      /* Use n, since we cannot test for unsigned rank >= low_rank when low_rank is 0 */
      rank = high_rank - 1;
      while (--n >= 0) { /* For qend, want higher qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank+1] - endpoints[2*rank])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
	rank--;
      }
    }

  } else {
    debug1(printf("known_spliceends_trim3_anti, minus\n"));

    /* Previously had middle_genomicpos to start_genomicpos, but new rank procedure requres them to be ascending */
    endpoints = Knownsplicing_donors(&low_rank,&high_rank,knownsplicing,
				     univdiagonal,querylength,end_genomicpos - left,start_genomicpos - left);
    debug1(printf("Knownsplicing donors at %u..%u yields low_rank %lu to high_rank %lu\n",
		  end_genomicpos,start_genomicpos,low_rank,high_rank));
    /* Don't collapse duplicate endpoints, because we care about the partners */
    if ((n = (int) (high_rank - low_rank)) > MAX_NSPLICEENDS) {
      /* Skip */
    } else {
      /* Use n, since we cannot test for unsigned rank >= low_rank when low_rank is 0 */
      rank = high_rank - 1;
      while (--n >= 0) { /* For qend, want higher qpos first */
	debug1(printf("Rank #%lu at qpos %d: %u..%u (splice distance %u)\n",
		      rank,/*splice_pos*/endpoints[2*rank] - left,
		      endpoints[2*rank],endpoints[2*rank+1],
		      (Chrpos_T) (endpoints[2*rank+1] - endpoints[2*rank])));
	this->trimends[nspliceends] = endpoints[2*rank] - left;
	this->partners[nspliceends++] = endpoints[2*rank+1];
	rank--;
      }
    }
  }
  
  if (nspliceends > 0) {
    /* Refine results based on distal mismatches and return univdiagonals */

    /* Need to compute mismatch_positions_right because we are returning medial_nmismatches */
    pos3 = max_spliceend(this->trimends,nspliceends); /* Need to cover all possible splice ends */
    mismatch_positions_right = this->mismatch_positions_right; /* Use allocated memory */
    nmismatches_right = Genomebits_mismatches_fromright(mismatch_positions_right,/*nmismatches_allowed*/querylength,
							/*ome*/genomebits,/*ome_alt*/genomebits_alt,query_compress,
							univdiagonal,querylength,/*pos5*/qstart,pos3,
							plusp,genestrand);
    debug1(
	    printf("(2) %d mismatches on right from %d to %d at:",nmismatches_right,pos3,qstart);
	    for (i = 0; i <= nmismatches_right; i++) {
	      printf(" %d",mismatch_positions_right[i]);
	    }
	    printf("\n");
	    );
    

    debug1(printf("Writing to medial_nmismatches and distal_nmismatches\n"));
    best_adj_support = 0;
    
    for (i = 0; i < nspliceends; i++) {
      splice_qpos = this->trimends[i];
      this->distal_nmismatches[i] =
	Genomebits_count_mismatches_substring(&ref_distal_nmismatches,genomebits,genomebits_alt,query_compress,
					      /*univdiagonal*/this->partners[i] - splice_qpos + querylength,querylength,
					      /*pos5*/splice_qpos,/*pos3*/querylength,plusp,genestrand);
      if ((adj_support = querylength - splice_qpos - 3*this->distal_nmismatches[i]) > best_adj_support) {
	best_adj_support = adj_support;
      }
    }
    
    if (best_adj_support == 0) {
      debug1(printf("Insufficient distal support\n"));
      nspliceends = 0;

    } else {
      debug1(printf("Sufficient distal support of %d\n",best_adj_support));
      k = 0;
      righti = 0;
      for (i = 0; i < nspliceends; i++) {
	splice_qpos = this->trimends[i];
	if (querylength - splice_qpos - 3*this->distal_nmismatches[i] < best_adj_support) {
	  /* Skip */
	} else {
	  while (righti < nmismatches_right && mismatch_positions_right[righti] >= splice_qpos) {
	    righti++;
	  }
	  debug1(printf("For (2) splice_qpos %d, advanced to righti %d, so computing medial_nmismatches as %d - %d = %d\n",
			splice_qpos,righti,nmismatches_right,righti,nmismatches_right - righti));
	  
	  this->medial_nmismatches[k] = nmismatches_right - righti;
	  this->matchlengths[k] = querylength - splice_qpos;
	  this->trimends[k] = splice_qpos;
	  this->partners[k] = this->partners[i];
	  this->distal_nmismatches[k] = this->distal_nmismatches[i];
	  this->ambig_probs[k] = 1.0;
	  this->distal_probs[k] = 1.0;

	  k++;
	}
      }
      
      nspliceends = k;
    }
  }

  debug1(printf("knownsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


static int
novel_spliceends_trim3_anti (double *max_prob, bool *partnerp, T this,
			     Univcoord_T end_genomicpos, Univcoord_T start_genomicpos, Univcoord_T middle_genomicpos,
			     int *mismatch_positions, int total_nmismatches,
			     Univcoord_T univdiagonal, int querylength,
			     Compress_T query_compress, char *queryptr,
			     Univcoord_T chroffset, Univcoord_T chrhigh,
			     Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			     int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			     Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			     double medial_splicesite_prob, double distal_splicesite_prob, int max_nconsecutive,
			     bool plusp, int genestrand, int localdb_nmismatches_allowed,
			     bool search_localdb_p, bool innerp, bool salvagep) {
  int nspliceends = 0, k = 0;
  Univcoord_T genomicpos, distal_genomicpos, low_univdiagonal, high_univdiagonal;

  int local_nmismatches, matchlength;
  double donor_prob, acceptor_prob;
  int querypos, pos3, splice_qpos;
  int mismatchi = total_nmismatches;
  int nconsecutive;
  int novel_ndiagonals, i;
  Univcoord_T left = univdiagonal - querylength;

  *max_prob = 0.0;
  *partnerp = false;

  assert(start_genomicpos > end_genomicpos);

  debug1(printf("Start with univdiagonal %u\n",univdiagonal));
  low_univdiagonal = univdiagonal + MIN_INTRON_LENGTH; /* Add so we don't return a continuation */
  debug1(printf("Add %d to yield low_univdiagonal %u\n",MIN_INTRON_LENGTH,low_univdiagonal));
#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos3 = (low_univdiagonal <= chrhigh) ? querylength : (int) (chrhigh - left);
#else
  pos3 = querylength;
#endif
  high_univdiagonal = add_bounded(low_univdiagonal,shortsplicedist_novelend,chrhigh);
  debug1(printf("Add %d (bounded by %u) to yield high_univdiagonal %u\n",
		shortsplicedist_novelend,chrhigh,high_univdiagonal));
  debug1(printf("  (4) shortsplicedist_novelend %u, low %u, high %u\n",
		shortsplicedist_novelend,low_univdiagonal,high_univdiagonal));

  genomicpos = start_genomicpos;
  querypos = genomicpos - left;
  while (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] >= querypos) {
    mismatchi--;
  }

  if (low_univdiagonal > high_univdiagonal) {
    /* Skip */

  } else if (plusp) {
    debug1(printf("novel_spliceends_trim3_anti, plus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos > middle_genomicpos) {
      acceptor_prob = Maxent_hr_antiacceptor_prob(genomicpos,chroffset); /* Case 5 */
      debug1(printf("3' plus, sense anti %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,acceptor_prob));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }
#endif

	} else {
	  debug1(printf("(13) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_antidonor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
    }
      
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos > end_genomicpos && nconsecutive < max_nconsecutive) {
      acceptor_prob = Maxent_hr_antiacceptor_prob(genomicpos,chroffset); /* Case 5 */
      debug1(printf("3' plus, sense anti %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,acceptor_prob,nconsecutive));
      if (acceptor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = acceptor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (acceptor_prob > *max_prob) {
	    *max_prob = acceptor_prob;
	  }

	} else {
	  debug1(printf("(14) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    donor_prob = Maxent_hr_antidonor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],donor_prob));
	    if (donor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = acceptor_prob;
	      this->distal_probs[k++] = donor_prob;
	      if (acceptor_prob + donor_prob > *max_prob) {
		*max_prob = acceptor_prob + donor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));

  } else {
    debug1(printf("novel_spliceends_trim3_anti, minus\n"));

    /* Region from start_genomicpos to middle_genomicpos: require a partner */
    while (k < MAX_NSPLICEENDS && genomicpos > middle_genomicpos) {
      donor_prob = Maxent_hr_donor_prob(genomicpos,chroffset); /* Case 1 */
      debug1(printf("3' minus, sense anti %u %u %d %f distal\n",
		     genomicpos,genomicpos-chroffset,genomicpos-left,donor_prob));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
#ifdef ALLOW_DISTAL_PARTNER
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
#ifdef ALLOW_DISTAL_PARTNER
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }
#endif

	} else {
	  debug1(printf("(15) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_acceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	mismatchi--;
      }
    }
    
    /* Region from middle_genomicpos to end_genomicpos: do not require a partner */
    assert(querypos == (int) (genomicpos - left));
    nconsecutive = 0;
    /* was (nconsecutive < max_nconsecutive || k == 0) */
    while (k < MAX_NSPLICEENDS && genomicpos > end_genomicpos && nconsecutive < max_nconsecutive) {
      donor_prob = Maxent_hr_donor_prob(genomicpos,chroffset); /* Case 1 */
      debug1(printf("3' minus, sense anti %u %u %d %f.  nconsecutive %d\n",
		     genomicpos,genomicpos-chroffset,querypos,donor_prob,nconsecutive));
      if (donor_prob >= medial_splicesite_prob) {
	splice_qpos = genomicpos - left;
	debug1(printf("Testing splice_qpos %d with mismatchi %d\n",splice_qpos,mismatchi));
	if (search_localdb_p == false) {
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if ((novel_ndiagonals = Localdb_get(&matchlength,&local_nmismatches,novel_diagonals_alloc,localdb,
						   localdb_alloc,streamspace_max_alloc,streamspace_alloc,
						   streamptr_alloc,streamsize_alloc,mergeinfo,
						   queryptr,/*pos5*/splice_qpos,pos3,querylength,low_univdiagonal,high_univdiagonal,
						   query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,salvagep)) == 0) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got no novel diagonals\n"));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else if (k + novel_ndiagonals > MAX_NSPLICEENDS) {
	  /* Mark as a trimming position without a partner */
	  debug1(printf("Got %d localdb diagonals, but too many\n",novel_ndiagonals));
	  this->matchlengths[k] = 0;
	  this->trimends[k] = splice_qpos;
	  this->medial_nmismatches[k] = mismatchi;

	  this->partners[k] = 0;
	  this->distal_nmismatches[k] = -1;
	  this->ambig_probs[k] = donor_prob;
	  this->distal_probs[k++] = 0.0;
	  if (donor_prob > *max_prob) {
	    *max_prob = donor_prob;
	  }

	} else {
	  debug1(printf("(16) Got %d localdb diagonals with matchlength %d and local_nmismatches %d\n",
			novel_ndiagonals,matchlength,local_nmismatches));
	  for (i = 0; i < novel_ndiagonals; i++) {
	    distal_genomicpos = novel_diagonals_alloc[i] - querylength + splice_qpos;
	    acceptor_prob = Maxent_hr_acceptor_prob(distal_genomicpos,chroffset);
	    debug1(printf("%u %f\n",novel_diagonals_alloc[i],acceptor_prob));
	    if (acceptor_prob >= distal_splicesite_prob) {
	      this->matchlengths[k] = matchlength;
	      this->trimends[k] = splice_qpos;
	      this->medial_nmismatches[k] = mismatchi;

	      this->partners[k] = distal_genomicpos;
	      this->distal_nmismatches[k] = local_nmismatches;
	      this->ambig_probs[k] = donor_prob;
	      this->distal_probs[k++] = acceptor_prob;
	      if (donor_prob + acceptor_prob > *max_prob) {
		*max_prob = donor_prob + acceptor_prob;
	      }
	      *partnerp = true;
	    }
	  }
	}
      }

      querypos--;
      genomicpos--;
      if (mismatchi - 1 >= 0 && mismatch_positions[mismatchi - 1] == querypos) {
	nconsecutive = 0;
	mismatchi--;
      } else {
	nconsecutive++;
      }
    }
    /* *end_genomicpos = genomicpos; */
    debug1(printf("\n"));
  }

  debug1(printf("k = %d\n",k));
  if (k == 0) {
    /* Skip */
    nspliceends = 0;

  } else if (innerp == false) {
    /* Keep only the best spliceends (max_prob should distinguish partner from non-partner) */
    for (i = 0; i < k; i++) {
      if (this->ambig_probs[i] + this->distal_probs[i] == *max_prob) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else if (*partnerp == true) {
    /* Keep all partner ends for later resolving of ambiguity */
    for (i = 0; i < k; i++) {
      if (this->partners[i] != 0) {
	this->matchlengths[nspliceends] = this->matchlengths[i];
	this->trimends[nspliceends] = this->trimends[i];
	this->medial_nmismatches[nspliceends] = this->medial_nmismatches[i];
	this->partners[nspliceends] = this->partners[i];
	this->distal_nmismatches[nspliceends] = this->distal_nmismatches[i];
	this->ambig_probs[nspliceends] = this->ambig_probs[i];
	this->distal_probs[nspliceends++] = this->distal_probs[i];
      }
    }

  } else {
    /* Keep the most distal inner splice end */
    nspliceends = 1;
  }

  debug1(printf("novelsplicing yielded %d spliceends\n",nspliceends));
  return nspliceends;
}


static T
trim_3 (bool *partnerp, Compress_T query_compress, char *queryptr,
	Knownsplicing_T knownsplicing, int try_sensedir,
	Univcoord_T univdiagonal, int querylength,
	int qstart, int qend, int pos3, int exon_origin,
	Univcoord_T chroffset, Univcoord_T chrhigh,
	int *mismatch_positions, int total_nmismatches,
	Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
	int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
	Univcoord_T **streamptr_alloc, int *streamsize_alloc,
	Mergeinfo_T mergeinfo, Spliceendsgen_T spliceendsgen,
	int max_nconsecutive, bool plusp, int genestrand, int localdb_nmismatches_allowed,
	bool search_localdb_p, bool innerp, bool salvagep) {
  T new, anti;
  int found_sensedir;
  int qdistal;
  int mismatchi;
  int nspliceends = 0, n_sense_spliceends, n_anti_spliceends;
  Univcoord_T start_genomicpos, middle_genomicpos, end_genomicpos;
  double max_sense_prob = 0.0, max_antisense_prob = 0.0;
  bool sense_partnerp, antisense_partnerp;
  double medial_splicesite_prob, distal_splicesite_prob;
  Univcoord_T left = univdiagonal - querylength;


  debug1(printf("\nEntered trim_3 with try_sensedir %d, qstart %d to qend %d\n",
		 try_sensedir,qstart,qend));

  if (salvagep == true) {
    medial_splicesite_prob = SALVAGE_MEDIAL_SPLICESITE_PROB;
    distal_splicesite_prob = SALVAGE_DISTAL_SPLICESITE_PROB;
  } else {
    medial_splicesite_prob = DEFAULT_MEDIAL_SPLICESITE_PROB;
    distal_splicesite_prob = DEFAULT_DISTAL_SPLICESITE_PROB;
  }

  /* Search from qend - END_SPLICESITE_SEARCH, but not past qstart, to
     qend + END_SPLICESITE_SEARCH_MM */
  middle_genomicpos = left + qend;

  debug1(
	 printf("%d mismatches from qstart %d up to pos3 %d:",total_nmismatches,qstart,pos3);
	 for (int i = 0; i <= total_nmismatches; i++) {
	   printf(" %d",mismatch_positions[i]);
	 }
	 printf("\n");
	 );


  /* middle_genomicpos is where the current trim is.  Previously
     added END_SPLICESITE_SEARCH_MM, but now allowing some number
     of mismatches distally to get to start_genomicpos */
  mismatchi = 0;
  while (mismatchi < total_nmismatches && mismatch_positions[mismatchi] < qend) {
    mismatchi++;
  }

  if (mismatchi + distal_nmismatches_allowed >= total_nmismatches) {
    qdistal = pos3;
    debug1(printf("qdistal = pos3 %d\n",qdistal));
  } else {
    qdistal = mismatch_positions[mismatchi + distal_nmismatches_allowed];
    debug1(printf("qdistal = mismatch position %d\n",qdistal));
  }
  if (qdistal == querylength) {
    /* Don't need to evaluate at the end of the read */
    qdistal = querylength - 1;
  }

#if 0
  if ((start_genomicpos = middle_genomicpos + END_SPLICESITE_SEARCH_MM) > left + querylength) {
    start_genomicpos = left + querylength;
  }
#else
  start_genomicpos = left + qdistal;
#endif

  if (middle_genomicpos < left + qstart + END_SPLICESITE_SEARCH) {
    end_genomicpos = left + qstart;
  } else {
    end_genomicpos = middle_genomicpos - END_SPLICESITE_SEARCH;
  }

#ifdef TRIM_AT_GENOME_BOUNDS
  if (left + qstart + MIN_EXON_LENGTH >= genomelength) {
    /* At end of genome, so don't add MIN_EXON_LENGTH */
  } else if (end_genomicpos < left + exon_origin + MIN_EXON_LENGTH) {
    end_genomicpos = left + exon_origin + MIN_EXON_LENGTH;
  }
#else
  if (end_genomicpos < left + exon_origin + MIN_EXON_LENGTH) {
    end_genomicpos = left + exon_origin + MIN_EXON_LENGTH;
  }
#endif

  debug1(printf("\n1 Set end points for 3' trim to be %u..%u..%u\n",
		 start_genomicpos,middle_genomicpos,end_genomicpos));

  if (start_genomicpos <= end_genomicpos) {
    /* Skip */
    debug1(printf("Got no spliceends\n"));
    return (T) NULL;
  } else {
    new = Spliceendsgen_checkout(spliceendsgen,querylength);
  }

  if (try_sensedir == SENSE_FORWARD) {
    if (knownsplicing != NULL &&
	(nspliceends = known_spliceends_trim3_sense(new,end_genomicpos,start_genomicpos,qstart,qend,
						    query_compress,univdiagonal,querylength,
						    knownsplicing,plusp,genestrand)) > 0) {
      *partnerp = true;
      max_sense_prob = 1.0;
    } else {
      nspliceends = novel_spliceends_trim3_sense(&max_sense_prob,&(*partnerp),new,
						 end_genomicpos,start_genomicpos,middle_genomicpos,
						 mismatch_positions,total_nmismatches,univdiagonal,querylength,
						 query_compress,queryptr,chroffset,chrhigh,
						 novel_diagonals_alloc,localdb_alloc,
						 streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						 medial_splicesite_prob,distal_splicesite_prob,
						 max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						 search_localdb_p,innerp,salvagep);
    }
    found_sensedir = SENSE_FORWARD;

  } else if (try_sensedir == SENSE_ANTI) {
    if (knownsplicing != NULL &&
	(nspliceends = known_spliceends_trim3_anti(new,end_genomicpos,start_genomicpos,qstart,qend,
						   query_compress,univdiagonal,querylength,
						   knownsplicing,plusp,genestrand)) > 0) {
      *partnerp = true;
      max_antisense_prob = 1.0;
    } else {
      nspliceends = novel_spliceends_trim3_anti(&max_antisense_prob,&(*partnerp),new,
						end_genomicpos,start_genomicpos,middle_genomicpos,
						mismatch_positions,total_nmismatches,univdiagonal,querylength,
						query_compress,queryptr,chroffset,chrhigh,
						novel_diagonals_alloc,localdb_alloc,
						streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						medial_splicesite_prob,distal_splicesite_prob,
						max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						search_localdb_p,innerp,salvagep);
    }
    found_sensedir = SENSE_ANTI;

  } else {
    /* SENSE_NULL */
    anti = Spliceendsgen_checkout(spliceendsgen,querylength);
    if (knownsplicing != NULL &&
	(n_sense_spliceends = known_spliceends_trim3_sense(new,end_genomicpos,start_genomicpos,qstart,qend,
							   query_compress,univdiagonal,querylength,
							   knownsplicing,plusp,genestrand)) > 0) {
      sense_partnerp = true;
      max_sense_prob = 1.0;
    } else {
      n_sense_spliceends = novel_spliceends_trim3_sense(&max_sense_prob,&sense_partnerp,new,
							end_genomicpos,start_genomicpos,middle_genomicpos,
							mismatch_positions,total_nmismatches,univdiagonal,querylength,
							query_compress,queryptr,chroffset,chrhigh,
							novel_diagonals_alloc,localdb_alloc,
							streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
							medial_splicesite_prob,distal_splicesite_prob,
							max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
							search_localdb_p,innerp,salvagep);
    }

    if (knownsplicing != NULL &&
	(n_anti_spliceends = known_spliceends_trim3_anti(anti,end_genomicpos,start_genomicpos,qstart,qend,
							 query_compress,univdiagonal,querylength,
							 knownsplicing,plusp,genestrand)) > 0) {
      antisense_partnerp = true;
      max_antisense_prob = 1.0;
    } else {
      nspliceends = novel_spliceends_trim3_anti(&max_antisense_prob,&antisense_partnerp,anti,
						end_genomicpos,start_genomicpos,middle_genomicpos,
						mismatch_positions,total_nmismatches,univdiagonal,querylength,
						query_compress,queryptr,chroffset,chrhigh,
						novel_diagonals_alloc,localdb_alloc,
						streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
						medial_splicesite_prob,distal_splicesite_prob,
						max_nconsecutive,plusp,genestrand,localdb_nmismatches_allowed,
						search_localdb_p,innerp,salvagep);
    }

    if (max_sense_prob > max_antisense_prob) {
      /* Keep information in trimends and segmentj_partners */
      *partnerp = sense_partnerp;
      nspliceends = n_sense_spliceends;
      found_sensedir = SENSE_FORWARD;
      Spliceendsgen_return(spliceendsgen,&anti);
    } else if (max_antisense_prob > max_sense_prob) {
      /* Copy information into trimends and segmentj_partners */
      *partnerp = antisense_partnerp;
      nspliceends = n_anti_spliceends;
      found_sensedir = SENSE_ANTI;
      Spliceendsgen_return(spliceendsgen,&new);
      new = anti;
    } else {
      debug1(printf("Cannot distinguish between sense and antisense at end\n"));
      Spliceendsgen_return(spliceendsgen,&anti);
      Spliceendsgen_return(spliceendsgen,&new);
      return (T) NULL;
    }
  }


  if (nspliceends == 0) {
    debug1(printf("Got no spliceends\n"));
    Spliceendsgen_return(spliceendsgen,&new);
    return (T) NULL;

  } else {
    new->nspliceends = nspliceends;
    new->sensedir = found_sensedir;
    if (found_sensedir == SENSE_FORWARD) {
      if (plusp) {
	new->splicetype = DONOR;
      } else {
	new->splicetype = ANTIACCEPTOR;
      }
    } else {
      /* SENSE_ANTI */
      if (plusp) {
	new->splicetype = ANTIACCEPTOR;
      } else {
	new->splicetype = DONOR;
      }
    }

    debug1(printf("trim_3 got %d spliceends\n",nspliceends));
    return new;
  }
}



/* Taken from Substring_trim_qstart_nosplice */
/* Want to return the most distal good region */
int
Spliceends_trim_qstart_nosplice (int *nmismatches_to_trimpos, int *total_nmismatches, int *mismatch_positions_alloc,
				 Compress_T query_compress, Genomebits_T bits, Genomebits_T bits_alt,
				 Univcoord_T univdiagonal, int querylength,
				 int pos5, int pos3, bool plusp, int genestrand) {
  int max_score, score;
  int trimpos = pos5, pos, prevpos, i;
  int *mismatch_positions = mismatch_positions_alloc;
  int alignlength = pos3 - pos5;


  debug6(printf("Entered trim_qstart_nosplice with pos5 %d, pos3 %d, mismatch_scores %d/%d, match_score %d\n",
		pos5,pos3,TRIM_MISMATCH_SCORE_LAST,TRIM_MISMATCH_SCORE_MULT,TRIM_MATCH_SCORE));
  debug6(printf("Calling Genomebits_mismatches_fromright_trim with univdiagonal %u, pos5 %d, pos3 %d, max_mismatches %d\n",
		univdiagonal,pos5,pos3,alignlength));
  *total_nmismatches = Genomebits_mismatches_fromright_trim(mismatch_positions,/*max_mismatches*/alignlength,
							    /*ome*/bits,/*ome_alt*/bits_alt,query_compress,
							    univdiagonal,querylength,pos5,pos3,plusp,genestrand);
  debug6(printf("%d mismatches:",*total_nmismatches));
  debug6(
	 for (i = 0; i <= *total_nmismatches; i++) {
	   printf(" %d",mismatch_positions[i]);
	 }
	 printf("\n");
	 );

  if (allow_soft_clips_p == false) {
    /* Report mismatches and do not soft clip */
    *nmismatches_to_trimpos = -1;
    return 0;
  } else if (*total_nmismatches == 0) {
    *nmismatches_to_trimpos = 0;
    return pos5;
  }

  /* pos3 | mismatch_positions | (pos5 - 1) */
  prevpos = pos3;
  trimpos = pos = mismatch_positions[0];
  /* Don't add mismatch initially because we stop before the mismatch */
  max_score = score = (prevpos - pos - 1)*TRIM_MATCH_SCORE /*+ TRIM_MISMATCH_SCORE_MULT*/;
  *nmismatches_to_trimpos = 0;
  debug6(printf("Initialize trimpos to be %d with 0 nmismatches and score %d\n",trimpos,score));
  prevpos = pos;

  for (i = 1; i < *total_nmismatches; i++) {
    pos = mismatch_positions[i];
    score += TRIM_MISMATCH_SCORE_MULT;
    score += (prevpos - pos - 1)*TRIM_MATCH_SCORE;
    debug6(printf("pos %d, score %d",pos,score));
    if (score >= max_score) {
      debug6(printf(" **"));
      trimpos = pos;
      *nmismatches_to_trimpos = i;
      max_score = score;
    }
    debug6(printf("\n"));
    prevpos = pos;
  }
    
  if (*nmismatches_to_trimpos == (*total_nmismatches) - 1) {
    /* If last mismatch compensated for previous, then take the last
       segment, regardless of whether it compensates for the last
       mismatch */
    trimpos = pos5 - 1;
    *nmismatches_to_trimpos += 1;

  } else {
    /* See if last segment compensates */
    pos = pos5 - 1;
    score += TRIM_MISMATCH_SCORE_MULT;
    score += (prevpos - pos - 1)*TRIM_MATCH_SCORE;
    debug6(printf("pos %d, score %d",pos,score));
    if (score >= max_score) {
      debug6(printf(" **"));
      trimpos = pos;
      *nmismatches_to_trimpos = i;
      max_score = score;
    }
    debug6(printf("\n"));
    /* prevpos = pos; */
  }

  return trimpos + 1;		/* One position after the mismatch for qstart */

#if 0
  if (trimpos != 0) { /* trimpos + 1 != 1 */
    debug6(printf("Final qstart pos %d => trimpos %d, nmismatches_to_trimpos %d\n",pos,trimpos+1,*nmismatches_to_trimpos));
    return trimpos + 1;		/* One position after the mismatch */
  } else {
    /* For DNA-seq or RNA-seq, if still within chromosome, accept the initial mismatch at the beginning of the read */
    debug6(printf("Backing up 1 bp to start => trimpos %d, nmismatches_to_trimpos %d+1\n",0,*nmismatches_to_trimpos));
    *nmismatches_to_trimpos += 1;
    return 0;			/* trimpos + 1 - 1 */
  }
#endif
}



/* Returns number of spliceends found.  If a partner is found, then returns spliceendsgen */
int
Spliceends_trimmed_qstarts (T *new, int *nosplice_trimpos, int *farsplice_trimpos,
			    int *pos5_nmismatches, int *nosplice_nmismatches, int *farsplice_nmismatches,
			    bool *splice5p, Splicetype_T *splicetype5, double *ambig_prob_5,
			    int try_sensedir, Univcoord_T univdiagonal, int querylength,
			    int qend, int exon_origin, Chrnum_T chrnum, Univcoord_T chroffset,
			    bool plusp, int genestrand, int localdb_nmismatches_allowed, bool innerp, bool salvagep,
			    int *mismatch_positions_alloc, Univcoord_T *novel_diagonals_alloc,
			    unsigned short *localdb_alloc, int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			    Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			    Knownsplicing_T knownsplicing, Spliceendsgen_T spliceendsgen,
			    Compress_T query_compress, char *queryptr,
			    Genomebits_T genomebits, Genomebits_T genomebits_alt, bool novelsplicingp) {
  int pos5;
  bool partnerp;
  bool search_localdb_p;

  search_localdb_p = (localdb == NULL) ? false : true;

  debug8(printf("\n***Entered Spliceends_trimmed_qstarts with univdiagonal %u, qend %d..%d, plusp %d, try_sensedir %d\n",
		univdiagonal-chroffset,0,qend,plusp,try_sensedir));

  /* left = univdiagonal - (Univcoord_T) querylength; */

  *farsplice_trimpos = -1;
  *farsplice_nmismatches = 0;
  *splice5p = false; *splicetype5 = NO_SPLICE; *ambig_prob_5 = 0.0;

#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos5 = (univdiagonal >= chroffset + (Univcoord_T) querylength) ? 0 : (int) (chroffset - left);
#else
  pos5 = 0;
#endif

  if (pos5 >= qend) {
    debug8(printf("trimpos %d >= qend %d, so returning -1\n",pos5,qend));
    /* No spliceends.  No trimming. */
    *nosplice_trimpos = pos5;
    return 0;

  } else {
    /* Note: This procedure allows for 1 mismatch at the start of the read, so we don't need to handle it here */
    *nosplice_trimpos =
      Spliceends_trim_qstart_nosplice(&(*nosplice_nmismatches),&(*pos5_nmismatches),
				      mismatch_positions_alloc,query_compress,
				      /*bits*/genomebits,/*bits_alt*/genomebits_alt,
				      univdiagonal,querylength,
				      pos5,/*pos3*/qend,plusp,genestrand);
    debug8(printf("nosplice: trimpos %d (relative to %d)\n",*nosplice_trimpos,pos5));
  }

  if (*nosplice_trimpos >= qend) {
    debug8(printf("trimpos %d >= qend %d, so returning -1\n",*nosplice_trimpos,qend));
    /* No spliceends.  No trimming. */
    return 0;

  } else if (knownsplicing == NULL && novelsplicingp == false) {
    /* No spliceends.  Found a trim. */
    debug8(printf("Keeping given trim because splicingp is false\n"));
    *new = (T) NULL;
    return 1;

#ifdef DISALLOW_CIRCULAR_SPLICING
  } else if (circularp[chrnum] == true) {
    /* No spliceends.  Found a trim. */
    debug8(printf("Keeping given trim because chrnum %d is circular\n",chrnum));
    *new = (T) NULL;
    return 1;
#endif

  } else {
    /* Want this because it is equivalent to having peelback */
    debug8(printf("Finding splice based on trim_5 on trimpos %d to qend %d\n",*nosplice_trimpos,qend));
    if ((*new = trim_5(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
		       univdiagonal,querylength,pos5,/*qstart*/*nosplice_trimpos,qend,exon_origin,chroffset,
		       mismatch_positions_alloc,/*total_nmismatches*/*pos5_nmismatches,
		       novel_diagonals_alloc,localdb_alloc,
		       streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
		       spliceendsgen,MAX_NCONSECUTIVE_FAR,
		       plusp,genestrand,localdb_nmismatches_allowed,search_localdb_p,
		       innerp,salvagep)) != NULL) {
      *farsplice_trimpos = (*new)->trimends[0];
      *farsplice_nmismatches = (*new)->medial_nmismatches[0];

      *splice5p = true; *splicetype5 = (*new)->splicetype; *ambig_prob_5 = (*new)->ambig_probs[0];
      if (partnerp == true) {
	debug8(printf("found spliceends with partner\n"));
	return (*new)->nspliceends;
      } else {
	debug8(printf("found spliceends without partner\n"));
	Spliceendsgen_return(spliceendsgen,&(*new));
	*new = (T) NULL;
	return 1;
      }

    } else {
      /* No spliceends.  Found a trim. */
      debug8(printf("spliceends is NULL\n"));
      return 1;
    }
  }
}


/* TODO: Find the best splice site near the nosplice trimpos,
   regardless of probability.  Then these splice sites can be used in
   two-pass mode to use this site, regardless of probability */

/* Cannot return -1 for trimpos, because caller needs to use its value */
bool
Spliceends_qstart_trim (int *trimpos, int *nmismatches_to_trimpos,
			int *found_sensedir, Splicetype_T *splicetype, double *ambig_prob_qstart,
			Knownsplicing_T knownsplicing, int try_sensedir,
			Univcoord_T univdiagonal, int querylength,
			int pos3, int exon_origin, Chrnum_T chrnum, Univcoord_T chroffset,
			bool plusp, int genestrand, int *mismatch_positions_alloc,
			Spliceendsgen_T spliceendsgen, Compress_T query_compress, char *queryptr,
			Genomebits_T genomebits, Genomebits_T genomebits_alt,
			bool novelsplicingp) {
  T spliceends;
  int pos5;
  int total_nmismatches;
  bool partnerp;


  *found_sensedir = try_sensedir;
  /* left = univdiagonal - (Univcoord_T) querylength; */

#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos5 = (univdiagonal >= chroffset + (Univcoord_T) querylength) ? 0 : (int) (chroffset - left);
#else
  pos5 = 0;
#endif
  debug8(printf("\n***Entered Spliceends_qstart_trim with univdiagonal %u, pos5 %d, pos3 %d, plusp %d, try_sensedir %d\n",
		univdiagonal,pos5,pos3,plusp,try_sensedir));

  if (pos5 >= pos3) {
    debug8(printf("pos5 %d >= pos3 %d, so returning pos3\n",pos5,pos3));
    *trimpos = pos3;
    *splicetype = NO_SPLICE;
    *ambig_prob_qstart = 0.0;
    return false;

  } else {
    /* Note: This procedure allows for 1 mismatch at the start of the read, so we don't need to handle it here */
    *trimpos = Spliceends_trim_qstart_nosplice(&(*nmismatches_to_trimpos),&total_nmismatches,
					       mismatch_positions_alloc,query_compress,
					       /*bits*/genomebits,/*bits_alt*/genomebits_alt,
					       univdiagonal,querylength,
					       pos5,pos3,plusp,genestrand);
    debug8(printf("nosplice trimpos %d (relative to %d)\n",*trimpos,pos5));
  }

  if (*trimpos >= pos3) {
    debug8(printf("trimpos %d >= pos3 %d, so returning pos3\n",*trimpos,pos3));
    *trimpos = pos3;
    *splicetype = NO_SPLICE;
    *ambig_prob_qstart = 0.0;
    return false;

  } else if (*trimpos == pos5) {
    /* Use trimpos, which extends to the start, which could be longer than the caller had */
    debug8(printf("Using trimpos %d, which extends to the start, pos5 %d\n",*trimpos,pos5));
    *splicetype = NO_SPLICE;
    *ambig_prob_qstart = 0.0;
    return false;

  } else if (knownsplicing == NULL && novelsplicingp == false) {
    /* Keep given trim */
    debug8(printf("Keeping given trim because splicingp is false\n"));
    *splicetype = NO_SPLICE;
    *ambig_prob_qstart = 0.0;
    return false;

#ifdef DISALLOW_CIRCULAR_SPLICING
  } else if (circularp[chrnum] == true) {
    /* Keep given trim */
    debug8(printf("Keeping given trim because chrnum %d is circular\n",chrnum));
    *splicetype = NO_SPLICE;
    *ambig_prob_qstart = 0.0;
    return false;
#endif

#if 0
  } else if (0 && *trimpos <= pos5 + ACCEPTABLE_TRIM) {
    debug8(printf("Accepting splice based on trim_5 on pos5 %d to pos3 %d\n",pos5,pos3));
    if ((spliceends = trim_5(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
			     unifdiagonal,querylength,pos5,qstart,/*qend*/pos3,exon_origin,chroffset,
			     mismatch_positions_alloc,total_nmismatches,
			     /*novel_diagonals_alloc*/NULL,/*localdb_alloc*/NULL,
			     /*streamspace_max_alloc*/0,/*streamspace_alloc*/NULL,
			     /*streamptr_alloc*/NULL,/*streamsize_alloc*/NULL,/*mergeinfo*/NULL,
			     spliceendsgen,MAX_NCONSECUTIVE_CLOSE,
			     plusp,genestrand,/*localdb_nmismatches_allowed*/querylength,/*search_localdb_p*/false,
			     /*innerp*/false,/*salvagep*/false)) != NULL) {
      /* TODO: Make sure this is the farthest one */
      *found_sensedir = spliceends->sensedir;
      *trimpos = spliceends->trimends[0];
      *nmismatches_to_trimpos = spliceends->medial_nmismatches[0];
      *splicetype = spliceends->splicetype;
      *ambig_prob_qstart = spliceends->ambig_probs[0];
      Spliceendsgen_return(spliceendsgen,&spliceends);
      debug8(printf("found spliceends at trimpos %d with %d nmismatches\n",*trimpos,*nmismatches_to_trimpos));
      return true;

    } else {
      debug8(printf("spliceends is NULL, but multiple mismatches at the end => trimpos %d\n",*trimpos));
      *splicetype = NO_SPLICE;
      *ambig_prob_qstart = 0.0;
      return false;
    }
#endif
    
  } else {
    debug8(printf("Finding splice based on trim_5 on trimpos %d to pos3 %d\n",*trimpos,pos3));
    if ((spliceends = trim_5(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
			     univdiagonal,querylength,pos5,
			     /*qstart*/(*trimpos),/*qend*/pos3,exon_origin,chroffset,
			     mismatch_positions_alloc,total_nmismatches,
			     /*novel_diagonals_alloc*/NULL,/*localdb_alloc*/NULL,
			     /*streamspace_max_alloc*/0,/*streamspace_alloc*/NULL,
			     /*streamptr_alloc*/NULL,/*streamsize_alloc*/NULL,/*mergeinfo*/NULL,
			     spliceendsgen,MAX_NCONSECUTIVE_FAR,
			     plusp,genestrand,/*localdb_nmismatches_allowed*/querylength,/*search_localdb_p*/false,
			     /*innerp*/false,/*salvagep*/false)) != NULL) {
      /* TODO: Make sure this is the farthest one */
      *found_sensedir = spliceends->sensedir;
      *trimpos = spliceends->trimends[0];
      *nmismatches_to_trimpos = spliceends->medial_nmismatches[0];
      *splicetype = spliceends->splicetype;
      *ambig_prob_qstart = spliceends->ambig_probs[0];
      Spliceendsgen_return(spliceendsgen,&spliceends);
      debug8(printf("found spliceends at trimpos %d with %d nmismatches\n",*trimpos,*nmismatches_to_trimpos));
      return true;
      
    } else {
      /* Keep given trim */
      debug8(printf("spliceends is NULL\n"));
      *splicetype = NO_SPLICE;
      *ambig_prob_qstart = 0.0;
      return false;
    }
  }
}


/* Taken from Substring_trim_qend_nosplice */
/* Want to return the most distal good region */
int
Spliceends_trim_qend_nosplice (int *nmismatches_to_trimpos, int *total_nmismatches, int *mismatch_positions_alloc,
			       Compress_T query_compress, Genomebits_T bits, Genomebits_T bits_alt,
			       Univcoord_T univdiagonal, int querylength,
			       int pos5, int pos3, bool plusp, int genestrand) {
  int max_score, score;
  int trimpos = pos3, pos, prevpos, i;
  int *mismatch_positions = mismatch_positions_alloc;
  int alignlength = pos3 - pos5;


  debug6(printf("Entered trim_qend_nosplice with pos5 %d, pos3 %d, mismatch_scores %d/%d, match_score %d\n",
		pos5,pos3,TRIM_MISMATCH_SCORE_LAST,TRIM_MISMATCH_SCORE_MULT,TRIM_MATCH_SCORE));
  debug6(printf("Calling Genomebits_mismatches_fromleft_trim with univdiagonal %u, pos5 %d, pos3 %d, max_mismatches %d\n",
		univdiagonal,pos5,pos3,alignlength));
  *total_nmismatches = Genomebits_mismatches_fromleft_trim(mismatch_positions,/*max_mismatches*/alignlength,
							   /*ome*/bits,/*ome_alt*/bits_alt,query_compress,
							   univdiagonal,querylength,pos5,pos3,plusp,genestrand);

  debug6(printf("%d mismatches:",*total_nmismatches));
  debug6(
	 for (i = 0; i <= *total_nmismatches; i++) {
	   printf(" %d",mismatch_positions[i]);
	 }
	 printf("\n");
	 );

  if (allow_soft_clips_p == false) {
    /* Report mismatches and do not soft clip */
    *nmismatches_to_trimpos = -1;
    return querylength;
  } else if (*total_nmismatches == 0) {
    *nmismatches_to_trimpos = 0;
    return pos3;
  }

  /* (pos5 - 1) | mismatch_positions | pos3 */
  prevpos = pos5 - 1;
  trimpos = pos = mismatch_positions[0];
  /* Don't add mismatch initially because we stop before the mismatch */
  max_score = score = (pos - prevpos - 1)*TRIM_MATCH_SCORE /*+ TRIM_MISMATCH_SCORE_MULT*/;
  *nmismatches_to_trimpos = 0;
  debug6(printf("Initialize trimpos to be %d with 0 nmismatches and score %d\n",trimpos,score));
  prevpos = pos;

  for (i = 1; i < *total_nmismatches; i++) {
    pos = mismatch_positions[i];
    score += TRIM_MISMATCH_SCORE_MULT;
    score += (pos - prevpos - 1)*TRIM_MATCH_SCORE;
    debug6(printf("pos %d, score %d",pos,score));
    if (score >= max_score) {
      debug6(printf(" **"));
      trimpos = pos;
      *nmismatches_to_trimpos = i;
      max_score = score;
    }
    debug6(printf("\n"));
    prevpos = pos;
  }
  
  if (*nmismatches_to_trimpos == (*total_nmismatches) - 1) {
    /* If last mismatch compensated for previous, then take the last
       segment, regardless of whether it compensates for the last
       mismatch */
    trimpos = pos3;
    *nmismatches_to_trimpos += 1;
  } else {
    /* See if last segment compensates */
    pos = pos3;
    score += TRIM_MISMATCH_SCORE_MULT;
    score += (pos - prevpos - 1)*TRIM_MATCH_SCORE;
    debug6(printf("pos %d, score %d",pos,score));
    if (score >= max_score) {
      debug6(printf(" **"));
      trimpos = pos;
      *nmismatches_to_trimpos = i;
      max_score = score;
    }
    debug6(printf("\n"));
    /* prevpos = pos; */
  }

  return trimpos;		/* At the mismatch for qend */
  
#if 0
  if (trimpos != querylength - 1) {
    debug6(printf("Final qend pos %d => trimpos %d, nmismatches_to_trimpos %d\n",pos,trimpos,*nmismatches_to_trimpos));
    return trimpos;		/* qend is outside the region */
  } else {
    /* For DNA-seq or RNA-seq, if still within the chromosome, accept the final mismatch at end of read */
    debug6(printf("Advancing 1 bp to end => trimpos %d, nmismatches_to_trimpos %d+1\n",querylength,*nmismatches_to_trimpos));
    *nmismatches_to_trimpos += 1;
    return querylength;
  }
#endif
}


/* Returns number of spliceends found.  If a partner is found, then returns spliceendsgen */
int
Spliceends_trimmed_qends (T *new, int *nosplice_trimpos, int *farsplice_trimpos,
			  int *pos3_nmismatches, int *nosplice_nmismatches, int *farsplice_nmismatches,
			  bool *splice3p, Splicetype_T *splicetype3, double *ambig_prob_3,
			  int try_sensedir, Univcoord_T univdiagonal, int querylength,
			  int qstart, int exon_origin, Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
			  bool plusp, int genestrand, int localdb_nmismatches_allowed, bool innerp, bool salvagep,
			  int *mismatch_positions_alloc, Univcoord_T *novel_diagonals_alloc,
			  unsigned short *localdb_alloc, int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			  Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			  Knownsplicing_T knownsplicing, Spliceendsgen_T spliceendsgen,
			  Compress_T query_compress, char *queryptr,
			  Genomebits_T genomebits, Genomebits_T genomebits_alt, bool novelsplicingp) {
  int pos3;
  bool partnerp;
  bool search_localdb_p;

  search_localdb_p = (localdb == NULL) ? false : true;

  debug8(printf("\n***Entered Spliceends_trimmed_qends with univdiagonal %u, qstart %d..%d, plusp %d, try_sensedir %d\n",
		univdiagonal-chroffset,qstart,querylength,plusp,try_sensedir));

  /* left = univdiagonal - (Univcoord_T) querylength; */

#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos3 = (univdiagonal <= chrhigh) ? querylength : (int) (chrhigh - left);
#else
  pos3 = querylength;
#endif

  *farsplice_trimpos = -1;
  *farsplice_nmismatches = 0;
  *splice3p = false; *splicetype3 = NO_SPLICE; *ambig_prob_3 = 0.0;

  if (pos3 <= qstart) {
    debug8(printf("pos3 %d <= qstart %d, so returning -1\n",pos3,qstart));
    /* No spliceends.  No trimming. */
    *nosplice_trimpos = pos3;
    return 0;

  } else {
    /* Note: This procedure allows for 1 mismatch at the end of the read, so we don't need to handle it here */
    *nosplice_trimpos =
      Spliceends_trim_qend_nosplice(&(*nosplice_nmismatches),&(*pos3_nmismatches),
				    mismatch_positions_alloc,query_compress,
				    /*bits*/genomebits,/*bits_alt*/genomebits_alt,
				    univdiagonal,querylength,
				    /*pos5*/qstart,pos3,plusp,genestrand);
    debug8(printf("nosplice: trimpos %d (relative to %d)\n",*nosplice_trimpos,pos3));
  }

  if (*nosplice_trimpos <= qstart) {
    debug8(printf("trimpos %d <= qstart %d, so returning -1\n",*nosplice_trimpos,qstart));
    /* No spliceends.  No trimming. */
    return 0;

  } else if (knownsplicing == NULL && novelsplicingp == false) {
    /* No spliceends.  Found a trim. */
    debug8(printf("Keeping given trim because splicingp is false\n"));
    *new = (T) NULL;
    return 1;

#ifdef DISALLOW_CIRCULAR_SPLICING
  } else if (circularp[chrnum] == true) {
    /* No spliceends.  Found a trim. */
    debug8(printf("Keeping given trim because chrnum %d is circular\n",chrnum));
    *new = (T) NULL;
    return 1;
#endif

  } else {
    /* Want this because it is equivalent to peelback */
    debug8(printf("Finding splice based on trim_3 from qstart %d to trimpos %d\n",qstart,*nosplice_trimpos));
    if ((*new = trim_3(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
		       univdiagonal,querylength,
		       qstart,/*qend*/*nosplice_trimpos,pos3,exon_origin,
		       chroffset,chrhigh,mismatch_positions_alloc,/*total_nmismatches*/*pos3_nmismatches,
		       novel_diagonals_alloc,localdb_alloc,
		       streamspace_max_alloc,streamspace_alloc,streamptr_alloc,streamsize_alloc,mergeinfo,
		       spliceendsgen,MAX_NCONSECUTIVE_FAR,
		       plusp,genestrand,localdb_nmismatches_allowed,search_localdb_p,
		       innerp,salvagep)) != NULL) {
      *farsplice_trimpos = (*new)->trimends[0];
      *farsplice_nmismatches = (*new)->medial_nmismatches[0];

      *splice3p = true; *splicetype3 = (*new)->splicetype; *ambig_prob_3 = (*new)->ambig_probs[0];
      if (partnerp == true) {
	debug8(printf("found spliceends with partner\n"));
	return (*new)->nspliceends;
      } else {
	debug8(printf("found spliceends without partner\n"));
	Spliceendsgen_return(spliceendsgen,&(*new));
	*new = (T) NULL;
	return 1;
      }

    } else {
      /* No spliceends.  Found a trim. */
      debug8(printf("spliceends is NULL\n"));
      *new = (T) NULL;
      return 1;
    }
  }
}


/* TODO: Find the best splice site near the nosplice trimpos,
   regardless of probability.  Then these splice sites can be used in
   two-pass mode to use this site, regardless of probability */

/* Cannot return -1 for trimpos, because caller needs to use its value */
bool
Spliceends_qend_trim (int *trimpos, int *nmismatches_to_trimpos,
		      int *found_sensedir, Splicetype_T *splicetype, double *ambig_prob_qend,
		      Knownsplicing_T knownsplicing, int try_sensedir,
		      Univcoord_T univdiagonal, int querylength, int pos5,
		      int exon_origin, Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
		      bool plusp, int genestrand, int *mismatch_positions_alloc,
		      Spliceendsgen_T spliceendsgen, Compress_T query_compress, char *queryptr,
		      Genomebits_T genomebits, Genomebits_T genomebits_alt, bool novelsplicingp) {
  T spliceends;
  int pos3;
  int total_nmismatches;
  bool partnerp;

  *found_sensedir = try_sensedir;

  /* left = univdiagonal - (Univcoord_T) querylength; */

#ifdef TRIM_AT_CHROMOSOME_BOUNDS
  pos3 = (univdiagonal <= chrhigh) ? querylength : (int) (chrhigh - left);
#else
  pos3 = querylength;
#endif
  debug8(printf("\n***Entered Spliceends_qend_trim with univdiagonal %u, pos5 %d, pos3 %d, plusp %d, try_sensedir %d\n",
		univdiagonal,pos5,pos3,plusp,try_sensedir));

  if (pos3 <= pos5) {
    debug8(printf("trimpos %d <= pos5 %d, so returning pos5\n",*trimpos,pos5));
    *trimpos = pos5;
    *splicetype = NO_SPLICE;
    *ambig_prob_qend = 0.0;
    return false;

  } else {
    /* Note: This procedure allows for 1 mismatch at the start of the read, so we don't need to handle it here */
    *trimpos = Spliceends_trim_qend_nosplice(&(*nmismatches_to_trimpos),&total_nmismatches,
					     mismatch_positions_alloc,query_compress,
					     /*bits*/genomebits,/*bits_alt*/genomebits_alt,
					     univdiagonal,querylength,
					     pos5,pos3,plusp,genestrand);
    debug8(printf("nosplice trimpos %d (relative to %d)\n",*trimpos,pos3));
  }

  if (*trimpos <= pos5) {
    debug8(printf("trimpos %d <= pos5 %d, so returning -1\n",*trimpos,pos5));
    *trimpos = pos5;
    *splicetype = NO_SPLICE;
    *ambig_prob_qend = 0.0;
    return false;

  } else if (*trimpos == pos3) {
    /* Use trimpos, which extends to the end, which could be longer than the caller had */
    debug8(printf("Using trimpos %d, which extends to the end, pos3 %d\n",*trimpos,pos3));
    *splicetype = NO_SPLICE;
    *ambig_prob_qend = 0.0;
    return false;

  } else if (knownsplicing == NULL && novelsplicingp == false) {
    /* Keep given trim */
    debug8(printf("Keeping given trim because splicingp is false\n"));
    *splicetype = NO_SPLICE;
    *ambig_prob_qend = 0.0;
    return false;

#ifdef DISALLOW_CIRCULAR_SPLICING
  } else if (circularp[chrnum] == true) {
    /* Keep given trim */
    debug8(printf("Keeping given trim because chrnum %d is circular\n",chrnum));
    *splicetype = NO_SPLICE;
    *ambig_prob_qend = 0.0;
    return false;
#endif

#if 0
  } else if (0 && *trimpos >= pos3 - ACCEPTABLE_TRIM) {
    debug8(printf("Accepting splice based on trim_3 from pos5 %d to pos3 %d\n",pos5,pos3));
    if ((spliceends = trim_3(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
			     univdiagonal,querylength,/*qstart*/pos5,qend,pos3,exon_origin,
			     chroffset,chrhigh,mismatch_positions_alloc,total_nmismatches,
			     /*novel_diagonals_alloc*/NULL,/*localdb_alloc*/NULL,
			     /*streamspace_max_alloc*/0,/*streamspace_alloc*/NULL,
			     /*streamptr_alloc*/NULL,/*streamsize_alloc*/NULL,/*mergeinfo*/NULL,
			     spliceendsgen,MAX_NCONSECUTIVE_CLOSE,
			     plusp,genestrand,/*localdb_nmismatches_allowed*/0,/*search_localdb_p*/false,
			     /*innerp*/false,/*salvagep*/false)) != NULL) {
      /* TODO: Make sure this is the farthest one */
      *found_sensedir = spliceends->sensedir;
      *trimpos = spliceends->trimends[0];
      *nmismatches_to_trimpos = spliceends->medial_nmismatches[0];
      *splicetype = spliceends->splicetype;
      *ambig_prob_qend = spliceends->ambig_probs[0];
      Spliceendsgen_return(spliceendsgen,&spliceends);
      debug8(printf("found spliceends at trimpos %d and %d nmismatches\n",*trimpos,*nmismatches_to_trimpos));
      return true;

    } else {
      debug8(printf("spliceends is NULL, but multiple mismatches at the end => trimpos %d\n",*trimpos));
      *splicetype = NO_SPLICE;
      *ambig_prob_qend = 0.0;
      return false;
    }
#endif

  } else {
    debug8(printf("Finding splice based on trim_3 from pos5 %d to trimpos %d\n",pos5,*trimpos));
    if ((spliceends = trim_3(&partnerp,query_compress,queryptr,knownsplicing,try_sensedir,
			     univdiagonal,querylength,
			     /*qstart*/pos5,/*qend*/*trimpos,pos3,exon_origin,
			     chroffset,chrhigh,mismatch_positions_alloc,total_nmismatches,
			     /*novel_diagonals_alloc*/NULL,/*localdb_alloc*/NULL,
			     /*streamspace_max_alloc*/0,/*streamspace_alloc*/NULL,
			     /*streamptr_alloc*/NULL,/*streamsize_alloc*/NULL,/*mergeinfo*/NULL,
			     spliceendsgen,MAX_NCONSECUTIVE_FAR,
			     plusp,genestrand,/*localdb_nmismatches_allowed*/0,/*search_localdb_p*/false,
			     /*innerp*/false,/*salvagep*/false)) != NULL) {
      /* TODO: Make sure this is the farthest one */
      *found_sensedir = spliceends->sensedir;
      *trimpos = spliceends->trimends[0];
      *nmismatches_to_trimpos = spliceends->medial_nmismatches[0];
      *splicetype = spliceends->splicetype;
      *ambig_prob_qend = spliceends->ambig_probs[0];
      Spliceendsgen_return(spliceendsgen,&spliceends);
      debug8(printf("found spliceends at trimpos %d and %d nmismatches\n",*trimpos,*nmismatches_to_trimpos));
      return true;

    } else {
      /* Keep given trim */
      debug8(printf("spliceends is NULL\n"));
      *splicetype = NO_SPLICE;
      *ambig_prob_qend = 0.0;
      return false;
    }
  }
}


Univcoord_T
Spliceends_qstart_resolve (int *local_nmismatches, int pos3, int querylength,
			   Univcoord_T low_univdiagonal, Univcoord_T high_univdiagonal,
			   Compress_T query_compress, char *queryptr, bool plusp, int genestrand,
			   Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			   int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			   Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			   int localdb_nmismatches_allowed) {
  int ndiagonals;
  int matchlength;

  /* Not sure whether to use nmismatches_allowed instead of 0 */
  /* TODO: Use Boyer-Moore instead */
  /* Called only after Path_extend, so we have already tried salvage
     mode over a large region.  Here are relying on a small region
     near the anchor end, so we can require few mismatches */
  /* Want nmismatches_allowed based on the fragment, not the entire
     read.  This value is ignored for salvage mode anyway. */

  /* Setting salvagep to be true results in very slow speed */
  debug3(printf("\nEntered Spliceends_qstart_resolve with querystart 0 to pos3 %d\n",pos3));
  if (localdb == NULL) {
    /* No localdb present */
    return (Univcoord_T) 0;

  } else if ((ndiagonals = Localdb_get(&matchlength,&(*local_nmismatches),novel_diagonals_alloc,localdb,
				       localdb_alloc,streamspace_max_alloc,streamspace_alloc,
				       streamptr_alloc,streamsize_alloc,mergeinfo,
				       queryptr,/*pos5*/0,pos3,querylength,low_univdiagonal,high_univdiagonal,
				       query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,
				       /*salvagep*/false)) != 1) {
    debug3(printf("multiple ndiagonals %d\n\n",ndiagonals));
    return (Univcoord_T) 0;

  } else {
    debug3(printf("Returning univdiagonal %u with local_nmismatches %d\n\n",
		  novel_diagonals_alloc[0],*local_nmismatches));
    return novel_diagonals_alloc[0];
  }
}


Univcoord_T
Spliceends_qend_resolve (int *local_nmismatches, int pos5, int querylength,
			 Univcoord_T low_univdiagonal, Univcoord_T high_univdiagonal,
			 Compress_T query_compress, char *queryptr, bool plusp, int genestrand,
			 Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
			 int streamspace_max_alloc, Univcoord_T *streamspace_alloc,
			 Univcoord_T **streamptr_alloc, int *streamsize_alloc, Mergeinfo_T mergeinfo,
			 int localdb_nmismatches_allowed) {
  int ndiagonals;
  int matchlength;

  /* Not sure whether to use nmismatches_allowed instead of 0 */
  /* TODO: Use Boyer-Moore instead */
  /* Called only after Path_extend, so we have already tried salvage
     mode over a large region.  Here are relying on a small region
     near the anchor end, so we can require few mismatches */
  /* Want nmismatches_allowed based on the fragment, not the entire
     read.  This value is ignored for salvage mode anyway. */

  /* Setting salvagep to be true results in very slow speed */
  debug3(printf("\nEntered Spliceends_qend_resolve with pos5 %d to querylength %d\n",pos5,querylength));
  if (localdb == NULL) {
    /* No localdb present */
    return (Univcoord_T) 0;

  } else if ((ndiagonals = Localdb_get(&matchlength,&(*local_nmismatches),novel_diagonals_alloc,localdb,
				       localdb_alloc,streamspace_max_alloc,streamspace_alloc,
				       streamptr_alloc,streamsize_alloc,mergeinfo,
				       queryptr,pos5,/*pos3*/querylength,querylength,low_univdiagonal,high_univdiagonal,
				       query_compress,plusp,genestrand,genomebits,localdb_nmismatches_allowed,
				       /*salvagep*/false)) != 1) {
    debug3(printf("multiple ndiagonals %d\n\n",ndiagonals));
    return (Univcoord_T) 0;

  } else {
    debug3(printf("Returning univdiagonal %u with local_nmismatches %d\n\n",
		  novel_diagonals_alloc[0],*local_nmismatches));
    return novel_diagonals_alloc[0];
  }
}

