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

#include "path.h"

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

#include "mem.h"
#include "assert.h"
#include "transcript.h"

#include "sedgesort.h"
#include "genomebits_count.h"


static bool *circularp;
static bool *altlocp;


#define ENDTRIM_ALLOWED 4


#ifdef DEBUG0
#define debug0(x) x
#else
#define debug0(x)
#endif

/* Path_print */
/* Also, need to define DEBUG1 in junction.c */
#ifdef DEBUG1
#define debug1(x) x
#else
#define debug1(x)
#endif

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

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

/* Path_common_structure_p */
#ifdef DEBUG5
#define debug5(x) x
#else
#define debug5(x)
#endif


#define T Path_T


/* TODO: Consider whether we need to check ambig_prob_5 and
   ambig_prob_3, since they are supposed to be incorporated into
   splice_prob in Path_nmatches */
int
Path_effective_sensedir (T this) {
  List_T p;

  if (this->qstart_alts != NULL) {
    return this->sensedir;
  } else if (this->qend_alts != NULL) {
    return this->sensedir;
  } else if (this->splicetype5 != NO_SPLICE) {
    return this->sensedir;
  } else if (this->splicetype3 != NO_SPLICE) {
    return this->sensedir;
  } else {
    for (p = this->junctions; p != NULL; p = List_next(p)) {
      if (Junction_type((Junction_T) List_head(p)) == SPLICE_JUNCTION) {
	return this->sensedir;
      }
    }
    return SENSE_NULL;
  }
}


int
Path_coverage (T this) {
  int pos5, pos3, fusion_coverage;

  if (this->qstart_alts != NULL) {
    pos5 = 0;
  } else {
    pos5 = Intlist_head(this->endpoints);
  }
  if (this->qend_alts != NULL) {
    pos3 = this->querylength;
  } else {
    pos3 = Intlist_last_value(this->endpoints);
  }
  
  if (this->fusion_querystart_junction != NULL) {
    fusion_coverage = Intlist_last_value(this->fusion_endpoints) - Intlist_head(this->fusion_endpoints);
  } else if (this->fusion_queryend_junction != NULL) {
    fusion_coverage = Intlist_last_value(this->fusion_endpoints) - Intlist_head(this->fusion_endpoints);
  } else {
    fusion_coverage = 0;
  }

  return pos3 - pos5 + fusion_coverage;
}


bool
Path_softclippedp (T this) {
  if (Intlist_head(this->endpoints) > 0) {
    return true;
  } else if (this->querylength - Intlist_last_value(this->endpoints) > 0) {
    return true;
  } else {
    return false;
  }
}


bool
Path_resolved_qstart_p (T this) {
  /* Presence of qstart_alts means not resolved, and implies endpoint is not 0 */
  if (Intlist_head(this->endpoints) == 0) {
    return true;
  } else if (this->plusp == true && this->fusion_querystart_junction != NULL) {
    return true;
  } else if (this->plusp == false && this->fusion_queryend_junction != NULL) {
    return true;
  } else {
    return false;
  }
}


bool
Path_resolved_qend_p (T this) {
  /* Presence of qend_alts means not resolved, and implies endpoint is not querylength */
  if (Intlist_last_value(this->endpoints) == this->querylength) {
    return true;
  } else if (this->plusp == true && this->fusion_queryend_junction != NULL) {
    return false;
  } else if (this->plusp == false && this->fusion_querystart_junction != NULL) {
    return false;
  } else {
    return false;
  }
}


bool
Path_unextended_qstart_p (T this, int endtrim_allowed, bool allow_ambig_p) {
  /* printf("Path_unextended_qstart_p => "); */
  if (this->qstart_alts != NULL) {
    /* printf("qstart_alts => false\n"); */
    return false;
  } else if (this->plusp == true && this->fusion_querystart_junction != NULL) {
    /* printf("fusion_querystart => false\n"); */
    return false;
  } else if (this->plusp == false && this->fusion_queryend_junction != NULL) {
    /* printf("fusion_queryend => false\n"); */
    return false;
  } else if (allow_ambig_p == true && this->splice5p == true) {
    /* printf("ambig5 => false\n"); */
    return false;
  } else if (Intlist_head(this->endpoints) <= endtrim_allowed) {
    /* printf("endpoints %d => false\n",Intlist_head(this->endpoints)); */
    return false;
  } else {
    /* printf("true\n"); */
    return true;
  }
}


bool
Path_unextended_qend_p (T this, int endtrim_allowed, bool allow_ambig_p) {
  if (this->qend_alts != NULL) {
    return false;
  } else if (this->plusp == true && this->fusion_queryend_junction != NULL) {
    return false;
  } else if (this->plusp == false && this->fusion_querystart_junction != NULL) {
    return false;
  } else if (allow_ambig_p == true && this->splice3p == true) {
    return false;
  } else if (this->querylength - Intlist_last_value(this->endpoints) <= endtrim_allowed) {
    return false;
  } else {
    return true;
  }
}


bool
Path_unextended_querystart_p (T this, int endtrim_allowed, bool allow_ambig_p) {
  if (this->plusp == true) {
    return Path_unextended_qstart_p(this,endtrim_allowed,allow_ambig_p);
  } else {
    return Path_unextended_qend_p(this,endtrim_allowed,allow_ambig_p);
  }
}


bool
Path_unextended_queryend_p (T this, int endtrim_allowed, bool allow_ambig_p) {
  if (this->plusp == true) {
    return Path_unextended_qend_p(this,endtrim_allowed,allow_ambig_p);
  } else {
    return Path_unextended_qstart_p(this,endtrim_allowed,allow_ambig_p);
  }
}


bool
Path_unextendedp (T this, int endtrim_allowed, bool allow_ambig_p) {
  if (this->transcriptome_method_p == true) {
    return false;
  } else if (Path_unextended_qstart_p(this,endtrim_allowed,allow_ambig_p) == true) {
    return true;
  } else if (Path_unextended_qend_p(this,endtrim_allowed,allow_ambig_p) == true) {
    return true;
  } else {
    return false;
  }
}

bool
Path_unsolvedp (T this) {
  List_T p;

  for (p = this->junctions; p != NULL; p = List_next(p)) {
    if ((Junction_T) List_head(p) == JUNCTION_UNSOLVED) {
      return true;
    }
  }

  return false;
}


/* Used for NM:i in SAM output */
int
Path_ndiffs (T this) {
  int nmismatches, nindels = 0;
  List_T j;

  nmismatches = this->score_within_trims;
  for (j = this->junctions; j != NULL; j = List_next(j)) {
    /* Insertions and deletions count as one mismatch per base */
    nindels += Junction_nindels((Junction_T) List_head(j));
  }

  return nmismatches + nindels;
}



Chrpos_T
Path_chrlength (T this) {
  if (this == NULL) {
    /* Can happen if we call upon a mate in a halfmapping */
    return 0;
  } else if (circularp[this->chrnum] == true) {
    return (this->chrhigh - this->chroffset)/2;
  } else {
    return (this->chrhigh - this->chroffset);
  }
}


#if 0
/* To consider splice junctions, sites, or alts, use Path_effective_sensedir */
int
Path_sensedir (T this) {
  List_T j;
  Junction_T junction;

  if (this->qstart_alts != NULL) {
    return this->sensedir;
  } else if (this->qend_alts != NULL) {
    return this->sensedir;
  } else {
    for (j = this->junctions; j != NULL; j = List_next(j)) {
      junction = (Junction_T) List_head(j);
      if (Junction_type(junction) == SPLICE_JUNCTION) {
	return this->sensedir;
      }
    }
    return SENSE_NULL;
  }
}
#endif
    

int
Path_genomiclow_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;

  Univcoord_T genomiclow_x = Path_genomiclow(a);
  Univcoord_T genomiclow_y = Path_genomiclow(b);

  if (genomiclow_x < genomiclow_y) {
    return -1;
  } else if (genomiclow_y < genomiclow_x) {
    return +1;
  } else {
    return 0;
  }
}


int
Path_genomichigh_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;

  Univcoord_T genomichigh_x = Path_genomichigh(a);
  Univcoord_T genomichigh_y = Path_genomichigh(b);

  if (genomichigh_x < genomichigh_y) {
    return -1;
  } else if (genomichigh_y < genomichigh_x) {
    return +1;
  } else {
    return 0;
  }
}


int
Path_interval_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;
  Univcoord_T genomiclow_x, genomiclow_y,
    genomichigh_x, genomichigh_y;

  genomiclow_x = Path_genomiclow(a);
  genomiclow_y = Path_genomiclow(b);

  if (genomiclow_x < genomiclow_y) {
    return -1;
  } else if (genomiclow_y < genomiclow_x) {
    return +1;
  } else {
    genomichigh_x = Path_genomichigh(a);
    genomichigh_y = Path_genomichigh(b);
    if (genomichigh_x > genomichigh_y) {
      return -1;
    } else if (genomichigh_y > genomichigh_x) {
      return +1;
    } else {
      return 0;
    }
  }
}


int
Path_structure_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;
  Univcoordlist_T p, q;

  if (a->sensedir > b->sensedir) {
    return -1;
  } else if (b->sensedir > a->sensedir) {
    return +1;
  } else {
    p = a->univdiagonals;
    q = b->univdiagonals;

    while (p != NULL && q != NULL) {
      if (Univcoordlist_head(p) < Univcoordlist_head(q)) {
	return -1;
      } else if (Univcoordlist_head(q) < Univcoordlist_head(p)) {
	return +1;
      } else {
	p = Univcoordlist_next(p);
	q = Univcoordlist_next(q);
      }
    }

    if (p == NULL && q == NULL) {
      return 0;
    } else if (p == NULL) {
      return -1;
    } else {
      return +1;
    }
  }
}


