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

#include "concordance.h"

#include <stdlib.h>		/* For qsort */
#include <stdio.h>
#include <string.h>
#include <strings.h>

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

#include "path.h"
#include "pathpair.h"
#include "path-solve.h"


static int subopt_levels;

static Chrpos_T pairmax_transcriptome;
static Chrpos_T pairmax_linear;	/* For two ends that both lack a splice */
static Chrpos_T pairmax_circular;

static bool two_pass_p;
static Chrpos_T adjacent_pairlength;  /* For two ends, one of which has a splice */

static bool *circularp;
static bool merge_samechr_p;


#define MAX_HITS 10000
#define MAX_OVERLAP 1000

#define T Path_T

/* Concordant paths */
#ifdef DEBUG0
#define debug0(x) x
#else
#define debug0(x)
#endif

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

/* Exhaustive listing of jj loop */
#ifdef DEBUG9
#define debug9(x) x
#else
#define debug9(x)
#endif




#ifdef DEBUG
static char *
print_sense (int sense) {
  if (sense == SENSE_NULL) {
    return "sense:null";
  } else if (sense == SENSE_ANTI) {
    return "sense:anti";
  } else if (sense == SENSE_FORWARD) {
    return "sense:fwd";
  } else {
    abort();
  }
}
#endif


