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

#include "altsplice.h"
#include "genomicpos.h"

#include <stdio.h>
#include <string.h>		/* For memcpy */


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


#ifdef DEBUG10
#define debug10(x) x
#else
#define debug10(x)
#endif


#define T Altsplice_T


void
Altsplice_free (T *old, Pathpool_T pathpool) {
  if (*old) {
    /* Allocated by Vectorpool_T, and not reclaiming due to variable lengths */
    /* FREE_OUT((*old)->alts_coords); */
    /* FREE_OUT((*old)->alts_nmismatches); */
    /* FREE_OUT((*old)->alts_ref_nmismatches); */
    /* FREE_OUT((*old)->alts_probs); */
    Pathpool_free_altsplice(&(*old),pathpool
			    pathpool_trace(__FILE__,__LINE__)); /* Allocated by Pathpool_new_altsplice */
  }
  return;
}


void
Altsplice_print (T this) {
  int i;

  if (this != NULL) {
    
    for (i = 0; i < this->alts_ncoords; i++) {
      if (this->alts_probs[i] == this->best_distal_prob) {
	printf(" %u(%f-%f*)",this->alts_coords[i],this->medial_prob,this->alts_probs[i]);
      } else {
	printf(" %u(%f-%f)",this->alts_coords[i],this->medial_prob,this->alts_probs[i]);
      }
    }
  }
  return;
}


T
Altsplice_copy (T old, Pathpool_T pathpool, Vectorpool_T vectorpool) {
  T new;

  if (old == NULL) {
    return (T) NULL;
  } else {
    new = (T) Pathpool_new_altsplice(pathpool
				     pathpool_trace(__FILE__,__LINE__));

    new->distal_length = old->distal_length;
    new->medial_prob = old->medial_prob;

    new->best_nmatches = old->best_nmatches;
    new->best_distal_prob = old->best_distal_prob;

    new->alts_ncoords = old->alts_ncoords;
    new->alts_coords = Vectorpool_new_univcoordvector(vectorpool,old->alts_ncoords);
    new->alts_nmismatches = Vectorpool_new_intvector(vectorpool,old->alts_ncoords);
    new->alts_ref_nmismatches = Vectorpool_new_intvector(vectorpool,old->alts_ncoords);
    new->alts_probs = Vectorpool_new_doublevector(vectorpool,old->alts_ncoords);

    memcpy(new->alts_coords,old->alts_coords,old->alts_ncoords * sizeof(Univcoord_T));
    memcpy(new->alts_nmismatches,old->alts_nmismatches,old->alts_ncoords * sizeof(int));
    memcpy(new->alts_ref_nmismatches,old->alts_ref_nmismatches,old->alts_ncoords * sizeof(int));
    memcpy(new->alts_probs,old->alts_probs,old->alts_ncoords * sizeof(double));

    /* new->alt_type = old->alt_type; */

    return new;
  }
}


T
Altsplice_new (int distal_length, double medial_prob,
	       Univcoord_T *distal_splice_positions, int *distal_nmismatches,
	       double *distal_probs, int npartners,
	       Pathpool_T pathpool, Vectorpool_T vectorpool) {
  T new = Pathpool_new_altsplice(pathpool
				 pathpool_trace(__FILE__,__LINE__));
  int k;
  int min_nmismatches = distal_length;

  new->distal_length = distal_length;
  new->medial_prob = medial_prob;

  new->alts_ncoords = npartners;

  new->alts_coords = Vectorpool_new_univcoordvector(vectorpool,npartners);
  new->alts_nmismatches = Vectorpool_new_intvector(vectorpool,npartners);
  new->alts_ref_nmismatches = Vectorpool_new_intvector(vectorpool,npartners);
  new->alts_probs = Vectorpool_new_doublevector(vectorpool,npartners);

  new->best_distal_prob = 0.0;
  for (k = 0; k < npartners; k++) {
    if (distal_nmismatches[k] < min_nmismatches) {
      min_nmismatches = distal_nmismatches[k];
    }
    if (distal_probs[k] > new->best_distal_prob) {
      new->best_distal_prob = distal_probs[k];
    }

    /* Copy values */
    new->alts_coords[k] = distal_splice_positions[k];
    new->alts_nmismatches[k] = distal_nmismatches[k];
    new->alts_ref_nmismatches[k] = distal_nmismatches[k];
    new->alts_probs[k] = distal_probs[k];
  }

  new->best_nmatches = distal_length - min_nmismatches;

  return new;
}



