// File: /workspace/github_cpp_makefile_star2_O2/isovic[P]cigargen/cigargen.cc
// Function: GenerateCigar(char*, unsigned int, char*, unsigned int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, unsigned int*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*)
int32_t GenerateCigar(char *query, uint32_t query_length, char *reference, uint32_t reference_length, std::string *ret_cigar, uint32_t *ret_alignment_length, std::string *ret_alignment) {
  if (query == NULL || reference == NULL || query_length == 0 || reference_length == 0)
    return -1;

  // Preallocate the memory for the DP matrix and traceback, and initialize all values to 0.
  std::vector<std::vector<int32_t> > dp_matrix((query_length + 1), std::vector<int32_t>((reference_length + 1), 0));
  std::vector<std::vector<uint8_t> > dp_traceback((query_length + 1), std::vector<uint8_t>((reference_length + 1), 0));
  // Temporary variables for storing the options for the current step. (Could have been done differently, but increases readability.)
  int32_t up=0, left=0, diagonal=0;

  // Initialize the first row and column according to Needleman-Wunsch.
  for (uint32_t i=0; i<=query_length; i++)
    dp_matrix[i][0] = i * PENALTY_INSERTION;
  for (uint32_t i=0; i<=reference_length; i++)
    dp_matrix[0][i] = i * PENALTY_DELETION;

  int32_t max_score_index = 0;

  for (uint32_t i=1; i<=query_length; i++) {
    for (uint32_t j=1; j<=reference_length; j++) {
      // Calculate the options for the current value of the DP matrix.
      up = dp_matrix[i-1][j] + PENALTY_INSERTION;
      left = dp_matrix[i][j-1] + PENALTY_DELETION;
      diagonal = dp_matrix[i-1][j-1] + ((query[i-1] == reference[j-1]) ? PENALTY_MATCH : PENALTY_MISMATCH);

      // Find the maximum of the three values.
      dp_matrix[i][j] = diagonal;
      dp_traceback[i][j] = ((query[i-1] == reference[j-1])?0:1);
      if (up > dp_matrix[i][j]) {
        dp_matrix[i][j] = up;
        dp_traceback[i][j] = 2;
      }
      if (left > dp_matrix[i][j]) {
        dp_matrix[i][j] = left;
        dp_traceback[i][j] = 3;
      }

      // If this is the last row of the matrix, we need to look up for the maximum score. This will be our starting point for the
      // CIGAR traceback calculation.
      if (i == query_length && dp_matrix[query_length][j] > dp_matrix[query_length][max_score_index])
        max_score_index = j;
    }
  }

  // Initialize the traceback column to the index of the highest score, and the traceback row to the last row of the matrix.
  int32_t current_traceback_row = query_length, current_traceback_column = max_score_index;

  std::stringstream cigar_stream;
  std::string cigar = "";
  std::string alignment = "";
  uint32_t edit_distance = 0;

  // Traceback: Find the CIGAR string.
  uint32_t iterations=0, num_insertions=0, type=0, last_type=0, num_same_types=0;
  while (current_traceback_column > 0 && current_traceback_row > 0) {
    type = dp_traceback[current_traceback_row][current_traceback_column];

    // Count the number of same transitions in the DP matrix (whether if it was to the left, right or up.)
    if (iterations == 0) {
      // If this is the first traceback step, initialize the last type for counting.
      last_type = type;
      num_same_types = 1;
    }
    else {
      if (type == last_type) {
        // If types of transition are the same, just count them.
        num_same_types += 1;
      }
      else {
        // If the type has changed, stream the CIGAR count, and reset the type to the current one.
        cigar_stream << TypeToSymbol(last_type) << num_same_types;
        last_type = type;
        num_same_types = 1;
      }
    }

    if (type != TYPE_MATCH)
      edit_distance += 1;

    // Accumulate the characters for the alignment, but only if this was asked for (that's why there is
    // the NULL testing). We insert a special character '+' in this implementation, which represents that
    // there was an insertion on the reference (one character was removed from the query).
    // Character '-' represents the deletion in the reference (or an insertion on the query).
    if (ret_alignment != NULL)
        alignment +=  ((type == TYPE_DELETION) ? '-' :
                      ((type == TYPE_MATCH) ? query[current_traceback_row - 1] :
                      ((type == TYPE_INSERTION) ? '+' :
                      'x')));

    if (type == TYPE_INSERTION)
      num_insertions += 1;

    // Row changes in all cases except when a deletion occurs (type == 3).
    current_traceback_row -= (type != TYPE_DELETION) ? 1 : 0;
    // Column changes in all cases except when an insertion occurs (type == 2).
    current_traceback_column -= (type != TYPE_INSERTION) ? 1 : 0;

    // Count the traceback length.
    iterations += 1;
  }

  // Stream the remaining count to the CIGAR stream.
  cigar_stream << TypeToSymbol(last_type) << num_same_types;
  cigar = cigar_stream.str();
  std::reverse(cigar.begin(), cigar.end());
  std::reverse(alignment.begin(), alignment.end());

  if (ret_cigar != NULL)
    *ret_cigar = cigar;
  else
    Verbose(stdout, query, query_length, reference, reference_length, cigar, dp_matrix, dp_traceback);

  // Return the final alignment length. We need to subtract the number of insertions on the reference because the final
  // alignment should be shorter than the traceback for this amount.
  if (ret_alignment_length != NULL)
    *ret_alignment_length = (iterations - num_insertions);

  // Return the final alignment if required. The alignment.size() value is larger than ret_alignment_length, because
  // query deletions have not been completely removed, but changed with a special character.
  if (ret_alignment != NULL)
    *ret_alignment = alignment;

  return edit_distance;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x268, %rsp            # imm = 0x268
movq %rdx, -0x58(%rbp)
movq %rdi, -0x38(%rbp)
pushq $-0x1
popq %r12
testl %ecx, %ecx
je 0x2a4e
movq %rsi, -0x50(%rbp)
testl %esi, %esi
je 0x2a4e
cmpq $0x0, -0x38(%rbp)
je 0x2a4e
cmpq $0x0, -0x58(%rbp)
je 0x2a4e
movq %r9, %r15
movq %r8, -0xc0(%rbp)
movq %rcx, -0x60(%rbp)
leal 0x1(%rcx), %r14d
leaq -0xe0(%rbp), %rdx
andl $0x0, (%rdx)
leaq -0x288(%rbp), %rdi
leaq -0xb0(%rbp), %rcx
movq %r14, %rsi
callq 0x2d18
movq -0x50(%rbp), %rax
leal 0x1(%rax), %r12d
leaq -0x78(%rbp), %rdi
leaq -0x288(%rbp), %rdx
leaq -0x100(%rbp), %rcx
movq %r12, %rsi
callq 0x2d78
leaq -0x288(%rbp), %rdi
callq 0x2f36
leaq -0xe0(%rbp), %rdx
movb $0x0, (%rdx)
leaq -0x288(%rbp), %rdi
leaq -0xb0(%rbp), %rcx
movq %r14, %rsi
callq 0x2dd8
leaq -0x90(%rbp), %rdi
leaq -0x288(%rbp), %rdx
leaq -0x100(%rbp), %rcx
movq %r12, %rsi
callq 0x2e36
leaq -0x288(%rbp), %rdi
callq 0x3216
movq -0x78(%rbp), %rax
imulq $0x6, %r12, %rcx
xorl %edx, %edx
xorl %esi, %esi
cmpq %rsi, %rcx
je 0x266f
movq (%rax,%rsi,4), %rdi
movl %edx, (%rdi)
addq $0x6, %rsi
addl $-0x6, %edx
jmp 0x265b
movq (%rax), %rax
imulq $0x6, %r14, %rcx
xorl %edx, %edx
movq %rcx, %rsi
addq %rdx, %rsi
je 0x268c
movl %edx, (%rax)
addq $-0x6, %rdx
addq $0x4, %rax
jmp 0x2678
movl -0x50(%rbp), %eax
movl -0x60(%rbp), %ecx
xorl %ebx, %ebx
pushq $0x1
popq %rdx
pushq $0x5
popq %rsi
movq %r15, -0xb8(%rbp)
cmpq %rax, %rdx
ja 0x27ad
leaq -0x1(%rdx), %rdi
imulq $0x18, %rdi, %r8
imulq $0x18, %rdx, %r9
xorl %r11d, %r11d
leaq 0x1(%r11), %r10
cmpq %rcx, %r10
ja 0x27a5
movq -0x38(%rbp), %rdi
movb -0x1(%rdi,%rdx), %dil
movl %esi, %r12d
movq -0x58(%rbp), %r14
cmpb (%r14,%r11), %dil
je 0x26e0
pushq $-0x2
popq %r12
movq -0x78(%rbp), %r14
movq (%r14,%r8), %r13
movl 0x4(%r13,%r11,4), %edi
addl $-0x6, %edi
movq (%r14,%r9), %r15
movl (%r15,%r11,4), %r14d
addl (%r13,%r11,4), %r12d
movl %r12d, 0x4(%r15,%r11,4)
movq -0x38(%rbp), %r15
movb -0x1(%r15,%rdx), %r15b
movq -0x58(%rbp), %r12
cmpb (%r12,%r11), %r15b
movq -0x90(%rbp), %r15
movq (%r15,%r9), %r15
setne 0x1(%r15,%r11)
movq -0x78(%rbp), %r15
movq (%r15,%r9), %r12
movl 0x4(%r12,%r11,4), %r13d
cmpl %r13d, %edi
jle 0x2759
movl %edi, 0x4(%r12,%r11,4)
movq -0x90(%rbp), %rdi
movq (%rdi,%r9), %rdi
movb $0x2, 0x1(%rdi,%r11)
movq -0x78(%rbp), %rdi
movq (%rdi,%r9), %r12
movl 0x4(%r12,%r11,4), %r13d
addl $-0x6, %r14d
cmpl %r13d, %r14d
jle 0x2778
movl %r14d, 0x4(%r12,%r11,4)
movq -0x90(%rbp), %rdi
movq (%rdi,%r9), %rdi
movb $0x3, 0x1(%rdi,%r11)
cmpq %rax, %rdx
jne 0x279d
movq -0x78(%rbp), %rdi
imulq $0x18, %rax, %r14
movq (%rdi,%r14), %rdi
movl 0x4(%rdi,%r11,4), %r14d
movslq %ebx, %r15
cmpl (%rdi,%r15,4), %r14d
jle 0x279d
incl %r11d
movl %r11d, %ebx
movq %r10, %r11
jmp 0x26b9
incq %rdx
jmp 0x26a1
leaq -0x288(%rbp), %rdi
callq 0x20d0
movq -0x50(%rbp), %r15
leaq 0x1919(%rip), %rsi      # 0x40dd
leaq -0xe0(%rbp), %rdi
leaq -0xb0(%rbp), %rdx
callq 0x2482
leaq 0x18ff(%rip), %rsi      # 0x40dd
leaq -0xb0(%rbp), %rdi
leaq -0x100(%rbp), %rdx
callq 0x2482
movl $0x0, -0x40(%rbp)
movl %r15d, %edi
movl $0x0, -0x44(%rbp)
movl $0x0, -0x3c(%rbp)
xorl %eax, %eax
xorl %ecx, %ecx
movl %ecx, %r12d
movl %eax, %edx
testl %ebx, %ebx
jle 0x290b
testl %edi, %edi
jle 0x290b
movq %rbx, %r15
movl %edi, %r13d
movl %edi, %edi
movq -0x90(%rbp), %rsi
movq %rdi, %rbx
imulq $0x18, %rdi, %rdi
movl %r15d, %r8d
movq (%rsi,%rdi), %rsi
movzbl (%rsi,%r8), %r14d
movl %r14d, -0x30(%rbp)
pushq $0x1
popq %rsi
movl %esi, -0x2c(%rbp)
subl $0x1, -0x40(%rbp)
jb 0x2898
cmpl %r14d, %eax
jne 0x2863
incl %ecx
movl %eax, -0x30(%rbp)
movl %ecx, -0x2c(%rbp)
jmp 0x2898
movb $0x58, %cl
cmpl $0x3, %eax
ja 0x2874
leaq 0x189e(%rip), %rax      # 0x410f
movb (%rdx,%rax), %cl
movsbl %cl, %esi
leaq -0x278(%rbp), %rdi
callq 0x2150
movq %rax, %rdi
movq %r12, %rsi
callq 0x20c0
movl %r14d, -0x30(%rbp)
pushq $0x1
popq %rax
movl %eax, -0x2c(%rbp)
cmpl $0x1, %r14d
sbbl $-0x1, -0x44(%rbp)
cmpq $0x0, 0x10(%rbp)
je 0x28dc
cmpl $0x3, %r14d
je 0x28bc
testl %r14d, %r14d
jne 0x28c0
movq -0x38(%rbp), %rax
movb -0x1(%rax,%rbx), %al
jmp 0x28cd
movb $0x2d, %al
jmp 0x28cd
cmpl $0x2, %r14d
pushq $0x78
popq %rax
pushq $0x2b
popq %rcx
cmovel %ecx, %eax
movsbl %al, %esi
leaq -0xb0(%rbp), %rdi
callq 0x2120
xorl %eax, %eax
xorl %ecx, %ecx
cmpl $0x2, %r14d
sete %al
setne %cl
addl %eax, -0x3c(%rbp)
xorl %eax, %eax
cmpl $0x3, %r14d
setne %al
movl %r13d, %edi
subl %eax, %edi
movq %r15, %rbx
subl %ecx, %ebx
movl -0x30(%rbp), %eax
movl -0x2c(%rbp), %ecx
jmp 0x280d
movb $0x58, %cl
cmpl $0x3, %eax
ja 0x291c
leaq 0x17f6(%rip), %rax      # 0x410f
movb (%rdx,%rax), %cl
movsbl %cl, %esi
leaq -0x278(%rbp), %rdi
callq 0x2150
movq %rax, %rdi
movq %r12, %rsi
callq 0x20c0
movl -0x44(%rbp), %r15d
leaq -0x270(%rbp), %rsi
leaq -0x100(%rbp), %rdi
callq 0x21a0
leaq -0xe0(%rbp), %r12
leaq -0x100(%rbp), %r13
movq %r12, %rdi
movq %r13, %rsi
callq 0x2160
movq %r13, %rdi
callq 0x2080
movq (%r12), %rdi
movq 0x8(%r12), %rsi
addq %rdi, %rsi
callq 0x348f
movq -0xb8(%rbp), %r14
movl %r15d, %r12d
movq -0xb0(%rbp), %rdi
movq -0xa8(%rbp), %rsi
addq %rdi, %rsi
callq 0x348f
movq -0xc0(%rbp), %rdi
testq %rdi, %rdi
je 0x29b9
leaq -0xe0(%rbp), %rsi
callq 0x20a0
jmp 0x29ee
movq 0x3610(%rip), %rax      # 0x5fd0
movq (%rax), %rdi
leaq -0xe0(%rbp), %r9
movq -0x38(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq -0x58(%rbp), %rcx
movq -0x60(%rbp), %r8
leaq -0x90(%rbp), %rax
pushq %rax
leaq -0x78(%rbp), %rax
pushq %rax
callq 0x2ae6
popq %rax
popq %rcx
testq %r14, %r14
je 0x29fe
movl -0x3c(%rbp), %ebx
addl -0x40(%rbp), %ebx
negl %ebx
movl %ebx, (%r14)
cmpq $0x0, 0x10(%rbp)
je 0x2a15
leaq -0xb0(%rbp), %rsi
movq 0x10(%rbp), %rdi
callq 0x20a0
leaq -0xb0(%rbp), %rdi
callq 0x2080
leaq -0xe0(%rbp), %rdi
callq 0x2080
leaq -0x288(%rbp), %rdi
callq 0x20f0
leaq -0x90(%rbp), %rdi
callq 0x2e96
leaq -0x78(%rbp), %rdi
callq 0x2ec2
movl %r12d, %eax
addq $0x268, %rsp            # imm = 0x268
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x2aa2
movq %rax, %rbx
jmp 0x2ab1
movq %rax, %rbx
jmp 0x2abd
movq %rax, %rbx
jmp 0x2ac9
movq %rax, %rbx
leaq -0x288(%rbp), %rdi
callq 0x3216
jmp 0x2ad5
movq %rax, %rbx
jmp 0x2ad5
movq %rax, %rbx
leaq -0x288(%rbp), %rdi
callq 0x2f36
jmp 0x2ade
movq %rax, %rbx
jmp 0x2ade
jmp 0x2aa2
movq %rax, %rbx
leaq -0xb0(%rbp), %rdi
callq 0x2080
leaq -0xe0(%rbp), %rdi
callq 0x2080
leaq -0x288(%rbp), %rdi
callq 0x20f0
leaq -0x90(%rbp), %rdi
callq 0x2e96
leaq -0x78(%rbp), %rdi
callq 0x2ec2
movq %rbx, %rdi
callq 0x21d0