/* pathsL are the lower paths, and pathsH are the higher ones in the genome */
/* All paths are pointing toward higher coordinates, on the plus genome */
/* For alignment to the plus genome strand, pathsL is paths5 and pathsH is paths3 */
/* For alignment to the minus genome strand, pathsL is paths3 and pathsH is paths5 */
static List_T
do_genome (int *found_score_paired, int *found_score_5, int *found_score_3,
	   bool *found_transcriptp_5, bool *found_transcriptp_3,
	   T *pathsL, int npathsL, T *pathsH, int npathsH, Shortread_T queryseqL, Shortread_T queryseqH,
	   Compress_T query_compress_L, Compress_T queryL_compress_fwd, Compress_T queryL_compress_rev,
	   Compress_T query_compress_H, Compress_T queryH_compress_fwd, Compress_T queryH_compress_rev,
	   char *queryptrL, char *queryptrH, int genestrand, int querylengthL, int querylengthH, 
	   int *mismatch_positions_alloc_L, int *mismatch_positions_alloc_H,
	   Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc, Stage1_T stage1L, Stage1_T stage1H,
	   Knownsplicing_T knownsplicing, Knownindels_T knownindels,
	   Spliceendsgen_T spliceendsgenL, Spliceendsgen_T spliceendsgenH,
	   int nmismatches_allowed_L, int nmismatches_allowed_H,
	   int max_insertionlen_L, int max_insertionlen_H, int max_deletionlen_L, int max_deletionlen_H,
	   Chrpos_T overall_end_distance_L, Chrpos_T overall_end_distance_H,
	   Intlistpool_T intlistpool, Uintlistpool_T uintlistpool, Univcoordlistpool_T univcoordlistpool,
	   Listpool_T listpool,  Pathpool_T pathpool, Transcriptpool_T transcriptpool,
	   Vectorpool_T vectorpool, Hitlistpool_T hitlistpool, 
	   bool require_transcript_intersectp, Pass_T pass, bool plusp) {

  List_T pathpairs = NULL;
  int *found_score;
  bool *found_transcriptp;
  int nfound = 0, noverlap;
  int i, j;
  T pathL, pathH, newpathL, newpathH;
  List_T newpathsL, newpathsH, p, q;
  bool unextendedL_p, unextendedH_p, completep;
  Pathpair_T pathpair;
  Univcoord_T genomiclowL, genomichighL, genomichighH;
  Univcoord_T insert_start;
  int pairmax;
#ifdef DEBUG
  Univcoord_T genomiclowH;
#endif
#ifdef DEBUG9
  int jj;
#endif

  debug(printf("Entered do_genome with %d pathsL and %d pathsH, require transcript intersectp %d\n",
	       npathsL,npathsH,require_transcript_intersectp));
  if (npathsL > 0 && npathsH > 0) {
    i = j = 0;
    while (i < npathsL) {
      pathL = pathsL[i];
      assert(pathL->plusp == plusp);
      if (circularp[pathL->chrnum] == true) {
	pairmax = pairmax_circular;
      } else {
	pairmax = pairmax_linear;
      }
      
      genomiclowL = Path_genomiclow(pathL);
      genomichighL = Path_genomichigh(pathL);
      insert_start = genomichighL - querylengthL;

#ifdef DEBUG
      printf("%s/%s insert_start %u = genomichighL %u - querylengthL %d\n",
	     plusp == true ? "plus" : "minus",plusp == true ? "plus" : "minus",
	     insert_start - pathL->chroffset,genomichighL - pathL->chroffset,querylengthL);
      printf("%s/%s: i=%d/%d #%d:%u..%u %s %s %p",
	     plusp == true ? "plus" : "minus",plusp == true ? "plus" : "minus",
	     i,npathsL,pathL->chrnum,genomiclowL - pathL->chroffset,genomichighL - pathL->chroffset,
	     print_sense(pathL->sensedir),Method_string(pathL->method),pathL);
      if (j >= 0 && j < npathsH) {
	genomiclowH = Path_genomiclow(pathsH[j]);
	genomichighH = Path_genomichigh(pathsH[j]);
	printf("    j=%d/%d #%d:%u..%u %p",j,npathsH,pathsH[j]->chrnum,
	       genomiclowH - pathsH[j]->chroffset,genomichighH - pathsH[j]->chroffset,pathsH[j]);
      }
      printf("\n");
#endif

      while (j >= 0 && 
	     /*insert_end*/Path_genomiclow(pathsH[j]) + querylengthH /* for scramble: */ + pairmax > insert_start) {
#ifdef DEBUG
	genomiclowH = Path_genomiclow(pathsH[j]);
	genomichighH = Path_genomichigh(pathsH[j]);
	printf("  backup: j=%d/%d #%d:%u..%u %s %s %p\n",
	       j,npathsH,pathsH[j]->chrnum,genomiclowH - pathsH[j]->chroffset,genomichighH - pathsH[j]->chroffset,
	       print_sense(pathsH[j]->sensedir),Method_string(pathsH[j]->method),pathsH[j]);
#endif
	j--;
      }
      j++;		/* Finish backup */

      while (j < npathsH && 
	     /*insert_end*/Path_genomiclow(pathsH[j]) + querylengthH /* for scramble: */ + pairmax <= insert_start) {
#ifdef DEBUG
	genomiclowH = Path_genomiclow(pathsH[j]);
	genomichighH = Path_genomichigh(pathsH[j]);
	printf("  advance: j=%d/%d #%d:%u..%u %s %s %p\n",
	       j,npathsH,pathsH[j]->chrnum,genomiclowH - pathsH[j]->chroffset,genomichighH - pathsH[j]->chroffset,
	       print_sense(pathsH[j]->sensedir),Method_string(pathsH[j]->method),pathsH[j]);
#endif
	j++;
      }
      
      noverlap = 0;
      while (nfound <= MAX_HITS &&
	     noverlap++ < MAX_OVERLAP && j < npathsH &&
	     /*insert_end*/Path_genomiclow(pathsH[j]) + querylengthH <= pairmax + insert_start) {
	genomichighH = Path_genomichigh(pathsH[j]);
#ifdef DEBUG
	genomiclowH = Path_genomiclow(pathsH[j]);
	printf("  overlap: j=%d/%d #%d:%u..%u %s %s %p",
		     j,npathsH,pathsH[j]->chrnum,genomiclowH - pathsH[j]->chroffset,genomichighH - pathsH[j]->chroffset,
		     print_sense(pathsH[j]->sensedir),Method_string(pathsH[j]->method),pathsH[j]);
#endif
	pathH = pathsH[j];
	assert(pathH->plusp == plusp);
	
	if (pathL->chrnum != pathH->chrnum) {
	  debug(printf(" => diff chrs %d and %d",pathL->chrnum,pathH->chrnum));
	  
	} else if (SENSE_INCONSISTENT_P(pathL->sensedir,pathH->sensedir)) {
	  /* Use sensedir_for_concordance here and not sensedir */
	  debug(printf(" => sense inconsistent: %d | %d = %d",pathL->sensedir,pathH->sensedir,pathL->sensedir|pathH->sensedir));
	  
	} else if (genomichighH < genomiclowL) {
	  debug(printf(" => scramble because endH %llu < startL %llu\n",
		       (unsigned long long) genomichighH,(unsigned long long) genomiclowL));
	  
	} else if (require_transcript_intersectp == true &&
		   Pathpair_transcript_intersectp(pathL,pathH) == false) {
	  debug(printf(" => transcripts do not intersect\n"));

	} else {
	  debug0(printf(" => concordant effchr %d (chrnumL %d, chrnumH %d)",pathL->chrnum,pathL->chrnum,pathH->chrnum));
	  assert(pathL->plusp == plusp);
	  assert(pathH->plusp == plusp);
	  debug0(Path_print(pathL));
	  debug0(Path_print(pathH));
	  debug0(printf("\n"));
	  
	  if ((unextendedL_p = Path_unextendedp(pathL,/*endtrim_allowed*/0,/*allow_ambig_p*/false)) == false) {
	    newpathsL = (List_T) NULL;
	  } else {
	    found_score = (pathL->plusp == true) ? found_score_5 : found_score_3;
	    found_transcriptp = (pathL->plusp == true) ? found_transcriptp_5 : found_transcriptp_3;
	    newpathsL = Path_extend(&completep,&(*found_score),&(*found_transcriptp),
				    pathL,queryseqL,queryptrL,querylengthL,
				    mismatch_positions_alloc_L,novel_diagonals_alloc,localdb_alloc,
				    stage1L->streamspace_max_alloc,stage1L->streamspace_alloc,
				    stage1L->streamptr_alloc,stage1L->streamsize_alloc,stage1L->mergeinfo,
				    stage1L->indelinfo,stage1L->spliceinfo,
				    knownsplicing,knownindels,query_compress_L,
				    queryL_compress_fwd,queryL_compress_rev,genestrand,
				    max_insertionlen_L,max_deletionlen_L,overall_end_distance_L,
				    nmismatches_allowed_L,/*paired_end_p*/true,/*lowp*/true,
				    intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				    vectorpool,hitlistpool,spliceendsgenL,pass,
				    /*extend_qstart_p*/true,/*extend_qend_p*/true);
	  }
	  if ((unextendedH_p = Path_unextendedp(pathH,/*endtrim_allowed*/0,/*allow_ambig_p*/false)) == false) {
	    newpathsH = (List_T) NULL;
	  } else {
	    found_score = (pathH->plusp == true) ? found_score_3 : found_score_5;
	    found_transcriptp = (pathH->plusp == true) ? found_transcriptp_3 : found_transcriptp_5;
	    newpathsH = Path_extend(&completep,&(*found_score),&(*found_transcriptp),
				    pathH,queryseqH,queryptrH,querylengthH,
				    mismatch_positions_alloc_H,novel_diagonals_alloc,localdb_alloc,
				    stage1H->streamspace_max_alloc,stage1H->streamspace_alloc,
				    stage1H->streamptr_alloc,stage1H->streamsize_alloc,stage1H->mergeinfo,
				    stage1H->indelinfo,stage1H->spliceinfo,
				    knownsplicing,knownindels,query_compress_H,
				    queryH_compress_fwd,queryH_compress_rev,genestrand,
				    max_insertionlen_H,max_deletionlen_H,overall_end_distance_H,
				    nmismatches_allowed_H,/*paired_end_p*/true,/*lowp*/false,
				    intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				    vectorpool,hitlistpool,spliceendsgenH,pass,
				    /*extend_qstart_p*/true,/*extend_qend_p*/true);
	  }

	  /* Always copying path5 and path3 allows us to call Stage1hr_free with free_paths_p being true */
	  if (unextendedL_p == true && unextendedH_p == true) {
	    for (p = newpathsL; p != NULL; p = List_next(p)) {
	      newpathL = (Path_T) List_head(p);
	      for (q = newpathsH; q != NULL; q = List_next(q)) {
		newpathH = (Path_T) List_head(q);
		if ((pathpair =
		     Pathpair_new_concordant(newpathL,newpathH,queryseqL,queryseqH,plusp,
					     intlistpool,univcoordlistpool,listpool,
					     pathpool,vectorpool,transcriptpool,
					     /*copyLp (was false)*/true,/*copyHp (was false)*/true)) != NULL) {
		  debug0(printf("Pathpair found\n"));
		  if (Pathpair_found_score(pathpair) < *found_score_paired) {
		    *found_score_paired = Pathpair_found_score(pathpair);
		  }
		  pathpairs = Hitlist_push(pathpairs,hitlistpool,(void *) pathpair
					   hitlistpool_trace(__FILE__,__LINE__));
		  nfound++;
		}
	      }
	    }

	  } else if (unextendedL_p == true) {
	    for (p = newpathsL; p != NULL; p = List_next(p)) {
	      newpathL = (Path_T) List_head(p);
	      if ((pathpair =
		   Pathpair_new_concordant(newpathL,pathH,queryseqL,queryseqH,plusp,
					   intlistpool,univcoordlistpool,listpool,
					   pathpool,vectorpool,transcriptpool,
					    /*copyLp (was false)*/true,/*copyHp*/true)) != NULL) {
		debug0(printf("Pathpair found\n"));
		if (Pathpair_found_score(pathpair) < *found_score_paired) {
		  *found_score_paired = Pathpair_found_score(pathpair);
		}
		pathpairs = Hitlist_push(pathpairs,hitlistpool,(void *) pathpair
					 hitlistpool_trace(__FILE__,__LINE__));
		nfound++;
	      }
	    }

	  } else if (unextendedH_p == true) {
	    for (q = newpathsH; q != NULL; q = List_next(q)) {
	      newpathH = (Path_T) List_head(q);
	      if ((pathpair =
		   Pathpair_new_concordant(pathL,newpathH,queryseqL,queryseqH,plusp,
					   intlistpool,univcoordlistpool,listpool,
					   pathpool,vectorpool,transcriptpool,
					    /*copyLp*/true,/*copyHp (was false)*/true)) != NULL) {
		debug0(printf("Pathpair found\n"));
		if (Pathpair_found_score(pathpair) < *found_score_paired) {
		  *found_score_paired = Pathpair_found_score(pathpair);
		}
		pathpairs = Hitlist_push(pathpairs,hitlistpool,(void *) pathpair
					 hitlistpool_trace(__FILE__,__LINE__));
		nfound++;
	      }
	    }
	    
	  } else {
	    if ((pathpair =
		 Pathpair_new_concordant(pathL,pathH,queryseqL,queryseqH,plusp,
					 intlistpool,univcoordlistpool,listpool,
					 pathpool,vectorpool,transcriptpool,
					 /*copyLp*/true,/*copyHp*/true)) != NULL) {
	      debug0(printf("Pathpair found\n"));
	      if (Pathpair_found_score(pathpair) < *found_score_paired) {
		*found_score_paired = Pathpair_found_score(pathpair);
	      }
	      pathpairs = Hitlist_push(pathpairs,hitlistpool,(void *) pathpair
				       hitlistpool_trace(__FILE__,__LINE__));
	      nfound++;
	    }
	  }

#if 1
	  /* Must be careful to append newpaths to the front of the
	     list, since we called Concordance_simple with pointers
	     to the list */
	  if (plusp == true) {
	    for (p = newpathsL; p != NULL; p = List_next(p)) {
	      newpathL = (Path_T) List_head(p);
	      if (newpathL->sensedir == SENSE_FORWARD) {
		stage1L->sense_paths_gplus = Hitlist_push(stage1L->sense_paths_gplus,hitlistpool,(void *) newpathL
							  hitlistpool_trace(__FILE__,__LINE__));
	      } else {
		stage1L->antisense_paths_gplus = Hitlist_push(stage1L->antisense_paths_gplus,hitlistpool,(void *) newpathL
							      hitlistpool_trace(__FILE__,__LINE__));
	      }
	    }
	    for (q = newpathsH; q != NULL; q = List_next(q)) {
	      newpathH = (Path_T) List_head(q);
	      if (newpathH->sensedir == SENSE_FORWARD) {
		stage1H->sense_paths_gplus = Hitlist_push(stage1H->sense_paths_gplus,hitlistpool,(void *) newpathH
							  hitlistpool_trace(__FILE__,__LINE__));
	      } else {
		stage1H->antisense_paths_gplus = Hitlist_push(stage1H->antisense_paths_gplus,hitlistpool,(void *) newpathH
							      hitlistpool_trace(__FILE__,__LINE__));
	      }
	    }
	  } else {
	    for (p = newpathsL; p != NULL; p = List_next(p)) {
	      newpathL = (Path_T) List_head(p);
	      if (newpathL->sensedir == SENSE_FORWARD) {
		stage1L->sense_paths_gminus = Hitlist_push(stage1L->sense_paths_gminus,hitlistpool,(void *) newpathL
							   hitlistpool_trace(__FILE__,__LINE__));
	      } else {
		stage1L->antisense_paths_gminus = Hitlist_push(stage1L->antisense_paths_gminus,hitlistpool,(void *) newpathL
							       hitlistpool_trace(__FILE__,__LINE__));
	      }
	    }
	    for (q = newpathsH; q != NULL; q = List_next(q)) {
	      newpathH = (Path_T) List_head(q);
	      if (newpathH->sensedir == SENSE_FORWARD) {
		stage1H->sense_paths_gminus = Hitlist_push(stage1H->sense_paths_gminus,hitlistpool,(void *) newpathH
							   hitlistpool_trace(__FILE__,__LINE__));
	      } else {
		stage1H->antisense_paths_gminus = Hitlist_push(stage1H->antisense_paths_gminus,hitlistpool,(void *) newpathH
							       hitlistpool_trace(__FILE__,__LINE__));
	      }
	    }
	  }

	  Hitlistpool_free_list(&newpathsL,hitlistpool
				hitlistpool_trace(__FILE__,__LINE__));
	  Hitlistpool_free_list(&newpathsH,hitlistpool
				hitlistpool_trace(__FILE__,__LINE__));

#else
	  Path_gc(&newpathsL,intlistpool,univcoordlistpool,pathpool,transcriptpool,hitlistpool);
	  Path_gc(&newpathsH,intlistpool,univcoordlistpool,pathpool,transcriptpool,hitlistpool);
#endif

	}
	debug(printf("\n"));
	
	j++;
      }

#ifdef DEBUG9
      jj = j;
      while (jj < npathsH) {
	genomiclowH = Path_genomiclow(pathsH[jj]);
	genomichighH = Path_genomichigh(pathsH[jj]);
	printf("  skipping because genomiclowH %u + querylength %d > pairmax %u + insert_start %u\n",
	       genomiclowH - pathsH[jj]->chroffset,querylengthH,pairmax,insert_start - pathL->chroffset);
	printf("  skipping: j=%d/%d #%d:%u..%u %s %s %p",
	       jj,npathsH,pathsH[jj]->chrnum,genomiclowH - pathsH[jj]->chroffset,genomichighH - pathsH[jj]->chroffset,
	       print_sense(pathsH[jj]->sensedir),Method_string(pathsH[jj]->method),pathsH[jj]);
	printf("\n");

	jj++;
      }
#endif

      j--;		/* Finish advance */
      
      i++;
    }
  }

  if (nfound > MAX_HITS) {
    debug(printf("In do_genome, nfound is %d, so returning NULL\n",nfound));
    Pathpair_gc(&pathpairs,intlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,hitlistpool);
    return (List_T) NULL;

  } else {
    debug(printf("Returning %d concordant pathpairs, accumulated\n",List_length(pathpairs)));
    return pathpairs;
  }
}