static int
Path_local_sort_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;

  if (a->nmatches > b->nmatches) {
    return -1;
  } else if (b->nmatches > a->nmatches) {
    return +1;
  } else if (a->junction_splice_prob > b->junction_splice_prob) {
    return -1;
  } else if (b->junction_splice_prob > a->junction_splice_prob) {
    return +1;
  } else if (a->method > b->method) {
    return -1;
  } else if (b->method > a->method) {
    return +1;
  } else {
    return 0;
  }
}


/* Called only by stage1hr-paired */
static int
optimal_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;

  if (a->nmatches > b->nmatches) {
    return -1;
  } else if (b->nmatches > a->nmatches) {
    return +1;
  } else if (a->junction_splice_prob > b->junction_splice_prob) {
    return -1;
  } else if (b->junction_splice_prob > a->junction_splice_prob) {
    return +1;
  } else if (a->method > b->method) {
    return -1;
  } else if (b->method > a->method) {
    return +1;
  } else {
    return 0;
  }
}


static bool
Path_identical_mind_sensedir_p (T a, T b) {
  if (a->sensedir != b->sensedir) {
    return false;
  } else if (a->nmatches != b->nmatches) {
    return false;
  } else if (a->junction_splice_prob != b->junction_splice_prob) {
    return false;
  } else if (a->method != b->method) {
    return false;
  } else {
    return true;
  }
}

static bool
Path_identical_ignore_sensedir_p (T a, T b) {
  if (a->nmatches != b->nmatches) {
    return false;
  } else if (a->junction_splice_prob != b->junction_splice_prob) {
    return false;
  } else if (a->method != b->method) {
    return false;
  } else {
    return true;
  }
}


bool
Path_overlap_p (T x, T y) {
  Univcoord_T genomiclow_x, genomiclow_y,
    genomichigh_x, genomichigh_y;

  genomiclow_x = Path_genomiclow(x);
  genomiclow_y = Path_genomiclow(y);
  genomichigh_x = Path_genomichigh(x);
  genomichigh_y = Path_genomichigh(y);
  
  if (genomichigh_x < genomiclow_y) {
    return false;
  } else if (genomichigh_y < genomiclow_x) {
    return false;
  } else {
    return true;
  }
}


int
Path_max_trim (T this) {
  int overall_qstart, overall_qend;

  overall_qstart = Intlist_head(this->endpoints);
  overall_qend = Intlist_last_value(this->endpoints);
  if (overall_qstart > this->querylength - overall_qend) {
    return overall_qstart;
  } else {
    return this->querylength - overall_qend;
  }
}


/* Called only by stage1hr-paired */
/* Removes duplicates and subsumed paths.  Keeps both sensedirs, but
   called only on lists of a single sensedir anyway */
/* Frees paths, so needs to be called on a stage1 list and returned to a stage1 list */
List_T
Path_filter (List_T paths, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	     Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool,
	     Hitlistpool_T hitlistpool) {
  List_T list;
  T *array, path;
  Univcoord_T genomichigh;
  int n, i, j, k;

  if ((n = List_length(paths)) == 0) {
    return (List_T) NULL;

  } else {
    list = NULL;

    array = (T *) List_to_array(paths,NULL);
    qsort(array,n,sizeof(T),Path_interval_cmp);

    k = 0;
    i = 0;
    while (i < n) {
      genomichigh = Path_genomichigh(array[i]);
      j = i + 1;
      while (j < n && Path_genomiclow(array[j]) <= genomichigh) {
	j++;
      }

      if (j - i > 1) {
	qsort(&(array[i]),j - i,sizeof(T),optimal_cmp);
      }

      list = Hitlist_push(list,hitlistpool,(void *) array[i]
			  hitlistpool_trace(__FILE__,__LINE__));
      for (k = i + 1; k < j; k++) {
	if (Path_identical_mind_sensedir_p(array[k],array[i]) == true) {
	  path = array[k];
	  Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
	} else if (optimal_cmp(&(array[k]),&(array[i])) == 0) {
	  list = Hitlist_push(list,hitlistpool,(void *) array[k]
			      hitlistpool_trace(__FILE__,__LINE__));
	} else {
	  path = array[k];
	  Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
	}
      }

      i = j;
    }
    FREE(array);
    Hitlistpool_free_list(&paths,hitlistpool
			  hitlistpool_trace(__FILE__,__LINE__));  /* Assigned by Hitlist_push */

    debug0(printf("\n"));
    return List_reverse(list);
  }
}


static int
Path_method_cmp (const void *x, const void *y) {
  T a = * (T *) x;
  T b = * (T *) y;

  if (a->method > b->method) {
    return -1;
  } else if (b->method > a->method) {
    return +1;
  } else {
    return 0;
  }
}


/* Using instead of Path_filter.  Removes only reads that are structurally identical */
List_T
Path_unique (List_T paths, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	     Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool,
	     Hitlistpool_T hitlistpool) {
  List_T list;
  T *patharray, path;
  int n, i, j, l;

  if ((n = List_length(paths)) == 0) {
    return (List_T) NULL;

  } else if (n == 1) {
    return paths;

  } else {
    list = (List_T) NULL;
    patharray = (T *) List_to_array(paths,NULL);
    qsort(patharray,n,sizeof(T),Path_structure_cmp);
    
    i = 0;
    while (i < n) {
      j = i + 1;
      while (j < n && Path_structure_cmp(&(patharray[j]),&(patharray[i])) == 0) {
	j++;
      }
      debug4(printf("Found an identical group by structure (except sensedir) of %d paths => Re-sorting by method_cmp\n",j - i));
      
      qsort(&(patharray[i]),j - i,sizeof(T),Path_method_cmp);
      debug4(printf("(0) Keeping by method_cmp\n")); debug4(Path_print(patharray[i]));
      list = Hitlist_push(list,hitlistpool,(void *) patharray[i]
			  hitlistpool_trace(__FILE__,__LINE__));

      for (l = i + 1; l < j; l++) {
	debug4(printf("(0) Eliminating by method_cmp\n")); debug4(Path_print(patharray[l]));
	path = patharray[l];
	Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
      }

      i = j;
    }
    FREE(patharray);

    debug4(printf("After removing duplicates (except for sensedir), have %d paths\n",List_length(list)));

    return List_reverse(list);
  }
}


void
Path_filter_pick_sensedir (List_T *sense_paths, List_T *antisense_paths, List_T paths,
			   Hitlistpool_T hitlistpool) {
  T *array;
  Univcoord_T genomichigh;
  int n, i, j, k;

  *sense_paths = *antisense_paths = (List_T) NULL;
  if ((n = List_length(paths)) > 0) {
    array = (T *) List_to_array(paths,NULL);
    qsort(array,n,sizeof(T),Path_interval_cmp);

    k = 0;
    i = 0;
    while (i < n) {
      genomichigh = Path_genomichigh(array[i]);
      j = i + 1;
      while (j < n && Path_genomiclow(array[j]) <= genomichigh) {
	j++;
      }

      if (j - i > 1) {
	qsort(&(array[i]),j - i,sizeof(T),optimal_cmp);
      }

      if (array[i]->sensedir == SENSE_FORWARD) {
	*sense_paths = Hitlist_push(*sense_paths,hitlistpool,(void *) array[i]
				    hitlistpool_trace(__FILE__,__LINE__));
      } else {
	*antisense_paths = Hitlist_push(*antisense_paths,hitlistpool,(void *) array[i]
					hitlistpool_trace(__FILE__,__LINE__));
      }

      for (k = i + 1; k < j; k++) {
	if (Path_identical_ignore_sensedir_p(array[k],array[i]) == true) {
	  /* Stage1_free will take care of this at the end */
	  /* path = array[k]; */
	  /* Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool); */
	} else if (optimal_cmp(&(array[k]),&(array[i])) == 0) {
	  if (array[k]->sensedir == SENSE_FORWARD) {
	    *sense_paths = Hitlist_push(*sense_paths,hitlistpool,(void *) array[k]
					hitlistpool_trace(__FILE__,__LINE__));
	  } else {
	    *antisense_paths = Hitlist_push(*antisense_paths,hitlistpool,(void *) array[k]
					    hitlistpool_trace(__FILE__,__LINE__));
	  }
	} else {
	  /* Stage1_free will take care of this at the end */
	  /* path = array[k]; */
	  /* Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool); */
	}
      }

      i = j;
    }
    FREE(array);
    Hitlistpool_free_list(&paths,hitlistpool
			  hitlistpool_trace(__FILE__,__LINE__)); /* Assigned by Hitlist_push */

    debug0(printf("\n"));
  }

  return;
}


