// File: /workspace/github_c_makefile_star2_O1/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, 0x10(%rsp)
movq %rsi, 0x8(%rsp)
testq %rdx, %rdx
je 0x97ce
movq %r9, %rbp
movq %rcx, %r15
movq %rdx, %rbx
movq 0x78(%rsp), %r13
movl 0x70(%rsp), %r14d
movq %rdx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x9168
movl 0x3b0(%rbp), %r12d
xorpd %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
cmpl $0x0, 0x20(%rbx)
js 0x9396
movq 0x8(%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 0x6557
movsd %xmm0, 0x20(%rsp)
movq %r13, %rdi
movl %r12d, %esi
callq 0x76de
movapd %xmm0, %xmm1
jmp 0x939c
movsd %xmm0, 0x20(%rsp)
cmpl $0xb, %r14d
ja 0x9500
movl %r14d, %r14d
movl 0x3b8(%rbp), %r13d
movq %rbp, %rax
movq %r13, %rbp
shlq $0x6, %rbp
movq %rax, 0x18(%rsp)
addq %rax, %rbp
leaq 0x147ab(%rip), %rax     # 0x1db74
movslq (%rax,%r14,4), %rcx
addq %rax, %rcx
jmpq *%rcx
cmpl $0x0, 0x20(%rbx)
js 0x982b
movsd %xmm1, 0x30(%rsp)
cmpl $0x0, 0x24(%rbx)
js 0x984a
movq %r15, %rdi
movq 0x10(%rsp), %rsi
movq 0x78(%rsp), %rdx
callq 0x8b35
testq %rax, %rax
je 0x94fa
movq %rax, %r15
movq %r13, 0x10(%rsp)
movq %r14, %r13
shlq $0x6, %r13
addq 0x18(%rsp), %r13
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %rax, %rdx
callq 0x8d74
movq %rbx, %rdi
movq 0x78(%rsp), %rsi
movq %r15, %rdx
callq 0x9168
movq 0x8(%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 0x6557
movsd %xmm0, 0x28(%rsp)
movq %r15, %rdi
movl %r12d, %esi
callq 0x76de
movsd %xmm0, 0x8(%rsp)
cmpl $0x1, 0x38(%r13)
jne 0x95c3
movsd 0x8(%r13), %xmm0
mulsd 0x14641(%rip), %xmm0    # 0x1dad0
cvtsd2ss %xmm0, %xmm0
movss %xmm0, 0x10(%rsp)
movq 0x78(%rsp), %rdi
callq 0xba81
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
andps 0x1464f(%rip), %xmm0    # 0x1db00
cvtss2sd %xmm0, %xmm2
movsd (%r13), %xmm0
movsd 0x8(%r13), %xmm1
cvtss2sd 0x10(%rsp), %xmm3
movapd %xmm0, %xmm4
addsd %xmm3, %xmm4
ucomisd %xmm4, %xmm2
ja 0x966f
movapd %xmm0, %xmm4
subsd %xmm3, %xmm4
ucomisd %xmm2, %xmm4
ja 0x966f
movq 0x78(%rsp), %rdi
callq 0x597f
jmp 0x9680
movl $0xa, %r14d
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movsd %xmm0, 0x8(%rsp)
jmp 0x96e4
cmpl $0x0, 0x20(%rbx)
js 0x95e3
movq 0x18(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x76de
movsd 0x390(%r14), %xmm1
movsd %xmm1, 0x8(%rsp)
movsd 0x20(%rsp), %xmm1
subsd %xmm0, %xmm1
movapd %xmm1, %xmm0
callq 0x3680
mulsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x8(%rbp), %xmm1
movl 0x70(%rsp), %r14d
cmpl $0xb, %r14d
jne 0x97ad
xorpd %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
callq 0x5851
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x10(%rsp)
movl $0xb, %r14d
jmp 0x96e4
movsd 0x8(%rbp), %xmm1
movsd 0x144d7(%rip), %xmm0    # 0x1da80
mulsd %xmm1, %xmm0
callq 0x5851
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x10(%rsp)
xorpd %xmm0, %xmm0
jmp 0x95ed
movsd 0x8(%rbp), %xmm1
movsd 0x144b0(%rip), %xmm0    # 0x1da80
mulsd %xmm1, %xmm0
callq 0x5851
movq 0x10(%rsp), %r14
jmp 0x9680
xorpd %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
movsd %xmm0, 0x8(%rsp)
jmp 0x96df
cmpl $0x0, 0x20(%rbx)
js 0x9869
movsd 0x8(%rbp), %xmm1
movsd 0x14471(%rip), %xmm0    # 0x1da80
mulsd %xmm1, %xmm0
callq 0x5851
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0x18(%rsp), %r14
movl 0x3b0(%r14), %esi
movq 0x78(%rsp), %rdi
callq 0x76de
movsd 0x3a0(%r14), %xmm1
movsd %xmm1, 0x8(%rsp)
movsd 0x20(%rsp), %xmm1
subsd %xmm0, %xmm1
movapd %xmm1, %xmm0
callq 0x3680
mulsd 0x8(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movl $0x7, %r14d
jmp 0x96e4
movsd 0x14459(%rip), %xmm0    # 0x1dad0
mulsd %xmm1, %xmm0
callq 0x5851
movq 0x18(%rsp), %rax
shlq $0x6, %r14
divsd 0x10(%rax,%r14), %xmm0
movsd %xmm0, 0x10(%rsp)
movsd 0x18(%r13), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x20(%rsp), %xmm0
subsd 0x30(%rsp), %xmm0
addsd 0x28(%rsp), %xmm0
subsd 0x8(%rsp), %xmm0
callq 0x3680
mulsd 0x18(%rsp), %xmm0
xorpd %xmm1, %xmm1
movsd %xmm0, 0x8(%rsp)
ucomisd %xmm1, %xmm0
jne 0x96df
jp 0x96df
movl $0x6, %r14d
jmp 0x96e4
movl 0x70(%rsp), %r14d
xorl %eax, %eax
callq 0xa881
ucomisd 0x20(%rsp), %xmm0
jae 0x9747
xorl %eax, %eax
callq 0xa881
ucomisd 0x28(%rsp), %xmm0
jae 0x9747
movsd 0x20(%rsp), %xmm0
addsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
xorl %eax, %eax
callq 0xa881
movq 0x8(%rsp), %xmm1
movq %xmm1, %rax
btrq $0x3f, %rax
movabsq $0x7fefffffffffffff, %rcx # imm = 0x7FEFFFFFFFFFFFFF
cmpq %rcx, %rax
setg %al
ucomisd 0x20(%rsp), %xmm0
jae 0x9747
testb %al, %al
je 0x9759
xorl %eax, %eax
callq 0xa881
callq 0x3680
movsd %xmm0, 0x8(%rsp)
cmpl $0xa, %r14d
movsd 0x10(%rsp), %xmm0
jne 0x976f
xorpd %xmm0, %xmm0
movupd %xmm0, (%rbx)
jmp 0x977e
movq 0x8(%rsp), %xmm1
movq %xmm1, (%rbx)
movsd %xmm0, 0x8(%rbx)
movsd (%rbx), %xmm1
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jb 0x97ed
movsd 0x8(%rbx), %xmm1
ucomisd %xmm0, %xmm1
jb 0x980c
movl %r14d, 0x40(%rbx)
movl %r14d, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x142cb(%rip), %xmm0    # 0x1da80
mulsd %xmm1, %xmm0
callq 0x5851
divsd 0x10(%rbp), %xmm0
movsd %xmm0, 0x10(%rsp)
jmp 0x96e4
leaq 0x192cc(%rip), %rdi     # 0x22aa1
leaq 0x18529(%rip), %rsi     # 0x21d05
leaq 0x192d4(%rip), %rcx     # 0x22ab7
movl $0x7aa, %edx            # imm = 0x7AA
callq 0x3230
leaq 0x19378(%rip), %rdi     # 0x22b6c
leaq 0x1850a(%rip), %rsi     # 0x21d05
leaq 0x192b5(%rip), %rcx     # 0x22ab7
movl $0x851, %edx            # imm = 0x851
callq 0x3230
leaq 0x1937a(%rip), %rdi     # 0x22b8d
leaq 0x184eb(%rip), %rsi     # 0x21d05
leaq 0x19296(%rip), %rcx     # 0x22ab7
movl $0x852, %edx            # imm = 0x852
callq 0x3230
leaq 0x1931c(%rip), %rdi     # 0x22b4e
leaq 0x184cc(%rip), %rsi     # 0x21d05
leaq 0x19277(%rip), %rcx     # 0x22ab7
movl $0x7d2, %edx            # imm = 0x7D2
callq 0x3230
leaq 0x18ece(%rip), %rdi     # 0x2271f
leaq 0x184ad(%rip), %rsi     # 0x21d05
leaq 0x19258(%rip), %rcx     # 0x22ab7
movl $0x7d3, %edx            # imm = 0x7D3
callq 0x3230
leaq 0x192de(%rip), %rdi     # 0x22b4e
leaq 0x1848e(%rip), %rsi     # 0x21d05
leaq 0x19239(%rip), %rcx     # 0x22ab7
movl $0x809, %edx            # imm = 0x809
callq 0x3230