// File: /workspace/github_c_makefile_star2_O3/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 0x9a86
movq %r9, %r14
movq %rcx, %r15
movq %rdx, %rbx
movq 0x78(%rsp), %r13
movl 0x70(%rsp), %ebp
movq %rdx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x9444
movl 0x3b0(%r14), %r12d
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
cmpl $0x0, 0x20(%rbx)
js 0x9664
movq (%rsp), %rax
movq 0xa0(%rax), %rax
movslq (%r13), %rcx
movq (%rax,%rcx,8), %rsi
movl 0x18(%rbx), %ecx
subl 0x10(%rbx), %ecx
movq %r13, %rdi
movl %r12d, %edx
callq 0x6883
movsd %xmm0, 0x18(%rsp)
movq %r13, %rdi
movl %r12d, %esi
callq 0x7a35
movapd %xmm0, %xmm1
jmp 0x966a
movsd %xmm0, 0x18(%rsp)
cmpl $0xb, %ebp
ja 0x97c3
movl %ebp, %ebp
movq %r14, %rax
movl 0x3b8(%r14), %r14d
movq %r14, %r13
shlq $0x6, %r13
movq %rax, 0x10(%rsp)
addq %rax, %r13
leaq 0x1452f(%rip), %rax     # 0x1dbc4
movslq (%rax,%rbp,4), %rcx
addq %rax, %rcx
jmpq *%rcx
cmpl $0x0, 0x20(%rbx)
js 0x9aa5
movsd %xmm1, 0x30(%rsp)
cmpl $0x0, 0x24(%rbx)
js 0x9ac4
movq %r15, %rdi
movq 0x8(%rsp), %rsi
movq 0x78(%rsp), %rdx
callq 0x8e0b
testq %rax, %rax
je 0x97be
movq %rax, %r15
movq %rbp, 0x8(%rsp)
shlq $0x6, %rbp
addq 0x10(%rsp), %rbp
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %rax, %rdx
callq 0x904a
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %r15, %rdx
callq 0x9444
movq (%rsp), %rax
movq 0xa0(%rax), %rax
movslq (%r15), %rcx
movq (%rax,%rcx,8), %rsi
movl 0x1c(%rbx), %ecx
subl 0x14(%rbx), %ecx
movq %r15, %rdi
movl %r12d, %edx
callq 0x6883
movsd %xmm0, 0x20(%rsp)
movq %r15, %rdi
movl %r12d, %esi
callq 0x7a35
movsd %xmm0, (%rsp)
cmpl $0x1, 0x38(%rbp)
jne 0x9883
movsd 0x8(%rbp), %xmm0
mulsd 0x14344(%rip), %xmm0    # 0x1da98
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x2c(%rsp)
movq 0x78(%rsp), %r14
movq %r14, %rdi
callq 0xbd04
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
andps 0x143d7(%rip), %xmm0    # 0x1db50
cvtss2sd %xmm0, %xmm2
movsd (%rbp), %xmm0
movsd 0x8(%rbp), %xmm1
cvtss2sd 0x2c(%rsp), %xmm3
movapd %xmm0, %xmm4
addsd %xmm3, %xmm4
ucomisd %xmm4, %xmm2
ja 0x992d
movapd %xmm0, %xmm4
subsd %xmm3, %xmm4
ucomisd %xmm2, %xmm4
ja 0x992d
movq %r14, %rdi
callq 0x5b5e
jmp 0x993e
movl $0xa, %ebp
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
movsd %xmm0, (%rsp)
jmp 0x99a2
cmpl $0x0, 0x20(%rbx)
js 0x98a4
movq 0x10(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x7a35
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(%r13), %xmm1
movl 0x70(%rsp), %ebp
cmpl $0xb, %ebp
jne 0x9a64
xorpd %xmm0, %xmm0
movsd %xmm0, 0x20(%rsp)
callq 0x5a30
divsd 0x10(%r13), %xmm0
movsd %xmm0, 0x8(%rsp)
movl $0xb, %ebp
jmp 0x99a2
movsd 0x8(%r13), %xmm1
movsd 0x141f0(%rip), %xmm0    # 0x1da58
mulsd %xmm1, %xmm0
callq 0x5a30
divsd 0x10(%r13), %xmm0
movsd %xmm0, 0x8(%rsp)
xorpd %xmm0, %xmm0
jmp 0x98ae
movsd 0x8(%r13), %xmm1
movsd 0x141c7(%rip), %xmm0    # 0x1da58
mulsd %xmm1, %xmm0
callq 0x5a30
movq 0x10(%rsp), %rax
jmp 0x9948
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
movsd %xmm0, (%rsp)
jmp 0x999e
cmpl $0x0, 0x20(%rbx)
js 0x9b21
movsd 0x8(%r13), %xmm1
movsd 0x14188(%rip), %xmm0    # 0x1da58
mulsd %xmm1, %xmm0
callq 0x5a30
divsd 0x10(%r13), %xmm0
movsd %xmm0, 0x8(%rsp)
movq 0x10(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x7a35
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)
movl $0x7, %ebp
jmp 0x99a2
movsd 0x14163(%rip), %xmm0    # 0x1da98
mulsd %xmm1, %xmm0
callq 0x5a30
movq 0x10(%rsp), %rax
movq 0x8(%rsp), %r14
shlq $0x6, %r14
divsd 0x10(%rax,%r14), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x18(%rbp), %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 0x999e
jp 0x999e
movl $0x6, %ebp
jmp 0x99a2
movl 0x70(%rsp), %ebp
xorl %eax, %eax
callq 0xab49
ucomisd 0x18(%rsp), %xmm0
jae 0x9a04
xorl %eax, %eax
callq 0xab49
ucomisd 0x20(%rsp), %xmm0
jae 0x9a04
movsd 0x18(%rsp), %xmm0
addsd 0x20(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
xorl %eax, %eax
callq 0xab49
movq (%rsp), %xmm1
movq %xmm1, %rax
btrq $0x3f, %rax
movabsq $0x7fefffffffffffff, %rcx # imm = 0x7FEFFFFFFFFFFFFF
cmpq %rcx, %rax
setg %al
ucomisd 0x18(%rsp), %xmm0
jae 0x9a04
testb %al, %al
je 0x9a15
xorl %eax, %eax
callq 0xab49
callq 0x3680
movsd %xmm0, (%rsp)
cmpl $0xa, %ebp
movsd 0x8(%rsp), %xmm1
jne 0x9a2a
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
jmp 0x9a50
movsd (%rsp), %xmm2
movsd %xmm2, (%rbx)
movsd %xmm1, 0x8(%rbx)
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm2
jb 0x9ae3
ucomisd %xmm0, %xmm1
jb 0x9b02
movl %ebp, 0x40(%rbx)
movl %ebp, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x13fec(%rip), %xmm0    # 0x1da58
mulsd %xmm1, %xmm0
callq 0x5a30
divsd 0x10(%r13), %xmm0
movsd %xmm0, 0x8(%rsp)
jmp 0x99a2
leaq 0x19074(%rip), %rdi     # 0x22b01
leaq 0x182d1(%rip), %rsi     # 0x21d65
leaq 0x1907c(%rip), %rcx     # 0x22b17
movl $0x7aa, %edx            # imm = 0x7AA
callq 0x3230
leaq 0x19102(%rip), %rdi     # 0x22bae
leaq 0x182b2(%rip), %rsi     # 0x21d65
leaq 0x1905d(%rip), %rcx     # 0x22b17
movl $0x7d2, %edx            # imm = 0x7D2
callq 0x3230
leaq 0x18cb4(%rip), %rdi     # 0x2277f
leaq 0x18293(%rip), %rsi     # 0x21d65
leaq 0x1903e(%rip), %rcx     # 0x22b17
movl $0x7d3, %edx            # imm = 0x7D3
callq 0x3230
leaq 0x190e2(%rip), %rdi     # 0x22bcc
leaq 0x18274(%rip), %rsi     # 0x21d65
leaq 0x1901f(%rip), %rcx     # 0x22b17
movl $0x851, %edx            # imm = 0x851
callq 0x3230
leaq 0x190e4(%rip), %rdi     # 0x22bed
leaq 0x18255(%rip), %rsi     # 0x21d65
leaq 0x19000(%rip), %rcx     # 0x22b17
movl $0x852, %edx            # imm = 0x852
callq 0x3230
leaq 0x19086(%rip), %rdi     # 0x22bae
leaq 0x18236(%rip), %rsi     # 0x21d65
leaq 0x18fe1(%rip), %rcx     # 0x22b17
movl $0x809, %edx            # imm = 0x809
callq 0x3230