// File: /workspace/github_c_makefile_star2_O2/sc932[P]ALE/src/ALElike.c
// Function: setAlignment
enum MATE_ORIENTATION setAlignment(bam_header_t *header, assemblyT *theAssembly, alignSet_t *thisAlignment, void **mateTree1, void **mateTree2, libraryParametersT *libParams, enum MATE_ORIENTATION orientation, bam1_t *thisRead) {
  assert(thisAlignment != NULL);
  double loglikelihoodRead1 = 0.0;
  double loglikelihoodRead2 = 0.0;
  double logzNormalizeRead1, logzNormalizeRead2;

  double likelihoodInsert = 0.0;
  double likelihoodPlacement = 0.0;

  _setAlignment(thisAlignment, thisRead, NULL);

  // ************* //
  // NORMALIZATION //
  // ************* //

  // divide by the expected likelihood of the read by the normalization factor Z (from Bayes rule)
  // (read-qual normalization happens in setAlignment(q)
  // given only its length and the parameters of the distributions (See paper appendix)

  int qOff = libParams->qOff;
  if (thisAlignment->contigId1 >= 0) {
    //char *md1 = getMD(thisRead, theAssembly->contigs[thisRead->core.tid]->seq);
    //loglikelihoodRead1  = getMatchLogLikelihoodBAM(thisRead, qOff, md1);
    loglikelihoodRead1  = getMatchLogLikelihoodBAM(thisRead, theAssembly->contigs[thisRead->core.tid], qOff, thisAlignment->end1 - thisAlignment->start1);
    logzNormalizeRead1 = logzNormalizationReadQual(thisRead, qOff);
  }

  //printf("Likelihoods1 (%s): %12f %12f %s\n", bam1_qname(thisRead), loglikelihoodRead1, logzNormalizeRead1, MATE_ORIENTATION_LABELS[orientation]);

  libraryMateParametersT *mateParameters = &libParams->mateParameters[orientation];
  libraryMateParametersT *primaryMateParameters = &libParams->mateParameters[libParams->primaryOrientation];

