// File: zeeev[P]DASVC/bamtools/src/utils/bamtools_pileup_engine.cpp
// Function: BamTools::PileupEngine::PileupEnginePrivate::ParseAlignmentCigar(BamTools::BamAlignment const&)
void PileupEngine::PileupEnginePrivate::ParseAlignmentCigar(const BamAlignment& al) {
  
    // skip if unmapped
    if ( !al.IsMapped() ) return;
    
    // intialize local variables
    int  genomePosition      = al.Position;
    int  positionInAlignment = 0;
    bool isNewReadSegment    = true;
    bool saveAlignment       = true;    
    PileupAlignment pileupAlignment(al);
    
    // iterate over CIGAR operations
    const int numCigarOps = (const int)al.CigarData.size();
    for (int i = 0; i < numCigarOps; ++i ) { 
        const CigarOp& op = al.CigarData.at(i);
      
        // if op is MATCH
        if ( op.Type == 'M' ) {
          
            // if match op overlaps current position
            if ( genomePosition + (int)op.Length > CurrentPosition ) {
              
                // set pileup data
                pileupAlignment.IsCurrentDeletion   = false;
                pileupAlignment.IsNextDeletion      = false;
                pileupAlignment.IsNextInsertion     = false;
                pileupAlignment.PositionInAlignment = positionInAlignment + (CurrentPosition - genomePosition);
                
                // check for beginning of read segment
                if ( genomePosition == CurrentPosition && isNewReadSegment ) 
                    pileupAlignment.IsSegmentBegin = true;
                
                // if we're at the end of a match operation
                if ( genomePosition + (int)op.Length - 1 == CurrentPosition ) {
                    
                    // if not last operation
                    if ( i < numCigarOps - 1 ) {
                        
                        // check next CIGAR op
                        const CigarOp& nextOp = al.CigarData.at(i+1);
                        
                        // if next CIGAR op is DELETION
                        if ( nextOp.Type == 'D') {
                            pileupAlignment.IsNextDeletion = true;
                            pileupAlignment.DeletionLength = nextOp.Length;
                        }
                        
                        // if next CIGAR op is INSERTION
                        else if ( nextOp.Type == 'I' ) {
                            pileupAlignment.IsNextInsertion = true;
                            pileupAlignment.InsertionLength = nextOp.Length;
                        }
                            
                        // if next CIGAR op is either DELETION or INSERTION
                        if ( nextOp.Type == 'D' || nextOp.Type == 'I' ) {

                            // if there is a CIGAR op after the DEL/INS
                            if ( i < numCigarOps - 2 ) {
                                const CigarOp& nextNextOp = al.CigarData.at(i+2);
                                
                                // if next CIGAR op is clipping or ref_skip
                                if ( nextNextOp.Type == 'S' || 
                                     nextNextOp.Type == 'N' ||
                                     nextNextOp.Type == 'H' )
                                    pileupAlignment.IsSegmentEnd = true;
                            } 
                            else {
                                pileupAlignment.IsSegmentEnd = true;
                                
                                // if next CIGAR op is clipping or ref_skip
                                if ( nextOp.Type == 'S' || 
                                     nextOp.Type == 'N' ||
                                     nextOp.Type == 'H' )
                                    pileupAlignment.IsSegmentEnd = true;
                            }
                        }
                        
                        // otherwise
                        else { 
                        
                            // if next CIGAR op is clipping or ref_skip
                            if ( nextOp.Type == 'S' || 
                                 nextOp.Type == 'N' ||
                                 nextOp.Type == 'H' )
                                pileupAlignment.IsSegmentEnd = true;
                        }
                    }
                    
                    // else this is last operation
                    else pileupAlignment.IsSegmentEnd = true;
                }
            }
          
            // increment markers
            genomePosition      += op.Length;
            positionInAlignment += op.Length;
        } 
        
        // if op is DELETION
        else if ( op.Type == 'D' ) {
          
            // if deletion op overlaps current position
            if ( genomePosition + (int)op.Length > CurrentPosition ) {
              
                // set pileup data
                pileupAlignment.IsCurrentDeletion   = true;
                pileupAlignment.IsNextDeletion      = false;
                pileupAlignment.IsNextInsertion     = true;
                pileupAlignment.PositionInAlignment = positionInAlignment + (CurrentPosition - genomePosition);
            }
            
            // increment marker
            genomePosition += op.Length;
        }

        // if op is REF_SKIP
        else if ( op.Type == 'N' ) {
            genomePosition += op.Length;
        }
        
        // if op is INSERTION or SOFT_CLIP
        else if ( op.Type == 'I' || op.Type == 'S' ) {
            positionInAlignment += op.Length;
        }
        
        // checl for beginning of new read segment
        if ( op.Type == 'N' ||
             op.Type == 'S' ||
             op.Type == 'H' )
            isNewReadSegment = true;
        else 
            isNewReadSegment = false;
      
        // if we've moved beyond current position
        if ( genomePosition > CurrentPosition ) {
            if ( op.Type == 'N' ) saveAlignment = false; // ignore alignment if REF_SKIP
            break;
        }
    }

    // save pileup position if flag is true
    if ( saveAlignment )
        CurrentPileupData.PileupAlignments.push_back( pileupAlignment );
}