/* Picks sensedir only when one is clear */
/* Modeled after the first step in Pathpair_eval_and_sort */
void
Path_local_pick_sensedir (List_T *sense_paths, List_T *antisense_paths, List_T paths,
			  Hitlistpool_T hitlistpool) {

  T *patharray, path;
  int npaths, i, j, l;

  *sense_paths = *antisense_paths = (List_T) NULL;
  if ((npaths = List_length(paths)) > 0) {
    /* Sort by intervals to remove suboptimal at a given locus */
    patharray = (T *) List_to_array(paths,NULL);
    qsort(patharray,npaths,sizeof(T),Path_interval_cmp);

    i = 0;
    while (i < npaths) {
      j = i + 1;
      while (j < npaths && Path_overlap_p(patharray[j],patharray[i]) == true) {
	j++;
      }

      /* Re-sort by Path_local_sort_cmp */
      debug4(printf("Found an overlapping group of %d => re-sorting by Path_local_sort_cmp\n",j - i));
      qsort(&(patharray[i]),j - i,sizeof(T),Path_local_sort_cmp);
      debug4(printf("Keeping ")); debug4(Path_print(patharray[i]));
      path = patharray[i];
      if (path->sensedir == SENSE_FORWARD) {
	*sense_paths = Hitlist_push(*sense_paths,hitlistpool,(void *) path
				    hitlistpool_trace(__FILE__,__LINE__));
      } else {
	*antisense_paths = Hitlist_push(*antisense_paths,hitlistpool,(void *) path
					hitlistpool_trace(__FILE__,__LINE__));
      }

      l = i + 1;
      while (l < j && Path_local_sort_cmp(&(patharray[l]),&(patharray[i])) == 0) {
	debug4(printf("Keeping ")); debug4(Path_print(patharray[i]));
	path = patharray[l];
	if (path->sensedir == SENSE_FORWARD) {
	  *sense_paths = Hitlist_push(*sense_paths,hitlistpool,(void *) path
				      hitlistpool_trace(__FILE__,__LINE__));
	} else {
	  *antisense_paths = Hitlist_push(*antisense_paths,hitlistpool,(void *) path
					  hitlistpool_trace(__FILE__,__LINE__));
	}
	l++;
      }

#if 0
      /* Stage1_free will free these at the end */
      while (l < j) {
	debug4(printf("Eliminating ")); debug4(Path_print(patharray[l]));
	path = patharray[l];
	Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
	l++;
      }
#endif
      
      i = j;
    }
    FREE(patharray);
    Hitlistpool_free_list(&paths,hitlistpool
			  hitlistpool_trace(__FILE__,__LINE__)); /* Assigned by Hitlist_push */

    debug4(printf("\n"));
  }

  return;
}


#if 0
/* Incorporated into Path_filter_pick_sensedir */
void
Path_separate_sensedir (List_T *sense_paths, List_T *antisense_paths,
			List_T paths, Hitlistpool_T hitlistpool) {
  List_T p;
  T path;

  *sense_paths = *antisense_paths = (List_T) NULL;
  for (p = paths; p != NULL; p = List_next(p)) {
    path = (T) List_head(p);
    if (path->sensedir == SENSE_FORWARD) {
      *sense_paths = Hitlist_push(*sense_paths,hitlistpool,(void *) path
				  hitlistpool_trace(__FILE__,__LINE__));
    } else {
      *antisense_paths = Hitlist_push(*antisense_paths,hitlistpool,(void *) path
				      hitlistpool_trace(__FILE__,__LINE__));
    }
  }

  return;
}
#endif


/* Removes duplicates and subsumed paths */
int
Path_filter_array (List_T *duplicates, T *paths, int npaths,
		   Hitlistpool_T hitlistpool) {
  T *out, path;
  Univcoord_T genomichigh;
  int i, j, k;

  if (npaths == 0) {
    return 0;

  } else {
    /* Caller, which is Ladder_paths_for_score, already allocates paths, so just re-use */
    /* out = unique = (T *) MALLOC((npaths+1)*sizeof(T)); */

    qsort(paths,npaths,sizeof(T),Path_interval_cmp);

    out = paths;
    k = 0;
    i = 0;
    while (i < npaths) {
      genomichigh = Path_genomichigh(paths[i]);

      j = i + 1;
      while (j < npaths && Path_genomiclow(paths[j]) <= genomichigh) {
	j++;
      }

      if (j - i > 1) {
	qsort(&(paths[i]),j - i,sizeof(T),optimal_cmp);
      }

      *out++ = paths[i];
      for (k = i + 1; k < j; k++) {
	if (Path_identical_mind_sensedir_p(paths[k],paths[i]) == true) {
	  path = paths[k];
	  /* Path_free(&path); -- newladder and ladder share paths during Concordance_byscore, so store for freeing later */
	  /* printf("Pushing path %p into duplicates\n",path); */
	  *duplicates = Hitlist_push(*duplicates,hitlistpool,(void *) path
				     hitlistpool_trace(__FILE__,__LINE__));
	} else if (optimal_cmp(&(paths[k]),&(paths[i])) == 0) {
	  *out++ = paths[k];
	} else {
	  path = paths[k];
	  /* Path_free(&path); -- newladder and ladder share paths during Concordance_byscore, so store for freeing later */
	  /* printf("Pushing path %p into duplicates\n",path); */
	  *duplicates = Hitlist_push(*duplicates,hitlistpool,(void *) path
				     hitlistpool_trace(__FILE__,__LINE__));
	}
      }

      i = j;
    }

    /* FREE(paths); */

    return out - paths;
  }
}