  switch (orientation) {
    case (VALID_FR):
    case (VALID_RF):
    case (VALID_FF):
    case (NOT_PROPER_FR):
    case (NOT_PROPER_RF):
    case (NOT_PROPER_FF):
      // two reads, both mapped

      assert(thisAlignment->contigId1 >= 0);
      assert(thisAlignment->contigId2 >= 0);

      // valid orientation

      bam1_t *thisReadMate = getOrStoreMate(mateTree1, mateTree2, thisRead);

      if (thisReadMate != NULL) {
          // place this valid pair
          validateAlignmentMates(thisAlignment, thisRead, thisReadMate);

          _setAlignment(thisAlignment, thisRead, thisReadMate);

          //char *md2 = getMD(thisReadMate, theAssembly->contigs[thisReadMate->core.tid]->seq);
          //loglikelihoodRead2 = getMatchLogLikelihoodBAM(thisReadMate, qOff, md2);
          loglikelihoodRead2 = getMatchLogLikelihoodBAM(thisReadMate, theAssembly->contigs[thisReadMate->core.tid], qOff, thisAlignment->end2 - thisAlignment->start2);
          logzNormalizeRead2 = logzNormalizationReadQual(thisReadMate, qOff);

          //printf("Likelihoods2 (%s): %12f %12f\n", bam1_qname(thisRead), loglikelihoodRead2, logzNormalizeRead2);

          if (mateParameters->isValid == 1) {
              if ( isValidInsertSize(thisRead, mateParameters) ) { // i.e. within SIGMA_RANGE sigma
                  // this is a valid mate pair within a good insert size distribution
                  likelihoodInsert = getInsertLikelihoodBAM(thisRead, mateParameters->insertLength, mateParameters->insertStd) / mateParameters->zNormalizationInsert;
              } else {
                  // cap insert size contribution to SIGMA_RANGE sigma
                  likelihoodInsert = GetCappedInsertProbNormal(SIGMA_RANGE, mateParameters->insertStd) / mateParameters->zNormalizationInsert ; // punish it with SIGMA_RANGE sigma from normal
              }
          } else {
              // not a valid distribution... treat like chimer
              //likelihoodInsert = exp(getMinLogLike()) / primaryMateParameters->zNormalizationInsert; // punish it
              likelihoodInsert = GetCappedInsertProbNormal(SIGMA_RANGE+1.0, primaryMateParameters->insertStd) / primaryMateParameters->zNormalizationInsert; // punish it with SIGMA_RANGE+1 sigma from normal
          }
          likelihoodPlacement = mateParameters->libraryFraction; // orientation likelihood
          likelihoodPlacement *= exp( loglikelihoodRead1 - logzNormalizeRead1 + loglikelihoodRead2 - logzNormalizeRead2 ); // match likelihood
          
          if (likelihoodPlacement == 0.0) {
        	  orientation = UNMAPPED_PAIR;
          }
          // printf("Likelihood (%s): %12f\n", bam1_qname(thisRead), thisAlignment->likelihood);
          //bam_destroy1(thisReadMate);

          //printf("Applying read mate pair %s. %f %f\n", bam1_qname(thisRead), thisAlignment->likelihood, likelihoodInsert);
      } else {
          // do not process this read yet
          likelihoodPlacement = 0.0;
          likelihoodInsert = 0.0;
          orientation = HALF_VALID_MATE;
      }
      break;

      //  continue... this is actually a chimer
    case (CHIMER) :
      ////printf("WARNING: chimeric read mate pair %s.\n", bam1_qname(thisRead));

      assert(thisAlignment->contigId1 >= 0);
      likelihoodInsert = GetCappedInsertProbNormal(SIGMA_RANGE+1.0, primaryMateParameters->insertStd) / primaryMateParameters->zNormalizationInsert; // punish it with SIGMA_RANGE+1 sigma from normal
      //likelihoodInsert = exp(getMinLogLike()); // punish it for being a chimer

      if (thisRead->core.tid == thisRead->core.mtid && theAssembly->contigs[thisRead->core.tid]->isCircular == 1) {
        // TODO refine based on proximity to end of contigs in a circular genome
        // i.e. factor in: likelihoodThatRead1AndRead2AreCloseToContigEdgeSoAreNotChimersButProbablySpanningMatePairs
      }

      logzNormalizeRead1 = logzNormalizationReadQual(thisRead, libParams->qOff);
      likelihoodPlacement = libParams->totalChimerMateFraction; // orientation likelihood
      likelihoodPlacement *= exp(loglikelihoodRead1 - logzNormalizeRead1);
      break;

    case (SINGLE_UNMAPPED_MATE):
    case (SINGLE_READ):
      if (thisAlignment->contigId1 < 0) {
          // not aligned
          likelihoodPlacement = 0.0;
          break;
      }

      logzNormalizeRead1 = logzNormalizationReadQual(thisRead, libParams->qOff);
      likelihoodPlacement = libParams->totalValidSingleFraction; // orientation likelihood
      likelihoodPlacement *= exp(loglikelihoodRead1 - logzNormalizeRead1); // match likelihood

      if (orientation == SINGLE_READ) {
          likelihoodInsert = GetInsertProbNormal(0, primaryMateParameters->insertStd) / primaryMateParameters->zNormalizationInsert; // set max normal likelihood
      }else {
          // is a mate pair but other mate did not map.  Treat like chimer
          likelihoodInsert = GetCappedInsertProbNormal(SIGMA_RANGE+1.0, primaryMateParameters->insertStd) / primaryMateParameters->zNormalizationInsert; // punish it with SIGMA_RANGE+1 sigma from normal
          // likelihoodInsert = exp(getMinLogLike());
      }

      //printf("Applying single-ish read %s (%d %s) %f %f\n", bam1_qname(thisRead), orientation, MATE_ORIENTATION_LABELS[orientation], thisAlignment->likelihood, likelihoodInsert);

      break;

    case (UNMAPPED_MATE):
      // it is the unmapped mate of a pair.  Treat insert like chimer
    case (UNMAPPED_PAIR):
      // is a mate pair but neither mate mapped.  Treat insert like chimer
      likelihoodPlacement = 0.0;
      likelihoodInsert = GetCappedInsertProbNormal(SIGMA_RANGE+1.0, primaryMateParameters->insertStd) / primaryMateParameters->zNormalizationInsert; // punish it with SIGMA_RANGE+1 sigma from normal
      // since this is not technically an orientation, no orientation likelihood is applied...
      //likelihoodInsert = exp(getMinLogLike());
      break;

    default :
      likelihoodPlacement = 0.0;
      likelihoodInsert = 0.0;
      if (thisRead == NULL) { //printf("this read is null!!! Skipping %s\n", MATE_ORIENTATION_LABELS[orientation]);
          break;
      }
      assert(thisRead != NULL);
      //printf("Skipping %s read %s\n", MATE_ORIENTATION_LABELS[orientation], bam1_qname(thisRead));
      break;
  }
  // regardless of normalization, if any of the likelihoods hits the floor it stays at the floor.
  if (loglikelihoodRead1 <= getMinLogLike() || loglikelihoodRead2 <= getMinLogLike() || loglikelihoodRead1+loglikelihoodRead2 <= getMinLogLike() || isnan(likelihoodPlacement) || isinf(likelihoodPlacement)) {
	  likelihoodPlacement = exp(getMinLogLike());
	  //printf("floored placement for %s\n", bam1_qname(thisRead));
  }