bool
Altsplice_resolve_lower (Univcoord_T *univdiagonal_L, int *nmismatches_L, int *ref_nmismatches_L, double *prob_L,
			 T this, int querylengthL, int querylengthH,
			 Univcoord_T genomicstartH) {
  int besti = -1, i;
  Chrpos_T best_insertlength, insertlength;
  Univcoord_T genomicendL;
  int best_nmismatches, nmismatches;

  debug9(printf("Altsplice_resolve_lower\n"));

  best_insertlength = (Chrpos_T) -1;
  best_nmismatches = querylengthL;

  for (i = 0; i < this->alts_ncoords; i++) {
    genomicendL = this->alts_coords[i] + this->distal_length;
    /* debug9(printf(" Alt#%d:%u",i,(Chrpos_T) (genomicend - pathL->chroffset))); */
    /* debug9(printf(" [%u <? %u + %d]",genomicend - pathL->chroffset,hit3->genomicstart - pathH->chroffset,querylengthH)); */
    if (genomicendL < genomicstartH /*allow overlap*/+ querylengthH) {
      /* Look for valid insertlength */
      insertlength = genomicstartH - genomicendL + querylengthL + querylengthH;
      debug9(printf(" (insertlength %u)",insertlength));

      if (insertlength < best_insertlength) {
	besti = i;
	best_insertlength = insertlength;
	best_nmismatches = this->alts_nmismatches[i];
	debug9(printf("*"));

      } else if (insertlength == best_insertlength &&
		 (nmismatches = this->alts_nmismatches[i]) < best_nmismatches) {
	besti = i;
	best_nmismatches = nmismatches;
	debug9(printf("*"));

      } else if (nmismatches == best_nmismatches) {
	debug9(printf("tie"));
      }
    }
  }

  if (besti < 0) {
    return false;
  } else {
    *univdiagonal_L = this->alts_coords[besti] + this->distal_length;
    *nmismatches_L = this->alts_nmismatches[besti];
    *ref_nmismatches_L = this->alts_ref_nmismatches[besti];
    *prob_L = this->alts_probs[besti];
    return true;
  }
}


bool
Altsplice_resolve_higher (Univcoord_T *univdiagonal_H, int *nmismatches_H, int *ref_nmismatches_H, double *prob_H,
			  T this, int querylengthL, int querylengthH,
			  Univcoord_T genomicendL) {
  int bestj = -1, j;
  Chrpos_T best_insertlength, insertlength;
  Univcoord_T genomicstartH;
  int best_nmismatches, nmismatches;

  debug9(printf("Altsplice_resolve_higher\n"));

  best_insertlength = (Chrpos_T) -1;
  best_nmismatches = querylengthH;

  for (j = 0; j < this->alts_ncoords; j++) {
    genomicstartH = this->alts_coords[j] - this->distal_length;
    /* debug9(printf(" Alt#%d:%u",j,(Chrpos_T) (genomicstart - hit3->chroffset))); */
    /* debug9(printf(" [%u <? %u + %d]",hit5->genomicendL - hit5->chroffset,genomicstart - hi
t3->chroffset,querylength5)); */

    if (genomicendL < genomicstartH /*allow overlap*/+ querylengthH) {
      /* Look for valid insertlength */
      insertlength = genomicstartH - genomicendL + querylengthL + querylengthH;
      debug9(printf(" (insertlength %u)",insertlength));

      if (insertlength < best_insertlength) {
	bestj = j;
	best_insertlength = insertlength;
	best_nmismatches = this->alts_nmismatches[j];
	debug9(printf("*"));
	
      } else if (insertlength == best_insertlength &&
		 (nmismatches = this->alts_nmismatches[j]) < best_nmismatches) {
	bestj = j;
	best_nmismatches = nmismatches;
	debug9(printf("*"));

      } else if (nmismatches == best_nmismatches) {
	debug9(printf("tie"));
      }
    }
  }

  if (bestj < 0) {
    return false;
  } else {
    *univdiagonal_H = this->alts_coords[bestj] - this->distal_length + querylengthH;
    *nmismatches_H = this->alts_nmismatches[bestj];
    *ref_nmismatches_H = this->alts_ref_nmismatches[bestj];
    *prob_H = this->alts_probs[bestj];
    return true;
  }
}