/* Compares across all loci.  Relies upon effective_sensedir rather than try_sensedir */
List_T
Path_optimal_nmatches (List_T paths, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
		       Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool,
		       Hitlistpool_T hitlistpool) {
  List_T list, p;
  T path;
  int max_nmatches;

  if (List_length(paths) == 0) {
    return (List_T) NULL;

  } else {
    max_nmatches = 0;

    for (p = paths; p != NULL; p = List_next(p)) {
      path = (T) List_head(p);
      if (path->nmatches > max_nmatches) {
	max_nmatches = path->nmatches;
      }
    }

    list = NULL;
    for (p = paths; p != NULL; p = List_next(p)) {
      path = (T) List_head(p);
      if (path->nmatches < max_nmatches) {
	Path_free(&path,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
      } else {
	list = Hitlist_push(list,hitlistpool,(void *) path
			    hitlistpool_trace(__FILE__,__LINE__));
      }
    }

    return List_reverse(list);
  }
}



Univcoord_T *
Path_genomiclows (int *ndiagonals, List_T paths) {
  Univcoord_T *diagonals;
  int n, i, j, k = 0;
  List_T p;
  T path;

  n = List_length(paths);

  /* Need extra entry for Sedgesort */
  diagonals = (Univcoord_T *) MALLOC((n + 1) * sizeof(Univcoord_T));

  for (p = paths; p != NULL; p = List_next(p)) {
    path = (T) List_head(p);
    diagonals[k++] = Path_genomiclow(path);
  }
  
#ifdef LARGE_GENOMES
  Sedgesort_uint8(diagonals,n);
#else
  Sedgesort_uint4(diagonals,n);
#endif

  /* Remove duplicates */
  k = 0;
  i = 0;
  while (i < n) {
    j = i + 1;
    while (j < n && diagonals[j] == diagonals[i]) {
      j++;
    }

    diagonals[k++] = diagonals[i];

    i = j;
  }

  *ndiagonals = k;
  return diagonals;
}


Univcoord_T *
Path_genomichighs (int *ndiagonals, List_T paths) {
  Univcoord_T *diagonals;
  int n, i, j, k = 0;
  List_T p;
  T path;

  n = List_length(paths);

  /* Need extra entry for Sedgesort */
  diagonals = (Univcoord_T *) MALLOC((n + 1) * sizeof(Univcoord_T));

  for (p = paths; p != NULL; p = List_next(p)) {
    path = (T) List_head(p);
    diagonals[k++] = Path_genomichigh(path);
  }
  
#ifdef LARGE_GENOMES
  Sedgesort_uint8(diagonals,n);
#else
  Sedgesort_uint4(diagonals,n);
#endif

  /* Remove duplicates */
  k = 0;
  i = 0;
  while (i < n) {
    j = i + 1;
    while (j < n && diagonals[j] == diagonals[i]) {
      j++;
    }

    diagonals[k++] = diagonals[i];

    i = j;
  }

  *ndiagonals = k;
  return diagonals;
}




T
Path_reverse (T this, bool expect_fwd_p) {
  Intlist_T q;
#ifdef CHECK_ASSERTIONS
  int prev_endpoint;
#endif

  this->endpoints = Intlist_reverse(this->endpoints);
  this->univdiagonals = Univcoordlist_reverse(this->univdiagonals);
  this->nmismatches = Intlist_reverse(this->nmismatches);
  this->ref_nmismatches = Intlist_reverse(this->ref_nmismatches);
  this->junctions = List_reverse(this->junctions);
  
#ifdef CHECK_ASSERTIONS
  if (expect_fwd_p == true) {
    prev_endpoint = Intlist_head(this->endpoints);
    for (q = Intlist_next(this->endpoints); q != NULL; q = Intlist_next(q)) {
      /* Need to use < instead of <= because we allow repeated endpoints in an unsolved path */
      if (Intlist_head(q) < prev_endpoint) {
	printf("Expecting forward, but got\n");
	Path_print(this);
	abort();
      }
      prev_endpoint = Intlist_head(q);
    }
 
 } else {
    prev_endpoint = Intlist_head(this->endpoints);
    for (q = Intlist_next(this->endpoints); q != NULL; q = Intlist_next(q)) {
      /* Need to use > instead of >= because we allow repeated endpoints in an unsolved path */
      if (Intlist_head(q) > prev_endpoint) {
	printf("Expecting reverse, but got\n");
	Path_print(this);
	abort();
      }
      prev_endpoint = Intlist_head(q);
    }
  }
#endif

  return this;
}


/* Sometimes merging of left and right paths can result in anomalies */
/* Same as Trpath_endpoints_acceptable_p */
bool
Path_endpoints_acceptable_p (Intlist_T endpoints, List_T junctions) {
  Intlist_T p;
  List_T q;
  Junction_T junction;
  int last_endpoint;

  debug2(printf("Evaluating endpoints for acceptability: %s\n",Intlist_to_string(endpoints)));

  /* last_endpoint = 0; */
  /* Skip first endpoint */
  for (p = Intlist_next(endpoints), q = junctions; Intlist_next(p) != NULL; p = Intlist_next(p), q = List_next(q)) {
    last_endpoint = Intlist_head(p);
    junction = (Junction_T) List_head(q);
    /* Previously used >=, but a deletion can yield duplicated endpoints */
    if (last_endpoint + Junction_ninserts(junction) > Intlist_head(Intlist_next(p))) {
      debug2(printf("Endpoint %d + %d >= %d, so unacceptable\n",
		    last_endpoint,Junction_ninserts(junction),Intlist_head(Intlist_next(p))));
      return false;
    } else {
      debug2(printf("Endpoint %d + %d < %d, so acceptable\n",
		    last_endpoint,Junction_ninserts(junction),Intlist_head(Intlist_next(p))));
    }
  }

  return true;
}


/* Algorithm: Find the lowest common univdiagonal, keeping track of
   qstart trims.  Continue through common univdiagonals, returning
   false if different endpoints are found, and then initializing qend
   trims.  If a common univdiagonal is found after that, return false.
   Otherwise, return true and report the trims. */

bool
Path_common_structure_p (int *common_trim_qstart, int *common_trim_qend, T a, T b) {
  bool common_univdiagonal_p = false, same_univdiagonal_p;
  int a_leading_univdiagonals = 0, a_trailing_univdiagonals = 0,
    b_leading_univdiagonals = 0, b_trailing_univdiagonals = 0;
  bool a_common_longest_p = false, b_common_longest_p = false;
  Univcoordlist_T p0, p1;
  Intlist_T q0, q1;
  Univcoord_T a_longest_univdiagonal, b_longest_univdiagonal;
  Univcoord_T a_univdiagonal, b_univdiagonal;
  int a_qstart, a_qend, b_qstart, b_qend;
  int maxlength, length;

  int a_trim_qstart = 0, a_trim_qend = 0;
  int b_trim_qstart = 0, b_trim_qend = 0;

#ifdef DEBUG5
  printf("Entered Path_common_structure_p\n");
  Path_print(a);
  Path_print(b);
#endif

  /* Find longest univdiagonals on each path */
  maxlength = 0;
  p0 = a->univdiagonals;
  q0 = a->endpoints;
  while (p0 != NULL) {
    length = Intlist_second_value(q0) - Intlist_head(q0);
    if (length > maxlength) {
      a_longest_univdiagonal = Univcoordlist_head(p0);
      maxlength = length;
    }
    p0 = Univcoordlist_next(p0);
    q0 = Intlist_next(q0);
  }

  maxlength = 0;
  p1 = b->univdiagonals;
  q1 = b->endpoints;
  while (p1 != NULL) {
    length = Intlist_second_value(q1) - Intlist_head(q1);
    if (length > maxlength) {
      b_longest_univdiagonal = Univcoordlist_head(p1);
      maxlength = length;
    }
    p1 = Univcoordlist_next(p1);
    q1 = Intlist_next(q1);
  }


  /* Find common structure */
  p0 = a->univdiagonals;
  p1 = b->univdiagonals;
  q0 = a->endpoints;
  q1 = b->endpoints;

  /* Find qstart trims until the first common univdiagonal */
  while (p0 != NULL && p1 != NULL && common_univdiagonal_p == false) {
    a_univdiagonal = Univcoordlist_head(p0);
    b_univdiagonal = Univcoordlist_head(p1);

    if (a_univdiagonal < b_univdiagonal) {
      debug5(printf("pre: a segment is entirely before b segment\n"));
      a_trim_qstart += Intlist_second_value(q0) - Intlist_head(q0);
      p0 = Univcoordlist_next(p0);
      q0 = Intlist_next(q0);
      a_leading_univdiagonals += 1;

    } else if (b_univdiagonal < a_univdiagonal) {
      debug5(printf("pre: b segment is entirely before a segment\n"));
      b_trim_qstart += Intlist_second_value(q1) - Intlist_head(q1);
      p1 = Univcoordlist_next(p1);
      q1 = Intlist_next(q1);
      b_leading_univdiagonals += 1;

    } else {
      /* Found first common univdiagonal */
      a_qstart = Intlist_head(q0);
      a_qend = Intlist_second_value(q0);
      b_qstart = Intlist_head(q1);
      b_qend = Intlist_second_value(q1);
      debug5(printf("pre: %u %d..%d vs %u %d..%d, with the same univdiagonal\n",
		    a_univdiagonal,a_qstart,a_qend,b_univdiagonal,b_qstart,b_qend));
      
      if (a_qstart < b_qstart) {
	debug5(printf("pre: trimming a only\n"));
	a_trim_qstart += (b_qstart - a_qstart);
      } else if (b_qstart < a_qstart) {
	debug5(printf("pre: trimming b only\n"));
	b_trim_qstart += (a_qstart - b_qstart);
      } else {
	debug5(printf("pre: no trimming\n"));
      }
      common_univdiagonal_p = true;
      if (a_univdiagonal == a_longest_univdiagonal) {
	a_common_longest_p = true;
      }
      if (b_univdiagonal == b_longest_univdiagonal) {
	b_common_longest_p = true;
      }

      p0 = Univcoordlist_next(p0);
      q0 = Intlist_next(q0);
      p1 = Univcoordlist_next(p1);
      q1 = Intlist_next(q1);
    }
  }

  debug5(printf("done with pre: a univdiagonals %p, b univdiagonals %p, common_univdiagonal_p %d\n",
		p0,p1,common_univdiagonal_p));

  /* Continue through common internal structure */
  same_univdiagonal_p = true;
  while (p0 != NULL && p1 != NULL && same_univdiagonal_p == true) {
    a_univdiagonal = Univcoordlist_head(p0);
    b_univdiagonal = Univcoordlist_head(p1);

    if (a_univdiagonal < b_univdiagonal) {
      debug5(printf("mid: a segment is entirely before b segment\n"));
      a_trim_qend += Intlist_second_value(q0) - Intlist_head(q0);
      p0 = Univcoordlist_next(p0);
      q0 = Intlist_next(q0);
      same_univdiagonal_p = false;

    } else if (b_univdiagonal < a_univdiagonal) {
      debug5(printf("mid: b segment is entirely before a segment\n"));
      b_trim_qend += Intlist_second_value(q1) - Intlist_head(q1);
      p1 = Univcoordlist_next(p1);
      q1 = Intlist_next(q1);
      same_univdiagonal_p = false;

    } else if (a_qend != b_qend) {
      /* Another common univdiagonal but previous one has different ends */
      debug5(printf("mid: Previous univdiagonal had different ends, so returning false\n"));
      return false;

    } else if ((a_qstart = Intlist_head(q0)) != (b_qstart = Intlist_head(q1))) {
      /* Another common univdiagonal but this one has different starts */
      debug5(printf("mid: This univdiagonal had different starts, so returning false\n"));
      return false;
      
    } else {
      a_qend = Intlist_second_value(q0);
      b_qend = Intlist_second_value(q1);
      debug5(printf("mid: %u %d..%d vs %d..%d\n",a_univdiagonal,a_qstart,a_qend,b_qstart,b_qend));

      if (a_univdiagonal == a_longest_univdiagonal) {
	a_common_longest_p = true;
      }
      if (b_univdiagonal == b_longest_univdiagonal) {
	b_common_longest_p = true;
      }

      p0 = Univcoordlist_next(p0);
      q0 = Intlist_next(q0);
      p1 = Univcoordlist_next(p1);
      q1 = Intlist_next(q1);
    }
  }

  /* Handle the final common univdiagonal */
  if (a_qend > b_qend) {
    debug5(printf("mid: trimming a only\n"));
    a_trim_qend += (a_qend - b_qend);
	
  } else if (b_qend > a_qend) {
    debug5(printf("mid: trimming b only\n"));
    b_trim_qend += (b_qend - a_qend);
  } else {
    debug5(printf("mid: no trimming\n"));
  }
    
  debug5(printf("done with mid: a univdiagonals %p, b univdiagonals %p, same_univdiagonal_p %d\n",
		p0,p1,same_univdiagonal_p));


  /* Continue after the common internal structure */
  while (p0 != NULL && p1 != NULL) {
    a_univdiagonal = Univcoordlist_head(p0);
    b_univdiagonal = Univcoordlist_head(p1);

    if (a_univdiagonal < b_univdiagonal) {
      debug5(printf("post: a segment is entirely before b segment\n"));
      a_trim_qend += Intlist_second_value(q0) - Intlist_head(q0);
      p0 = Univcoordlist_next(p0);
      q0 = Intlist_next(q0);
      a_trailing_univdiagonals += 1;

    } else if (b_univdiagonal < a_univdiagonal) {
      debug5(printf("post: b segment is entirely before a segment\n"));
      b_trim_qend += Intlist_second_value(q1) - Intlist_head(q1);
      p1 = Univcoordlist_next(p1);
      q1 = Intlist_next(q1);
      b_trailing_univdiagonals += 1;

    } else {
      /* Found a common univdiagonal after different univdiagonals */
      debug5(printf("post: found a common univdiagonal after different ones, so returning false\n"));
      return false;
    }
  }

  while (p0 != NULL) {
    debug5(printf("post: have remaining segments for a\n"));
    a_trim_qend += Intlist_second_value(q0) - Intlist_head(q0);
    p0 = Univcoordlist_next(p0);
    q0 = Intlist_next(q0);
    a_trailing_univdiagonals += 1;
  }

  while (p1 != NULL) {
    debug5(printf("post: have remaining segments for b\n"));
    b_trim_qend += Intlist_second_value(q1) - Intlist_head(q1);
    p1 = Univcoordlist_next(p1);
    q1 = Intlist_next(q1);
    b_trailing_univdiagonals += 1;
  }
      
  debug5(printf("end: Have trims %d vs %d and %d vs %d\n",
		a_trim_qstart,b_trim_qstart,a_trim_qend,b_trim_qend));
  debug5(printf("leading %d and %d.  trailing %d and %d\n",
		a_leading_univdiagonals,b_leading_univdiagonals,
		a_trailing_univdiagonals,b_trailing_univdiagonals));

  if (common_univdiagonal_p == false) {
    debug5(printf("No common univdiagonal, so returning false\n"));
    return false;
  } else if (a_common_longest_p == false) {
    debug5(printf("Common univdiagonal for path a is not the longest, so returning false\n"));
    return false;
  } else if (b_common_longest_p == false) {
    debug5(printf("Common univdiagonal for path b is not the longest, so returning false\n"));
    return false;
  } else if (a_trim_qstart != b_trim_qstart) {
    debug5(printf("qstarts unequal, so returning false\n"));
    return false;
  } else if (a_trim_qend != b_trim_qend) {
    debug5(printf("qends unequal, so returning false\n"));
    return false;
  } else if (a_leading_univdiagonals > 1 || b_leading_univdiagonals > 1) {
    debug5(printf("too many leading univdiagonals\n"));
    return false;
  } else if (a_trailing_univdiagonals > 1 || b_trailing_univdiagonals > 1) {
    debug5(printf("too many trailing univdiagonals\n"));
    return false;
  } else if (a_leading_univdiagonals == 1 && b_trailing_univdiagonals == 1) {
    debug5(printf("mismatch leading/trailing univdiagonals\n"));
    return false;
  } else if (b_leading_univdiagonals == 1 && a_trailing_univdiagonals == 1) {
    debug5(printf("mismatch leading/trailing univdiagonals\n"));
    return false;
  } else if (a_trim_qstart + a_trim_qend >= Path_coverage(a)) {
    debug5(printf("Trims are too long, so returning false\n"));
    return false;
  } else {
    *common_trim_qstart = a_trim_qstart;
    *common_trim_qend = a_trim_qend;
    debug5(printf("Returning true with trims %d and %d\n",*common_trim_qstart,*common_trim_qend));
    return true;
  }
}



/* Called by conversion procedures in trpath-convert.c */
T
Path_convert_simple (Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
		     Intlist_T endpoints, Univcoordlist_T univdiagonals, Intlist_T nmismatches,
		     Intlist_T ref_nmismatches, List_T junctions,
		     bool plusp, int genestrand, int sensedir, int querylength,
		     Listpool_T listpool, Pathpool_T pathpool, Method_T method) {

  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  Intlist_T q;
#ifdef CHECK_ASSERTIONS
  int prev_endpoint;
#endif

  debug0(printf("Creating path %p by Path_create_simple\n",new));
  
  assert(sensedir == SENSE_FORWARD || sensedir == SENSE_ANTI);

  assert(Univcoordlist_length(univdiagonals) == Intlist_length(endpoints) - 1);
  assert(Intlist_length(nmismatches) == Intlist_length(endpoints) - 1);
  assert(Intlist_length(ref_nmismatches) == Intlist_length(endpoints) - 1);
  assert(List_length(junctions) == Intlist_length(endpoints) - 2);

  /* Avoids having to call Path_eval_nmatches */

  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;
  new->nmatches = new->ref_nmatches = querylength - Intlist_sum(nmismatches) - Junction_total_ninserts(junctions);

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = sensedir;
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = endpoints;
  new->univdiagonals = univdiagonals;
  new->nmismatches = nmismatches;
  new->ref_nmismatches = ref_nmismatches;
  new->junctions = junctions;

  new->splice5p = false;
  new->splicetype5 = NO_SPLICE;
  new->ambig_prob_5 = 0.0;

  new->splice3p = false;
  new->splicetype3 = NO_SPLICE;
  new->ambig_prob_3 = 0.0;

  new->qstart_alts = (Altsplice_T) NULL;
  new->qend_alts = (Altsplice_T) NULL;

  new->circular_endpoints = (Intlist_T) NULL;
#if 0
  new->circular_high_p = false;
  new->circular_nmismatches = (Intlist_T) NULL;
  new->circular_ref_nmismatches = (Intlist_T) NULL;
  new->circular_univdiagonals = (Univcoordlist_T) NULL;
  new->circular_junctions = (List_T) NULL;
#endif

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->fusion_chrnum = -1;
  new->fusion_chroffset = 0;
  new->fusion_chrhigh = 0;

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = true;

#ifdef CHECK_ASSERTIONS
  prev_endpoint = Intlist_head(new->endpoints);
  for (q = Intlist_next(new->endpoints); q != NULL; q = Intlist_next(q)) {
    /* Previously used <=, but a deletion can yield duplicated endpoints */
    if (Intlist_head(q) < prev_endpoint) {
      printf("Path_create_from_transcript expected forward, but got\n");
      Path_print(new);
      abort();
    }
    prev_endpoint = Intlist_head(q);
  }
#endif

  debug0(Path_print(new));
  return new;
}



/* Called by combine_leftright_paths */
T
Path_create (Intlist_T endpoints, Univcoordlist_T univdiagonals, Intlist_T nmismatches,
	     Intlist_T ref_nmismatches, List_T junctions,
	     bool plusp, int genestrand, int sensedir, int querylength, Method_T method,
	     Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
	     bool splice5p, Splicetype_T splicetype5, double ambig_prob_5,
	     bool splice3p, Splicetype_T splicetype3, double ambig_prob_3,
	     Altsplice_T qstart_alts, Altsplice_T qend_alts,
	     Pathpool_T pathpool, Vectorpool_T vectorpool) {

  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  Intlist_T q;
#ifdef CHECK_ASSERTIONS
  int prev_endpoint;
#endif

  debug0(printf("Creating path %p by Path_create\n",new));
  
  assert(sensedir == SENSE_FORWARD || sensedir == SENSE_ANTI);

  assert(Univcoordlist_length(univdiagonals) == Intlist_length(endpoints) - 1);
  assert(Intlist_length(nmismatches) == Intlist_length(endpoints) - 1);
  assert(Intlist_length(ref_nmismatches) == Intlist_length(endpoints) - 1);
  assert(List_length(junctions) == Intlist_length(endpoints) - 2);

  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = sensedir;
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = endpoints;
  new->univdiagonals = univdiagonals;
  new->nmismatches = nmismatches;
  new->ref_nmismatches = ref_nmismatches;
  new->junctions = junctions;

  new->splice5p = splice5p;
  new->splicetype5 = splicetype5;
  new->ambig_prob_5 = ambig_prob_5;

  new->splice3p = splice3p;
  new->splicetype3 = splicetype3;
  new->ambig_prob_3 = ambig_prob_3;

  new->qstart_alts = Altsplice_copy(qstart_alts,pathpool,vectorpool);
  new->qend_alts = Altsplice_copy(qend_alts,pathpool,vectorpool);

  new->circular_endpoints = (Intlist_T) NULL;

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = false;

#ifdef CHECK_ASSERTIONS
  prev_endpoint = Intlist_head(new->endpoints);
  for (q = Intlist_next(new->endpoints); q != NULL; q = Intlist_next(q)) {
    if (Intlist_head(q) <= prev_endpoint) {
      printf("Path_create expected forward, but got\n");
      Path_print(new);
      abort();
    }
    prev_endpoint = Intlist_head(q);
  }
#endif

  return new;
}


T
Path_copy (T old, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	   Listpool_T listpool, Pathpool_T pathpool, Vectorpool_T vectorpool,
	   Transcriptpool_T transcriptpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_copy from %p\n",new,old));

  assert(old->sensedir == SENSE_FORWARD || old->sensedir == SENSE_ANTI);

  assert(Univcoordlist_length(old->univdiagonals) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->ref_nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(List_length(old->junctions) == Intlist_length(old->endpoints) - 2);

  new->nmatches = old->nmatches;
  new->ref_nmatches = old->ref_nmatches;
  new->junction_splice_prob = old->junction_splice_prob;
  new->total_splice_prob = old->total_splice_prob;
  new->found_score = old->found_score;
  new->score_within_trims = old->score_within_trims;

  if (old->genomic_diff == NULL) {
    new->genomic_diff = (char *) NULL;
  } else {
    new->genomic_diff = Pathpool_new_string(pathpool,old->querylength+1);
    strcpy(new->genomic_diff,old->genomic_diff);
  }

  new->plusp = old->plusp;
  new->genestrand = old->genestrand;
  new->sensedir = old->sensedir;
  new->querylength = old->querylength;

  new->chrnum = old->chrnum;
  new->chroffset = old->chroffset;
  new->chrhigh = old->chrhigh;

  new->endpoints = Intlistpool_copy(old->endpoints,intlistpool);
  new->univdiagonals = Univcoordlistpool_copy(old->univdiagonals,univcoordlistpool);
  new->nmismatches = Intlistpool_copy(old->nmismatches,intlistpool);
  new->ref_nmismatches = Intlistpool_copy(old->ref_nmismatches,intlistpool);
  new->junctions = Junction_copy_list(old->junctions,listpool,pathpool);
  
  new->splice5p = old->splice5p;
  new->splicetype5 = old->splicetype5;
  new->ambig_prob_5 = old->ambig_prob_5;

  new->splice3p = old->splice3p;
  new->splicetype3 = old->splicetype3;
  new->ambig_prob_3 = old->ambig_prob_3;

  new->qstart_alts = Altsplice_copy(old->qstart_alts,pathpool,vectorpool);
  new->qend_alts = Altsplice_copy(old->qend_alts,pathpool,vectorpool);
  
  if (old->circular_endpoints == NULL) {
    new->circular_endpoints = (Intlist_T) NULL;
  } else {
    new->circular_high_p = old->circular_high_p;
    new->circular_endpoints = Intlistpool_copy(old->circular_endpoints,intlistpool);
    new->circular_univdiagonals = Univcoordlistpool_copy(old->circular_univdiagonals,univcoordlistpool);
    new->circular_nmismatches = Intlistpool_copy(old->circular_nmismatches,intlistpool);
    new->circular_ref_nmismatches = Intlistpool_copy(old->circular_ref_nmismatches,intlistpool);
    new->circular_junctions = Junction_copy_list(old->circular_junctions,listpool,pathpool);
  }

  new->fusion_querystart_junction = Junction_copy(old->fusion_querystart_junction,pathpool);
  new->fusion_queryend_junction = Junction_copy(old->fusion_queryend_junction,pathpool);
  if (new->fusion_querystart_junction == NULL && new->fusion_queryend_junction == NULL) {
    new->fusion_endpoints = (Intlist_T) NULL;
    /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */
  } else {
    new->fusion_chrnum = old->fusion_chrnum;
    new->fusion_chroffset = old->fusion_chroffset;
    new->fusion_chrhigh = old->fusion_chrhigh;
    new->fusion_plusp = old->fusion_plusp;
    
    new->fusion_endpoints = Intlistpool_copy(old->fusion_endpoints,intlistpool);
    new->fusion_univdiagonals = Univcoordlistpool_copy(old->fusion_univdiagonals,univcoordlistpool);
    new->fusion_nmismatches = Intlistpool_copy(old->fusion_nmismatches,intlistpool);
    new->fusion_ref_nmismatches = Intlistpool_copy(old->fusion_ref_nmismatches,intlistpool);
    new->fusion_junctions = Junction_copy_list(old->fusion_junctions,listpool,pathpool);

#if 0
    /* This computation was already done when constructing the fusion path */
    if (new->fusion_querystart_junction != NULL) {
      if (new->fusion_plusp == true) {
	new->fusion_alts = Altsplice_copy(old->qstart_alts,pathpool,vectorpool);
      } else {
	new->fusion_alts = Altsplice_copy(old->qend_alts,pathpool,vectorpool);
      }
    } else {
      if (new->fusion_plusp == true) {
	new->fusion_alts = Altsplice_copy(old->qend_alts,pathpool,vectorpool);
      } else {
	new->fusion_alts = Altsplice_copy(old->qstart_alts,pathpool,vectorpool);
      }
    }
#else
    new->fusion_alts = Altsplice_copy(old->fusion_alts,pathpool,vectorpool);
#endif
  }

  new->transcripts = Transcript_copy_list(old->transcripts,transcriptpool,listpool);
  new->invalid_transcripts = Transcript_copy_list(old->invalid_transcripts,transcriptpool,listpool);
  new->fusion_transcripts = Transcript_copy_list(old->fusion_transcripts,transcriptpool,listpool);
  new->fusion_invalid_transcripts = Transcript_copy_list(old->fusion_invalid_transcripts,transcriptpool,listpool);

  new->method = old->method;
  new->transcriptome_method_p = old->transcriptome_method_p;

  return new;
}


#if 0
List_T
Path_copy_list (List_T old, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
		Listpool_T listpool, Pathpool_T pathpool, Vectorpool_T vectorpool,
		Hitlistpool_T hitlistpool, Transcriptpool_T transcriptpool) {
  List_T new = NULL, p;

  for (p = old; p != NULL; p = List_next(p)) {
    new = Hitlist_push(new,hitlistpool,
		       (void *) Path_copy((T) List_head(p),intlistpool,univcoordlistpool,
					  listpool,pathpool,vectorpool,transcriptpool)
		       hitlistpool_trace(__FILE__,__LINE__));
  }
  return List_reverse(new);
}
#endif


T
Path_copy_5 (T old, bool splice5p, Splicetype_T splicetype5, double ambig_prob_5,
	     Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	     Listpool_T listpool, Pathpool_T pathpool, Vectorpool_T vectorpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_copy_5 from %p\n",new,old));
  
  assert(old->sensedir == SENSE_FORWARD || old->sensedir == SENSE_ANTI);

  assert(Univcoordlist_length(old->univdiagonals) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->ref_nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(List_length(old->junctions) == Intlist_length(old->endpoints) - 2);

 /* Need to call Path_eval_nmatches on this copy */
  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = old->querylength;
  new->score_within_trims = old->querylength;

  if (old->genomic_diff == NULL) {
    new->genomic_diff = (char *) NULL;
  } else {
    new->genomic_diff = Pathpool_new_string(pathpool,old->querylength+1);
    strcpy(new->genomic_diff,old->genomic_diff);
  }

  new->plusp = old->plusp;
  new->genestrand = old->genestrand;
  new->sensedir = old->sensedir;
  new->querylength = old->querylength;

  new->chrnum = old->chrnum;
  new->chroffset = old->chroffset;
  new->chrhigh = old->chrhigh;

  new->endpoints = Intlistpool_copy(old->endpoints,intlistpool);
  new->univdiagonals = Univcoordlistpool_copy(old->univdiagonals,univcoordlistpool);
  new->nmismatches = Intlistpool_copy(old->nmismatches,intlistpool);
  new->ref_nmismatches = Intlistpool_copy(old->ref_nmismatches,intlistpool);
  new->junctions = Junction_copy_list(old->junctions,listpool,pathpool);
  
  new->splice5p = splice5p;
  new->splicetype5 = splicetype5;
  new->ambig_prob_5 = ambig_prob_5;

  new->splice3p = old->splice3p;
  new->splicetype3 = old->splicetype3;
  new->ambig_prob_3 = old->ambig_prob_3;

  new->qstart_alts = Altsplice_copy(old->qstart_alts,pathpool,vectorpool);
  new->qend_alts = Altsplice_copy(old->qend_alts,pathpool,vectorpool);
  
  assert(old->circular_endpoints == NULL);
  new->circular_endpoints = (Intlist_T) NULL;

  assert(old->fusion_querystart_junction == NULL);
  assert(old->fusion_queryend_junction == NULL);
  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = old->method;
  new->transcriptome_method_p = old->transcriptome_method_p;

  return new;
}

T
Path_copy_3 (T old,  bool splice3p, Splicetype_T splicetype3, double ambig_prob_3,
	     Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	     Listpool_T listpool, Pathpool_T pathpool, Vectorpool_T vectorpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_copy_3 from %p\n",new,old));
  
  assert(old->sensedir == SENSE_FORWARD || old->sensedir == SENSE_ANTI);

  assert(Univcoordlist_length(old->univdiagonals) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(Intlist_length(old->ref_nmismatches) == Intlist_length(old->endpoints) - 1);
  assert(List_length(old->junctions) == Intlist_length(old->endpoints) - 2);

 /* Need to call Path_eval_nmatches on this copy */
  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = old->querylength;
  new->score_within_trims = old->querylength;

  if (old->genomic_diff == NULL) {
    new->genomic_diff = (char *) NULL;
  } else {
    new->genomic_diff = Pathpool_new_string(pathpool,old->querylength+1);
    strcpy(new->genomic_diff,old->genomic_diff);
  }

  new->plusp = old->plusp;
  new->genestrand = old->genestrand;
  new->sensedir = old->sensedir;
  new->querylength = old->querylength;

  new->chrnum = old->chrnum;
  new->chroffset = old->chroffset;
  new->chrhigh = old->chrhigh;

  new->endpoints = Intlistpool_copy(old->endpoints,intlistpool);
  new->univdiagonals = Univcoordlistpool_copy(old->univdiagonals,univcoordlistpool);
  new->nmismatches = Intlistpool_copy(old->nmismatches,intlistpool);
  new->ref_nmismatches = Intlistpool_copy(old->ref_nmismatches,intlistpool);
  new->junctions = Junction_copy_list(old->junctions,listpool,pathpool);
  
  new->splice5p = old->splice5p;
  new->splicetype5 = old->splicetype5;
  new->ambig_prob_5 = old->ambig_prob_5;

  new->splice3p = splice3p;
  new->splicetype3 = splicetype3;
  new->ambig_prob_3 = ambig_prob_3;

  new->qstart_alts = Altsplice_copy(old->qstart_alts,pathpool,vectorpool);
  new->qend_alts = Altsplice_copy(old->qend_alts,pathpool,vectorpool);
  
  assert(old->circular_endpoints == NULL);
  new->circular_endpoints = (Intlist_T) NULL;

  assert(old->fusion_querystart_junction == NULL);
  assert(old->fusion_queryend_junction == NULL);
  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = old->method;
  new->transcriptome_method_p = old->transcriptome_method_p;

  return new;
}


int
Path_exon_origin (T this) {
  int exon_origin;
  Intlist_T p = this->endpoints;
  List_T j = this->junctions;

  p = Intlist_next(p);
  exon_origin = Intlist_head(p);

  while (j != NULL && Junction_type((Junction_T) List_head(j)) != SPLICE_JUNCTION) {
    p = Intlist_next(p);
    exon_origin = Intlist_head(p);

    j = List_next(j);
  }

  return exon_origin;
}


void
Path_count (int *npaths_primary, int *npaths_altloc, List_T paths) {
  T path;

  *npaths_primary = *npaths_altloc = 0;

  while (paths != NULL) {
    path = (T) List_head(paths);
    if (altlocp[path->chrnum] == true) {
      *npaths_altloc += 1;
    } else {
      *npaths_primary += 1;
    }
    paths = List_next(paths);
  }

  return;
}


void
Path_free (T *old, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	   Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool) {
  debug0(printf("Freeing path %p\n",*old));

  assert((*old)->sensedir == SENSE_FORWARD || (*old)->sensedir == SENSE_ANTI);
  /* Note: assertions about lengths do not hold because procedures,
     such as Repair_path, can call Path_free before completing the
     path */

  Intlistpool_free_list(&(*old)->endpoints,intlistpool
			intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
  Univcoordlistpool_free_list(&(*old)->univdiagonals,univcoordlistpool
			      univcoordlistpool_trace(__FILE__,__LINE__)); /* allocated by Univcoordlistpool_push */
  Intlistpool_free_list(&(*old)->nmismatches,intlistpool
			intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
  Intlistpool_free_list(&(*old)->ref_nmismatches,intlistpool
			intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
  Junction_list_gc(&(*old)->junctions,listpool,pathpool); /* junctions allocated by Pathpool_new_junction, and list allocated by Listpool_push */

  if ((*old)->circular_endpoints != NULL) {
    Intlistpool_free_list(&(*old)->circular_endpoints,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Univcoordlistpool_free_list(&(*old)->circular_univdiagonals,univcoordlistpool
				univcoordlistpool_trace(__FILE__,__LINE__)); /* allocated by Univcoordlistpool_push */
    Intlistpool_free_list(&(*old)->circular_nmismatches,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Intlistpool_free_list(&(*old)->circular_ref_nmismatches,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Junction_list_gc(&(*old)->circular_junctions,listpool,pathpool); /* junctions allocated by Pathpool_new_junction, and list allocated by Listpool_push */
  }

  if ((*old)->fusion_endpoints != NULL) {
    Intlistpool_free_list(&(*old)->fusion_endpoints,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Univcoordlistpool_free_list(&(*old)->fusion_univdiagonals,univcoordlistpool
				univcoordlistpool_trace(__FILE__,__LINE__)); /* allocated by Univcoordlistpool_push */
    Intlistpool_free_list(&(*old)->fusion_nmismatches,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Intlistpool_free_list(&(*old)->fusion_ref_nmismatches,intlistpool
			  intlistpool_trace(__FILE__,__LINE__)); /* allocated by Intlistpool_push */
    Junction_list_gc(&(*old)->fusion_junctions,listpool,pathpool); /* junctions allocated by Pathpool_new_junction, and list allocated by Listpool_push */

    if ((*old)->fusion_alts != NULL) {
      Altsplice_free(&(*old)->fusion_alts,pathpool);
    }
  }

  if ((*old)->fusion_querystart_junction != NULL) {
    Pathpool_free_junction(&(*old)->fusion_querystart_junction,pathpool
			   pathpool_trace(__FILE__,__LINE__));
  }
  if ((*old)->fusion_queryend_junction != NULL) {
    Pathpool_free_junction(&(*old)->fusion_queryend_junction,pathpool
			   pathpool_trace(__FILE__,__LINE__));
  }

  /* altsplices are allocated by Pathpool_new_altsplice */
  if ((*old)->qstart_alts != NULL) {
    Altsplice_free(&(*old)->qstart_alts,pathpool);
  }
  if ((*old)->qend_alts != NULL) {
    Altsplice_free(&(*old)->qend_alts,pathpool);
  }
  
#if 0
  /* genomic_diff is allocated by Pathpool_new_string */
  if ((*old)->genomic_diff != NULL) {
    FREE((*old)->genomic_diff);
  }
#endif

  Transcript_list_gc(&(*old)->transcripts,listpool,transcriptpool);
  Transcript_list_gc(&(*old)->invalid_transcripts,listpool,transcriptpool);
  Transcript_list_gc(&(*old)->fusion_transcripts,listpool,transcriptpool);
  Transcript_list_gc(&(*old)->fusion_invalid_transcripts,listpool,transcriptpool);

  Pathpool_free_path(&(*old),pathpool
		     pathpool_trace(__FILE__,__LINE__)); /* Allocated by Pathpool_new_path */

  return;
}


void
Path_gc (List_T *list, Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
	 Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool,
	 Hitlistpool_T hitlistpool) {
  List_T p;
  T old;
  
  for (p = *list; p != NULL; p = List_next(p)) {
    old = (T) List_head(p);
    Path_free(&old,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool);
  }
  Hitlistpool_free_list(&(*list),hitlistpool
			hitlistpool_trace(__FILE__,__LINE__)); /* allocated by Hitlistpool_push */
  return;
}


#if 0
static int
Path_nsegments (T this) {
  int nsegments;

  nsegments = Univcoordlist_length(this->univdiagonals);
  if (this->qstart_alts != NULL) {
    nsegments += 1;
  }
  if (this->qend_alts != NULL) {
    nsegments += 1;
  }
  return nsegments;
}
#endif


#if 0
static int
Path_cmp (const void *a, const void *b) {
  T x = * (T *) a;
  T y = * (T *) b;
  Univcoordlist_T p, q;

  p = x->univdiagonals;
  q = y->univdiagonals;
  while (p != NULL && q != NULL) {

    if (Univcoordlist_head(p) < Univcoordlist_head(q)) {
      return -1;
    } else if (Univcoordlist_head(q) < Univcoordlist_head(p)) {
      return +1;
    } else {
      p = Univcoordlist_next(p);
      q = Univcoordlist_next(q);
    }
  }

  if (p == NULL && q == NULL) {
    return 0;
  } else if (p == NULL) {
    return -1;
  } else if (q == NULL) {
    return +1;
  } else {
    /* Not possible */
    return 0;
  }
}
#endif


T
Path_new_from_ends (Univcoord_T univdiagonal5, int qstart5, int qend5,
		    Univcoord_T univdiagonal3, int qstart3, int qend3,
		    bool plusp, int genestrand, int sensedir, int querylength, Method_T method,
		    Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
		    Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool,
		    Listpool_T listpool, Pathpool_T pathpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_new_from_ends\n",new));
  
  assert(sensedir == SENSE_FORWARD || sensedir == SENSE_ANTI);

  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = sensedir;
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = Intlistpool_push(NULL,intlistpool,qend3
				    intlistpool_trace(__FILE__,__LINE__));
  new->endpoints = Intlistpool_push(new->endpoints,intlistpool,qstart3
				    intlistpool_trace(__FILE__,__LINE__));
  new->endpoints = Intlistpool_push(new->endpoints,intlistpool,qstart5
				    intlistpool_trace(__FILE__,__LINE__));

  new->univdiagonals = Univcoordlistpool_push(NULL,univcoordlistpool,univdiagonal3
					      univcoordlistpool_trace(__FILE__,__LINE__));
  new->univdiagonals = Univcoordlistpool_push(new->univdiagonals,univcoordlistpool,univdiagonal5
					      univcoordlistpool_trace(__FILE__,__LINE__));

  new->nmismatches = Intlistpool_push(NULL,intlistpool,-1
				      intlistpool_trace(__FILE__,__LINE__));
  new->nmismatches = Intlistpool_push(new->nmismatches,intlistpool,-1
				      intlistpool_trace(__FILE__,__LINE__));

  new->ref_nmismatches = Intlistpool_push(NULL,intlistpool,-1
					  intlistpool_trace(__FILE__,__LINE__));
  new->ref_nmismatches = Intlistpool_push(new->ref_nmismatches,intlistpool,-1
					  intlistpool_trace(__FILE__,__LINE__));

#ifdef ALLOCATE_UNSOLVED_JUNCTION
  new->junctions = Listpool_push(NULL,listpool,Junction_new_unsolved(pathpool)
				 listpool_trace(__FILE__,__LINE__));
#else
  new->junctions = Listpool_push(NULL,listpool,(void *) JUNCTION_UNSOLVED
				 listpool_trace(__FILE__,__LINE__));
#endif
  
  new->splice5p = false;
  new->splicetype5 = NO_SPLICE;
  new->ambig_prob_5 = 0.0;

  new->splice3p = false;
  new->splicetype3 = NO_SPLICE;
  new->ambig_prob_3 = 0.0;

  new->qstart_alts = (Altsplice_T) NULL;
  new->qend_alts = (Altsplice_T) NULL;
  
  new->circular_endpoints = (Intlist_T) NULL;

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = false;

  return new;
}


T
Path_new_exact (Univcoord_T univdiagonal, int qstart, int qend, int nmismatches, int ref_nmismatches,
		bool plusp, int genestrand, int querylength, Method_T method,
		Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
		Intlistpool_T intlistpool, Univcoordlistpool_T univcoordlistpool, Pathpool_T pathpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_new_from_ends\n",new));
  
  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = SENSE_FORWARD; /* antisense generated after Path_copy */
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = Intlistpool_push(NULL,intlistpool,qend
				    intlistpool_trace(__FILE__,__LINE__));
  new->endpoints = Intlistpool_push(new->endpoints,intlistpool,qstart
				    intlistpool_trace(__FILE__,__LINE__));

  new->univdiagonals = Univcoordlistpool_push(NULL,univcoordlistpool,univdiagonal
					      univcoordlistpool_trace(__FILE__,__LINE__));

  new->nmismatches = Intlistpool_push(NULL,intlistpool,nmismatches
				      intlistpool_trace(__FILE__,__LINE__));
  new->ref_nmismatches = Intlistpool_push(NULL,intlistpool,ref_nmismatches
					  intlistpool_trace(__FILE__,__LINE__));

  new->junctions = (List_T) NULL;
  
  new->splice5p = false;
  new->splicetype5 = NO_SPLICE;
  new->ambig_prob_5 = 0.0;

  new->splice3p = false;
  new->splicetype3 = NO_SPLICE;
  new->ambig_prob_3 = 0.0;

  new->qstart_alts = (Altsplice_T) NULL;
  new->qend_alts = (Altsplice_T) NULL;
  
  new->circular_endpoints = (Intlist_T) NULL;

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = false;

  return new;
}



/* qstart and qend are the genome-normalized coordinates, so qstart
   marks the left coordinate and qend marks the right coordinate.  For
   a plus-strand alignment, qstart = querystart and qend = queryend.
   For a minus-strand alignment qstart = querylength - querystart and
   qend = querylength - queryend. */

/* Need to convert from qstart and qend to querystart and queryend
   when creating Altsplice_T objects */

T
Path_new_for_qstart_extension (Univcoord_T univdiagonal, int qstart, int qend, int nmismatches,
			       bool plusp, int genestrand, int sensedir, int querylength, Method_T method,
			       Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
			       bool splice5p, Splicetype_T splicetype5,
			       double ambig_prob_5, Intlistpool_T intlistpool,
			       Univcoordlistpool_T univcoordlistpool, Pathpool_T pathpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_new_for_qstart_extension\n",new));
  
  assert(sensedir == SENSE_FORWARD || sensedir == SENSE_ANTI);

  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = sensedir;
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = Intlistpool_push(Intlistpool_push(NULL,intlistpool,qend
						     intlistpool_trace(__FILE__,__LINE__)),intlistpool,qstart
				    intlistpool_trace(__FILE__,__LINE__));
  new->univdiagonals = Univcoordlistpool_push(NULL,univcoordlistpool,univdiagonal
					      univcoordlistpool_trace(__FILE__,__LINE__));
  new->nmismatches = Intlistpool_push(NULL,intlistpool,nmismatches
				      intlistpool_trace(__FILE__,__LINE__)); /* qstart..qend found by consecutive matches */
  new->ref_nmismatches = Intlistpool_push(NULL,intlistpool,nmismatches
					  intlistpool_trace(__FILE__,__LINE__));
  new->junctions = (List_T) NULL;
  
  new->splice5p = splice5p;
  new->splicetype5 = splicetype5;
  new->ambig_prob_5 = ambig_prob_5;

  new->splice3p = false;
  new->splicetype3 = NO_SPLICE;
  new->ambig_prob_3 = 0.0;

  new->qstart_alts = (Altsplice_T) NULL;
  new->qend_alts = (Altsplice_T) NULL;
  
  new->circular_endpoints = (Intlist_T) NULL;

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = false;

  return new;
}


T
Path_new_for_qend_extension (Univcoord_T univdiagonal, int qstart, int qend, int nmismatches,
			     bool plusp, int genestrand, int sensedir, int querylength, Method_T method,
			     Chrnum_T chrnum, Univcoord_T chroffset, Univcoord_T chrhigh,
			     bool splice3p, Splicetype_T splicetype3,
			     double ambig_prob_3, Intlistpool_T intlistpool,
			     Univcoordlistpool_T univcoordlistpool, Pathpool_T pathpool) {
  T new = Pathpool_new_path(pathpool
			    pathpool_trace(__FILE__,__LINE__));
  debug0(printf("Creating path %p by Path_new_for_qend_extension\n",new));

  assert(sensedir == SENSE_FORWARD || sensedir == SENSE_ANTI);

  new->nmatches = -1;
  new->ref_nmatches = -1;
  new->junction_splice_prob = 0.0;
  new->total_splice_prob = 0.0;
  new->found_score = querylength;
  new->score_within_trims = querylength;
  new->genomic_diff = (char *) NULL;

  new->plusp = plusp;
  new->genestrand = genestrand;
  new->sensedir = sensedir;
  new->querylength = querylength;

  new->chrnum = chrnum;
  new->chroffset = chroffset;
  new->chrhigh = chrhigh;

  new->endpoints = Intlistpool_push(Intlistpool_push(NULL,intlistpool,qstart
						     intlistpool_trace(__FILE__,__LINE__)),intlistpool,qend
				    intlistpool_trace(__FILE__,__LINE__));
  new->univdiagonals = Univcoordlistpool_push(NULL,univcoordlistpool,univdiagonal
					      univcoordlistpool_trace(__FILE__,__LINE__));
  new->nmismatches = Intlistpool_push(NULL,intlistpool,nmismatches
				      intlistpool_trace(__FILE__,__LINE__));
  new->ref_nmismatches = Intlistpool_push(NULL,intlistpool,nmismatches
					  intlistpool_trace(__FILE__,__LINE__));
  new->junctions = (List_T) NULL;

  new->splice5p = false;
  new->splicetype5 = NO_SPLICE;
  new->ambig_prob_5 = 0.0;

  new->splice3p = splice3p;
  new->splicetype3 = splicetype3;
  new->ambig_prob_3 = ambig_prob_3;

  new->qstart_alts = (Altsplice_T) NULL;
  new->qend_alts = (Altsplice_T) NULL;

  new->circular_endpoints = (Intlist_T) NULL;

  new->fusion_querystart_junction = (Junction_T) NULL;
  new->fusion_queryend_junction = (Junction_T) NULL;
  new->fusion_endpoints = (Intlist_T) NULL;
  /* Obviates need to set fusion_univdiagonals, fusion_nmismatches, fusion_ref_nmismatches, fusion_junctions and fusion_alts */

  new->transcripts = (List_T) NULL;
  new->invalid_transcripts = (List_T) NULL;
  new->fusion_transcripts = (List_T) NULL;
  new->fusion_invalid_transcripts = (List_T) NULL;

  new->method = method;
  new->transcriptome_method_p = false;

  return new;
}


static char *
sensedir_string (int sensedir) {
  if (sensedir == SENSE_NULL) {
    return "sense:null";
  } else if (sensedir == SENSE_ANTI) {
    return "sense:anti";
  } else if (sensedir == SENSE_FORWARD) {
    return "sense:fwd";
  } else {
    abort();
  }
}


static char *
splicetype_string (Splicetype_T splicetype) {
  switch (splicetype) {
  case DONOR: return "donor";
  case ACCEPTOR: return "acceptor";
  case ANTIDONOR: return "antidonor";
  case ANTIACCEPTOR: return "antiacceptor";
  default: abort();
  }
}


#if defined(CHECK_ASSERTIONS) || defined(DEBUG1)
void
Path_print (T this) {
  Junction_T fusion_junction;

  if (this != NULL) {
    printf(">> Path %p: ",this);

    if (this->nmatches >= 0) {
      /* Info added for new version */
      printf("found_score:%d, within_trims:%d; nmatches:%d splice_prob:%f->%f  ",
	     this->found_score,this->score_within_trims,this->nmatches,
	     this->junction_splice_prob,this->total_splice_prob);
    }

    /* Info added for new version */
    printf("plusp:%d try_%s eff_%s method:%s  ",
	   this->plusp,sensedir_string(this->sensedir),sensedir_string(Path_effective_sensedir(this)),
	   Method_string(this->method));

    printf("%s  %d:%s  %s  nmismatches:%s  ref_nmismatches:%s  ",
	   Univcoordlist_to_string(this->univdiagonals),this->chrnum,
	   Univcoordlist_to_string_offset(this->univdiagonals,this->chroffset),
	   Intlist_to_string(this->endpoints),
	   Intlist_to_string(this->nmismatches),Intlist_to_string(this->ref_nmismatches));

    if (this->splice5p == false) {
      printf("splice5p:0 ");
    } else {
      printf("splice5p:1(%s,%f) ",splicetype_string(this->splicetype5),this->ambig_prob_5);
    }

    if (this->splice3p == false) {
      printf("splice3p:0  ");
    } else {
      printf("splice3p:1(%s,%f)  ",splicetype_string(this->splicetype3),this->ambig_prob_3);
    }

    printf("jcns:");
    Junction_print_list(this->junctions);
    printf("  qstart_alts:");
    Altsplice_print(this->qstart_alts);
    printf("  qend_alts:");
    Altsplice_print(this->qend_alts);

    printf("  transcripts:");
    Transcript_print_nums(this->transcripts);
    printf("  invalid:");
    Transcript_print_nums(this->invalid_transcripts);

    if (this->circular_endpoints != NULL) {
      printf(" CIRCULAR (high:%d): %s %s ",
	     this->circular_high_p,
	     Intlist_to_string(this->circular_endpoints),
	     Univcoordlist_to_string(this->circular_univdiagonals));
      Junction_print_list(this->circular_junctions);
    }

    if (this->fusion_querystart_junction != NULL || this->fusion_queryend_junction != NULL) {
      if (this->fusion_querystart_junction != NULL) {
	fusion_junction = this->fusion_querystart_junction;
	printf(" QUERYSTART_FUSION: plusp:%d,%c%c-%c%c,%f,%f ",
	       this->fusion_plusp,fusion_junction->donor1,fusion_junction->donor2,
	       fusion_junction->acceptor2,fusion_junction->acceptor1,
	       fusion_junction->donor_prob,fusion_junction->acceptor_prob);
      } else {
	fusion_junction = this->fusion_queryend_junction;
	printf(" QUERYEND_FUSION: plusp:%d,%c%c-%c%c,%f,%f ",
	       this->fusion_plusp,fusion_junction->donor1,fusion_junction->donor2,
	       fusion_junction->acceptor2,fusion_junction->acceptor1,
	       fusion_junction->donor_prob,fusion_junction->acceptor_prob);
      }
      printf("%s  %d:%s  %s  nmismatches:%s  ref_nmismatches:%s  ",
	     Univcoordlist_to_string(this->fusion_univdiagonals),this->fusion_chrnum,
	     Univcoordlist_to_string_offset(this->fusion_univdiagonals,this->fusion_chroffset),
	     Intlist_to_string(this->fusion_endpoints),
	     Intlist_to_string(this->fusion_nmismatches),Intlist_to_string(this->fusion_ref_nmismatches));
      printf("jcns:");
      Junction_print_list(this->fusion_junctions);
    }

    if (this->genomic_diff != NULL) {
      printf(" %s",this->genomic_diff);
    }

    printf("\n");
  }

  return;
}
#endif


void
Path_setup (bool *circularp_in, bool *altlocp_in) {
  circularp = circularp_in;
  altlocp = altlocp_in;
  return;
}