  if(orientation == HALF_VALID_MATE) {
	thisAlignment->likelihood = 0.0;
	thisAlignment->likelihoodInsert = 0.0;
  } else {
	thisAlignment->likelihood = likelihoodPlacement;
    thisAlignment->likelihoodInsert = likelihoodInsert;
  }
  assert(thisAlignment->likelihood >= 0.0); // we cannot assume it is less than 1.0 because of the normalization
  assert(thisAlignment->likelihoodInsert >= 0);
  //printf("Likelihoods2 (%s): %12e %s\n", bam1_qname(thisRead), likelihoodInsert, MATE_ORIENTATION_LABELS[orientation]);

  thisAlignment->orientation = orientation; // record this orientation...

  return orientation;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %r8, 0x8(%rsp)
movq %rsi, (%rsp)
testq %rdx, %rdx
je 0x7986
movq %r9, %rbp
movq %rcx, %r14
movq %rdx, %rbx
movq 0x78(%rsp), %r15
movl 0x70(%rsp), %r13d
movq %rdx, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x7403
movl 0x3b0(%rbp), %r12d
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
cmpl $0x0, 0x20(%rbx)
js 0x75dd
movq (%rsp), %rax
movq 0xa0(%rax), %rax
movslq (%r15), %rcx
movq (%rax,%rcx,8), %rsi
movl 0x18(%rbx), %ecx
subl 0x10(%rbx), %ecx
movq %r15, %rdi
movl %r12d, %edx
callq 0x4cf8
movsd %xmm0, 0x18(%rsp)
movq %r15, %rdi
movl %r12d, %esi
callq 0x5bbf
movapd %xmm0, %xmm1
jmp 0x75e3
movsd %xmm0, 0x18(%rsp)
cmpl $0xb, %r13d
ja 0x7777
movl %r13d, %r15d
movl 0x3b8(%rbp), %edx
movq %rbp, %rax
movq %rdx, %rbp
shlq $0x6, %rbp
movq %rax, 0x10(%rsp)
addq %rax, %rbp
leaq 0x12585(%rip), %rax     # 0x19b94
movslq (%rax,%r15,4), %rcx
addq %rax, %rcx
jmpq *%rcx
cmpl $0x0, 0x20(%rbx)
js 0x79a5
movq %rdx, 0x28(%rsp)
movsd %xmm1, 0x30(%rsp)
cmpl $0x0, 0x24(%rbx)
js 0x79c4
movq %r14, %rdi
movq 0x8(%rsp), %rsi
movq 0x78(%rsp), %rdx
callq 0x6de0
testq %rax, %rax
je 0x76fa
movq %rax, %r13
movq %r15, %r14
shlq $0x6, %r14
addq 0x10(%rsp), %r14
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %rax, %rdx
callq 0x701a
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %r13, %rdx
callq 0x7403
movq (%rsp), %rax
movq 0xa0(%rax), %rax
movslq (%r13), %rcx
movq (%rax,%rcx,8), %rsi
movl 0x1c(%rbx), %ecx
subl 0x14(%rbx), %ecx
movq %r13, %rdi
movl %r12d, %edx
callq 0x4cf8
movsd %xmm0, 0x20(%rsp)
movq %r13, %rdi
movl %r12d, %esi
callq 0x5bbf
movsd %xmm0, (%rsp)
cmpl $0x1, 0x38(%r14)
jne 0x77ae
movq 0x78(%rsp), %rdi
movq %r14, %rsi
callq 0x6fb6
testl %eax, %eax
movl 0x70(%rsp), %r13d
je 0x7838
movsd (%r14), %xmm0
movsd 0x8(%r14), %xmm1
movq 0x78(%rsp), %rdi
callq 0x4229
jmp 0x784b
pushq $0xa
popq %r13
jmp 0x7777
cmpl $0x0, 0x20(%rbx)
js 0x7777
movq 0x10(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x5bbf
movsd 0x390(%r14), %xmm1
movsd %xmm1, (%rsp)
movsd 0x18(%rsp), %xmm1
subsd %xmm0, %xmm1
movapd %xmm1, %xmm0
callq 0x3680
mulsd (%rsp), %xmm0
movsd %xmm0, (%rsp)
movsd 0x8(%rbp), %xmm1
cmpl $0xb, %r13d
jne 0x7969
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
callq 0x40fe
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x8(%rsp)
pushq $0xb
jmp 0x78a2
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
jmp 0x77a4
movsd 0x8(%rbp), %xmm1
movsd 0x122c8(%rip), %xmm0    # 0x19a58
callq 0x41dc
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x8(%rsp)
xorpd %xmm0, %xmm0
movsd %xmm0, (%rsp)
jmp 0x78a4
movsd 0x8(%rbp), %xmm1
movsd 0x1229d(%rip), %xmm0    # 0x19a58
callq 0x41dc
movq 0x28(%rsp), %r15
movl 0x70(%rsp), %r13d
jmp 0x784b
cmpl $0x0, 0x20(%rbx)
js 0x7a21
movsd 0x8(%rbp), %xmm1
movsd 0x12275(%rip), %xmm0    # 0x19a58
callq 0x41dc
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x8(%rsp)
movq 0x10(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x5bbf
movsd 0x3a0(%r14), %xmm1
movsd %xmm1, (%rsp)
movsd 0x18(%rsp), %xmm1
subsd %xmm0, %xmm1
movapd %xmm1, %xmm0
callq 0x3680
mulsd (%rsp), %xmm0
movsd %xmm0, (%rsp)
pushq $0x7
jmp 0x78a2
movsd 0x8(%r14), %xmm1
movsd 0x1224a(%rip), %xmm0    # 0x19a90
callq 0x41dc
movq 0x10(%rsp), %rax
shlq $0x6, %r15
divsd 0x10(%rax,%r15), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x18(%r14), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x18(%rsp), %xmm0
subsd 0x30(%rsp), %xmm0
addsd 0x20(%rsp), %xmm0
subsd (%rsp), %xmm0
callq 0x3680
mulsd 0x10(%rsp), %xmm0
xorpd %xmm1, %xmm1
movsd %xmm0, (%rsp)
ucomisd %xmm1, %xmm0
jne 0x78a4
jp 0x78a4
pushq $0x6
popq %r13
xorl %eax, %eax
callq 0x8a45
ucomisd 0x18(%rsp), %xmm0
jae 0x7906
xorl %eax, %eax
callq 0x8a45
ucomisd 0x20(%rsp), %xmm0
jae 0x7906
movsd 0x18(%rsp), %xmm0
addsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
xorl %eax, %eax
callq 0x8a45
movq (%rsp), %xmm1
movq %xmm1, %rax
btrq $0x3f, %rax
movabsq $0x7fefffffffffffff, %rcx # imm = 0x7FEFFFFFFFFFFFFF
cmpq %rcx, %rax
setg %al
ucomisd 0x18(%rsp), %xmm0
jae 0x7906
testb %al, %al
je 0x7917
xorl %eax, %eax
callq 0x8a45
callq 0x3680
movsd %xmm0, (%rsp)
cmpl $0xa, %r13d
movsd 0x8(%rsp), %xmm1
jne 0x792d
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
jmp 0x7953
movsd (%rsp), %xmm2
movsd %xmm2, (%rbx)
movsd %xmm1, 0x8(%rbx)
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm2
jb 0x79e3
ucomisd %xmm0, %xmm1
jb 0x7a02
movl %r13d, 0x40(%rbx)
movl %r13d, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x120e7(%rip), %xmm0    # 0x19a58
callq 0x41dc
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x8(%rsp)
jmp 0x78a4
leaq 0x17144(%rip), %rdi     # 0x1ead1
leaq 0x163a1(%rip), %rsi     # 0x1dd35
leaq 0x1714c(%rip), %rcx     # 0x1eae7
movl $0x7aa, %edx            # imm = 0x7AA
callq 0x3230
leaq 0x171d2(%rip), %rdi     # 0x1eb7e
leaq 0x16382(%rip), %rsi     # 0x1dd35
leaq 0x1712d(%rip), %rcx     # 0x1eae7
movl $0x7d2, %edx            # imm = 0x7D2
callq 0x3230
leaq 0x16d84(%rip), %rdi     # 0x1e74f
leaq 0x16363(%rip), %rsi     # 0x1dd35
leaq 0x1710e(%rip), %rcx     # 0x1eae7
movl $0x7d3, %edx            # imm = 0x7D3
callq 0x3230
leaq 0x171b2(%rip), %rdi     # 0x1eb9c
leaq 0x16344(%rip), %rsi     # 0x1dd35
leaq 0x170ef(%rip), %rcx     # 0x1eae7
movl $0x851, %edx            # imm = 0x851
callq 0x3230
leaq 0x171b4(%rip), %rdi     # 0x1ebbd
leaq 0x16325(%rip), %rsi     # 0x1dd35
leaq 0x170d0(%rip), %rcx     # 0x1eae7
movl $0x852, %edx            # imm = 0x852
callq 0x3230
leaq 0x17156(%rip), %rdi     # 0x1eb7e
leaq 0x16306(%rip), %rsi     # 0x1dd35
leaq 0x170b1(%rip), %rcx     # 0x1eae7
movl $0x809, %edx            # imm = 0x809
callq 0x3230