/* This procedure tries to find the best concordance, based on score.  But with paths, we want concordance before we have scored them */
List_T
Concordance_simple (int *found_score_paired, int *found_score_5, int *found_score_3,
		    bool *found_transcriptp_5, bool *found_transcriptp_3,
		    List_T pathpairs,

		    List_T newpaths5_gplus, List_T newpaths5_gminus,
		    List_T newpaths3_gplus, List_T newpaths3_gminus,
		    List_T paths5_gplus, List_T paths5_gminus,
		    List_T paths3_gplus, List_T paths3_gminus,
		    
		    Compress_T query5_compress_fwd, Compress_T query5_compress_rev,
		    Compress_T query3_compress_fwd, Compress_T query3_compress_rev,

		    Shortread_T queryseq5, Shortread_T queryseq3,
		    char *queryuc_ptr_5, char *queryrc5, char *queryuc_ptr_3, char *queryrc3,
		    int querylength5, int querylength3, Stage1_T stage1_5, Stage1_T stage1_3, 

		    int *mismatch_positions_alloc_5, int *mismatch_positions_alloc_3,
		    Univcoord_T *novel_diagonals_alloc, unsigned short *localdb_alloc,
		    Knownsplicing_T knownsplicing, Knownindels_T knownindels,
		    Spliceendsgen_T spliceendsgen5, Spliceendsgen_T spliceendsgen3,

		    int nmismatches_allowed_5, int nmismatches_allowed_3,
		    int max_insertionlen_5, int max_insertionlen_3, int max_deletionlen_5, int max_deletionlen_3,
		    Chrpos_T overall_end_distance_5, Chrpos_T overall_end_distance_3,

		    Intlistpool_T intlistpool, Uintlistpool_T uintlistpool, Univcoordlistpool_T univcoordlistpool,
		    Listpool_T listpool, Pathpool_T pathpool, Transcriptpool_T transcriptpool,
		    Vectorpool_T vectorpool, Hitlistpool_T hitlistpool, int genestrand,
		    bool require_transcript_intersectp, Pass_T pass) {

  T *allpaths5, *allpaths3;
  int nnewpaths5, nnewpaths3, npaths5, npaths3;

  debug(printf("Entered Concordance_simple with %d pathpairs, newpaths5 %d+%d, newpaths3 %d+%d, paths5 %d+%d, paths3 %d+%d\n",
	       List_length(pathpairs),List_length(newpaths5_gplus),List_length(newpaths5_gminus),
	       List_length(newpaths3_gplus),List_length(newpaths3_gminus),
	       List_length(paths5_gplus),List_length(paths5_gminus),
	       List_length(paths3_gplus),List_length(paths3_gminus)));

  /* Plus */
  nnewpaths5 = List_length(newpaths5_gplus);
  nnewpaths3 = List_length(newpaths3_gplus);
  npaths5 = List_length(paths5_gplus);
  npaths3 = List_length(paths3_gplus);

  debug(printf("plus: %d+%d paths5 (pathsL) and %d+%d new paths3 (pathsH)\n",
	       npaths5,npaths3,nnewpaths5,nnewpaths3));

  if (nnewpaths5 + npaths5 > 0 && nnewpaths3 + npaths3 > 0) {
    allpaths5 = (T *) MALLOC((nnewpaths5 + npaths5)*sizeof(T));
    allpaths3 = (T *) MALLOC((nnewpaths3 + npaths3)*sizeof(T));

    /* New paths 5 vs All paths 3, plus */
    List_fill_array((void **) allpaths5,newpaths5_gplus);
    List_fill_array((void **) allpaths3,newpaths3_gplus);
    List_fill_array((void **) &(allpaths3[nnewpaths3]),paths3_gplus);

    qsort(allpaths5,nnewpaths5,sizeof(T),Path_genomichigh_cmp);
    qsort(allpaths3,nnewpaths3 + npaths3,sizeof(T),Path_genomiclow_cmp);
    
    pathpairs = List_append(pathpairs,
			    do_genome(&(*found_score_paired),&(*found_score_5),&(*found_score_3),
				      &(*found_transcriptp_5),&(*found_transcriptp_3),
				      /*pathsL*/allpaths5,/*npathsL*/nnewpaths5,
				      /*pathsH*/allpaths3,/*npathsH*/nnewpaths3 + npaths3,
				      /*queryseqL*/queryseq5,/*queryseqH*/queryseq3,
				      /*query_compress_L*/query5_compress_fwd,query5_compress_fwd,query5_compress_rev,
				      /*query_compress_H*/query3_compress_fwd,query3_compress_fwd,query3_compress_rev,
				      queryuc_ptr_5,queryuc_ptr_3,genestrand,querylength5,querylength3,
				      mismatch_positions_alloc_5,mismatch_positions_alloc_3,
				      novel_diagonals_alloc,localdb_alloc,/*stage1L*/stage1_5,/*stage1H*/stage1_3,
				      knownsplicing,knownindels,spliceendsgen5,spliceendsgen3,
				      nmismatches_allowed_5,nmismatches_allowed_3,
				      max_insertionlen_5,max_insertionlen_3,max_deletionlen_5,max_deletionlen_3,
				      overall_end_distance_5,overall_end_distance_3,
				      intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				      vectorpool,hitlistpool,require_transcript_intersectp,pass,/*plusp*/true));

    /* All hits 5 vs New hits 3, plus */
    /* List_fill_array((void **) allpaths5,newpaths5_gplus); -- Already filled above */
    List_fill_array((void **) &(allpaths5[nnewpaths5]),paths5_gplus);
    List_fill_array((void **) allpaths3,newpaths3_gplus);

    qsort(allpaths5,nnewpaths5 + npaths5,sizeof(T),Path_genomichigh_cmp);
    qsort(allpaths3,nnewpaths3,sizeof(T),Path_genomiclow_cmp);

    pathpairs = List_append(pathpairs,
			    do_genome(&(*found_score_paired),&(*found_score_5),&(*found_score_3),
				      &(*found_transcriptp_5),&(*found_transcriptp_3),
				      /*pathsL*/allpaths5,/*npathsL*/nnewpaths5 + npaths5,
				      /*pathsH*/allpaths3,/*npathsH*/nnewpaths3,
				      /*queryseqL*/queryseq5,/*queryseqH*/queryseq3,
				      /*query_compress_L*/query5_compress_fwd,query5_compress_fwd,query5_compress_rev,
				      /*query_compress_H*/query3_compress_fwd,query3_compress_fwd,query3_compress_rev,
				      queryuc_ptr_5,queryuc_ptr_3,genestrand,querylength5,querylength3,
				      mismatch_positions_alloc_5,mismatch_positions_alloc_3,
				      novel_diagonals_alloc,localdb_alloc,/*stage1L*/stage1_5,/*stage1H*/stage1_3,
				      knownsplicing,knownindels,spliceendsgen5,spliceendsgen3,
				      nmismatches_allowed_5,nmismatches_allowed_3,
				      max_insertionlen_5,max_insertionlen_3,max_deletionlen_5,max_deletionlen_3,
				      overall_end_distance_5,overall_end_distance_3,
				      intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				      vectorpool,hitlistpool,require_transcript_intersectp,pass,/*plusp*/true));
    FREE(allpaths3);
    FREE(allpaths5);
  }


  /* Minus */

  nnewpaths3 = List_length(newpaths3_gminus);
  nnewpaths5 = List_length(newpaths5_gminus);
  npaths3 = List_length(paths3_gminus);
  npaths5 = List_length(paths5_gminus);

  debug(printf("minus: %d+%d paths5 (pathsH) and %d+%d new paths3 (pathsL)\n",
	       npaths5,npaths3,nnewpaths5,nnewpaths3));

  if (nnewpaths3 + npaths3 > 0 && nnewpaths5 + npaths5 > 0) {
    allpaths3 = (T *) MALLOC((nnewpaths3 + npaths3)*sizeof(T));
    allpaths5 = (T *) MALLOC((nnewpaths5 + npaths5)*sizeof(T));

    /* New hits 5 vs All hits 3, minus */
    List_fill_array((void **) allpaths3,newpaths3_gminus);
    List_fill_array((void **) &(allpaths3[nnewpaths3]),paths3_gminus);
    List_fill_array((void **) allpaths5,newpaths5_gminus);

    qsort(allpaths5,nnewpaths5,sizeof(T),Path_genomichigh_cmp);
    qsort(allpaths3,nnewpaths3 + npaths3,sizeof(T),Path_genomiclow_cmp);

    pathpairs = List_append(pathpairs,
			    do_genome(&(*found_score_paired),&(*found_score_5),&(*found_score_3),
				      &(*found_transcriptp_5),&(*found_transcriptp_3),
				      /*pathsL*/allpaths3,/*npathsL*/nnewpaths3 + npaths3,
				      /*pathsH*/allpaths5,/*npathsH*/nnewpaths5,
				      /*queryseqL*/queryseq3,/*queryseqH*/queryseq5,
				      /*query_compress_L*/query3_compress_rev,query3_compress_fwd,query3_compress_rev,
				      /*query_compress_H*/query5_compress_rev,query5_compress_fwd,query5_compress_rev,
				      queryrc3,queryrc5,genestrand,querylength3,querylength5,
				      mismatch_positions_alloc_3,mismatch_positions_alloc_5,
				      novel_diagonals_alloc,localdb_alloc,/*stage1L*/stage1_3,/*stage1H*/stage1_5,
				      knownsplicing,knownindels,spliceendsgen3,spliceendsgen5,
				      nmismatches_allowed_3,nmismatches_allowed_5,
				      max_insertionlen_3,max_insertionlen_5,max_deletionlen_3,max_deletionlen_5,
				      overall_end_distance_3,overall_end_distance_5,
				      intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				      vectorpool,hitlistpool,require_transcript_intersectp,pass,/*plusp*/false));
  
    /* All hits 5 vs New hits 3, minus */
    List_fill_array((void **) allpaths3,newpaths3_gminus);
    /* List_fill_array((void **) allpaths5,newpaths5_gminus); -- Already filled above */
    List_fill_array((void **) &(allpaths5[nnewpaths5]),paths5_gminus);

    qsort(allpaths3,nnewpaths3,sizeof(T),Path_genomiclow_cmp);
    qsort(allpaths5,nnewpaths5 + npaths5,sizeof(T),Path_genomichigh_cmp);

    pathpairs = List_append(pathpairs,
			    do_genome(&(*found_score_paired),&(*found_score_5),&(*found_score_3),
				      &(*found_transcriptp_5),&(*found_transcriptp_3),
				      /*pathsL*/allpaths3,/*npathsL*/nnewpaths3,
				      /*pathsH*/allpaths5,/*npathsH*/nnewpaths5 + npaths5,
				      /*queryseqL*/queryseq3,/*queryseqH*/queryseq5,
				      /*query_compress_L*/query3_compress_rev,query3_compress_fwd,query3_compress_rev,
				      /*query_compress_H*/query5_compress_rev,query5_compress_fwd,query5_compress_rev,
				      queryrc3,queryrc5,genestrand,querylength3,querylength5,
				      mismatch_positions_alloc_3,mismatch_positions_alloc_5,
				      novel_diagonals_alloc,localdb_alloc,/*stage1L*/stage1_3,/*stage1H*/stage1_5,
				      knownsplicing,knownindels,spliceendsgen3,spliceendsgen5,
				      nmismatches_allowed_3,nmismatches_allowed_5,
				      max_insertionlen_3,max_insertionlen_5,max_deletionlen_3,max_deletionlen_5,
				      overall_end_distance_3,overall_end_distance_5,
				      intlistpool,uintlistpool,univcoordlistpool,listpool,pathpool,transcriptpool,
				      vectorpool,hitlistpool,require_transcript_intersectp,pass,/*plusp*/false));
    FREE(allpaths3);
    FREE(allpaths5);
  }

  return pathpairs;
}


void
Concordance_setup (int subopt_levels_in, Chrpos_T pairmax_transcriptome_in,
		   Chrpos_T pairmax_linear_in, Chrpos_T pairmax_circular_in,
		   bool *circularp_in, bool merge_samechr_p_in, bool two_pass_p_in) {
  subopt_levels = subopt_levels_in;

  pairmax_transcriptome = pairmax_transcriptome_in;
  pairmax_linear = pairmax_linear_in;
  pairmax_circular = pairmax_circular_in;

  adjacent_pairlength = 0;

  circularp = circularp_in;
  merge_samechr_p = merge_samechr_p_in;
  two_pass_p = two_pass_p_in;

  return;
}


void
Concordance_pass2_setup (double expected_pairlength_in, double pairlength_deviation_in) {
  adjacent_pairlength = (Chrpos_T) (expected_pairlength_in + pairlength_deviation_in);
  return;
}