bool
Altsplice_resolve_both (Univcoord_T *univdiagonal_L, int *nmismatches_L, int *ref_nmismatches_L, double *prob_L,
			Univcoord_T *univdiagonal_H, int *nmismatches_H, int *ref_nmismatches_H, double *prob_H,
			T thisL, T thisH, int querylengthL, int querylengthH) {
  int besti = -1, bestj = -1, i, j;
  Chrpos_T best_insertlength, insertlength;
  Univcoord_T genomicendL, genomicstartH;
  int best_nmismatches, nmismatches;

  debug9(printf("Altsplice_resolve_both\n"));

  best_insertlength = (Chrpos_T) -1;
  best_nmismatches = querylengthL + querylengthH;

  for (i = 0; i < thisL->alts_ncoords; i++) {
    genomicendL = thisL->alts_coords[i] + thisL->distal_length;
    for (j = 0; j < thisH->alts_ncoords; j++) {
      genomicstartH = thisH->alts_coords[j] - thisH->distal_length;
      /* debug9(printf(" Alt#%d,#%d:%u,%u",i,j,(Chrpos_T) (genomicendL - hit5->chroffset),(Chrpos_T) (genomicstart - hit3->chroffset))) */
      if (genomicendL < genomicstartH /*allow overlap*/+ querylengthH) {
	/* Look for valid insertlength */
	insertlength = genomicstartH - genomicendL + querylengthL + querylengthH;
	/* debug9(printf(" (insertlength %u)",insertlength)); */

	if (insertlength < best_insertlength) {
	  besti = i;
	  bestj = j;
	  best_insertlength = insertlength;
	  best_nmismatches = thisL->alts_nmismatches[i] + thisH->alts_nmismatches[j];
	  debug9(printf("*"));

	} else if (insertlength == best_insertlength &&
		   (nmismatches = thisL->alts_nmismatches[i] + thisH->alts_nmismatches[j]) < best_nmismatches) {
	  besti = i;
	  bestj = j;
	  best_nmismatches = nmismatches;
	  debug9(printf("*"));

	} else if (nmismatches == best_nmismatches) {
	  debug9(printf("tie"));
	}
      }
    }
  }

  if (besti < 0 || bestj < 0) {
    return false;
  } else {
    debug9(printf("\nBEST #%d and #%d HAS INSERTLENGTH %u AND NMISMATCHES %d\n",
		  besti,bestj,best_insertlength,best_nmismatches));
    *univdiagonal_L = thisL->alts_coords[besti] + thisL->distal_length;
    *nmismatches_L = thisL->alts_nmismatches[besti];
    *ref_nmismatches_L = thisL->alts_ref_nmismatches[besti];
    *prob_L = thisL->alts_probs[besti];

    *univdiagonal_H = thisH->alts_coords[bestj] - thisH->distal_length + querylengthH;
    *nmismatches_H = thisH->alts_nmismatches[bestj];
    *ref_nmismatches_H = thisH->alts_ref_nmismatches[bestj];
    *prob_H = thisH->alts_probs[bestj];

    return true;
  }
}
  