// Assembly:
subq $0x1e8, %rsp            # imm = 0x1E8
movq %rdi, 0x1e0(%rsp)
movq %rsi, 0x1d8(%rsp)
movq 0x1e0(%rsp), %rax
movq %rax, 0x20(%rsp)
movq 0x1d8(%rsp), %rdi
callq 0x860f0
testb $0x1, %al
jne 0x11182a
jmp 0x111cc3
movq 0x1d8(%rsp), %rax
movl 0xac(%rax), %eax
movl %eax, 0x1d4(%rsp)
movl $0x0, 0x1d0(%rsp)
movb $0x1, 0x1cf(%rsp)
movb $0x1, 0x1ce(%rsp)
movq 0x1d8(%rsp), %rsi
leaq 0x58(%rsp), %rdi
callq 0x1120e0
movq 0x1d8(%rsp), %rdi
addq $0xb8, %rdi
callq 0xdf240
movq %rax, 0x18(%rsp)
jmp 0x111887
movq 0x18(%rsp), %rax
movl %eax, 0x54(%rsp)
movl $0x0, 0x40(%rsp)
movl 0x40(%rsp), %eax
cmpl 0x54(%rsp), %eax
jge 0x111c98
movq 0x1d8(%rsp), %rdi
addq $0xb8, %rdi
movslq 0x40(%rsp), %rsi
callq 0x112150
movq %rax, 0x10(%rsp)
jmp 0x1118c6
movq 0x10(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4d, %eax
jne 0x111b55
movq 0x20(%rsp), %rcx
movl 0x1d4(%rsp), %eax
movq 0x38(%rsp), %rdx
addl 0x4(%rdx), %eax
cmpl 0x4(%rcx), %eax
jle 0x111b24
movq 0x20(%rsp), %rcx
movb $0x0, 0x1b4(%rsp)
movb $0x0, 0x1b5(%rsp)
movb $0x0, 0x1b6(%rsp)
movl 0x1d0(%rsp), %eax
movl 0x4(%rcx), %edx
subl 0x1d4(%rsp), %edx
addl %edx, %eax
movl %eax, 0x1b0(%rsp)
movl 0x1d4(%rsp), %eax
cmpl 0x4(%rcx), %eax
jne 0x111972
testb $0x1, 0x1cf(%rsp)
je 0x111972
movb $0x1, 0x1c0(%rsp)
jmp 0x111972
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x48(%rsp)
movl %eax, 0x44(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x929f0
jmp 0x111ccb
movq 0x20(%rsp), %rcx
movl 0x1d4(%rsp), %eax
movq 0x38(%rsp), %rdx
addl 0x4(%rdx), %eax
subl $0x1, %eax
cmpl 0x4(%rcx), %eax
jne 0x111b22
movl 0x40(%rsp), %eax
movl 0x54(%rsp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x111b18
movq 0x1d8(%rsp), %rdi
addq $0xb8, %rdi
movl 0x40(%rsp), %eax
incl %eax
movslq %eax, %rsi
callq 0x112150
movq %rax, 0x8(%rsp)
jmp 0x1119c9
movq 0x8(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x44, %eax
jne 0x1119f9
movb $0x1, 0x1b5(%rsp)
movq 0x30(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x1b8(%rsp)
jmp 0x111a1f
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x49, %eax
jne 0x111a1d
movb $0x1, 0x1b6(%rsp)
movq 0x30(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, 0x1bc(%rsp)
jmp 0x111a1f
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x44, %eax
je 0x111a3d
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x49, %eax
jne 0x111ae5
movl 0x40(%rsp), %eax
movl 0x54(%rsp), %ecx
subl $0x2, %ecx
cmpl %ecx, %eax
jge 0x111aaa
movq 0x1d8(%rsp), %rdi
addq $0xb8, %rdi
movl 0x40(%rsp), %eax
addl $0x2, %eax
movslq %eax, %rsi
callq 0x112150
movq %rax, (%rsp)
jmp 0x111a70
movq (%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x53, %eax
je 0x111aa0
movq 0x28(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
je 0x111aa0
movq 0x28(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x48, %eax
jne 0x111aa8
movb $0x1, 0x1c1(%rsp)
jmp 0x111ae3
movb $0x1, 0x1c1(%rsp)
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x53, %eax
je 0x111ad9
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
je 0x111ad9
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x48, %eax
jne 0x111ae1
movb $0x1, 0x1c1(%rsp)
jmp 0x111ae3
jmp 0x111b16
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x53, %eax
je 0x111b0c
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
je 0x111b0c
movq 0x30(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x48, %eax
jne 0x111b14
movb $0x1, 0x1c1(%rsp)
jmp 0x111b16
jmp 0x111b20
movb $0x1, 0x1c1(%rsp)
jmp 0x111b22
jmp 0x111b24
movq 0x38(%rsp), %rax
movl 0x4(%rax), %eax
addl 0x1d4(%rsp), %eax
movl %eax, 0x1d4(%rsp)
movq 0x38(%rsp), %rax
movl 0x4(%rax), %eax
addl 0x1d0(%rsp), %eax
movl %eax, 0x1d0(%rsp)
jmp 0x111c25
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x44, %eax
jne 0x111bca
movq 0x20(%rsp), %rcx
movl 0x1d4(%rsp), %eax
movq 0x38(%rsp), %rdx
addl 0x4(%rdx), %eax
cmpl 0x4(%rcx), %eax
jle 0x111bb2
movq 0x20(%rsp), %rcx
movb $0x1, 0x1b4(%rsp)
movb $0x0, 0x1b5(%rsp)
movb $0x1, 0x1b6(%rsp)
movl 0x1d0(%rsp), %eax
movl 0x4(%rcx), %ecx
subl 0x1d4(%rsp), %ecx
addl %ecx, %eax
movl %eax, 0x1b0(%rsp)
movq 0x38(%rsp), %rax
movl 0x4(%rax), %eax
addl 0x1d4(%rsp), %eax
movl %eax, 0x1d4(%rsp)
jmp 0x111c23
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
jne 0x111bef
movq 0x38(%rsp), %rax
movl 0x4(%rax), %eax
addl 0x1d4(%rsp), %eax
movl %eax, 0x1d4(%rsp)
jmp 0x111c21
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x49, %eax
je 0x111c09
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x53, %eax
jne 0x111c1f
movq 0x38(%rsp), %rax
movl 0x4(%rax), %eax
addl 0x1d0(%rsp), %eax
movl %eax, 0x1d0(%rsp)
jmp 0x111c21
jmp 0x111c23
jmp 0x111c25
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
je 0x111c4c
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x53, %eax
je 0x111c4c
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x48, %eax
jne 0x111c56
movb $0x1, 0x1cf(%rsp)
jmp 0x111c5e
movb $0x0, 0x1cf(%rsp)
movq 0x20(%rsp), %rcx
movl 0x1d4(%rsp), %eax
cmpl 0x4(%rcx), %eax
jle 0x111c86
movq 0x38(%rsp), %rax
movsbl (%rax), %eax
cmpl $0x4e, %eax
jne 0x111c84
movb $0x0, 0x1ce(%rsp)
jmp 0x111c98
jmp 0x111c88
movl 0x40(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x40(%rsp)
jmp 0x111898
testb $0x1, 0x1ce(%rsp)
je 0x111cb9
movq 0x20(%rsp), %rdi
addq $0x28, %rdi
leaq 0x58(%rsp), %rsi
callq 0x112190
jmp 0x111cb7
jmp 0x111cb9
leaq 0x58(%rsp), %rdi
callq 0x929f0
addq $0x1e8, %rsp            # imm = 0x1E8
retq
jmp 0x111ccd
movq 0x48(%rsp), %rdi
callq 0x86d80
movq %rax, %rdi
callq 0x91290
nop