// File: /workspace/github_cpp_makefile_star2_O3/zeeev[P]DASVC/bamtools/src/api/internal/bam/BamWriter_p.cpp
// Function: BamTools::Internal::BamWriterPrivate::WriteAlignment(BamTools::BamAlignment const&)
void BamWriterPrivate::WriteAlignment(const BamAlignment& al) {

    // calculate char lengths
    const unsigned int nameLength         = al.Name.size() + 1;
    const unsigned int numCigarOperations = al.CigarData.size();
    const unsigned int queryLength        = ( (al.QueryBases == "*") ? 0 : al.QueryBases.size() );
    const unsigned int tagDataLength      = al.TagData.size();

    // no way to tell if alignment's bin is already defined (there is no default, invalid value)
    // so we'll go ahead calculate its bin ID before storing
    const uint32_t alignmentBin = CalculateMinimumBin(al.Position, al.GetEndPosition());

    // create our packed cigar string
    string packedCigar;
    CreatePackedCigar(al.CigarData, packedCigar);
    const unsigned int packedCigarLength = packedCigar.size();

    // encode the query
    unsigned int encodedQueryLength = 0;
    string encodedQuery;
    if ( queryLength > 0 ) {
        EncodeQuerySequence(al.QueryBases, encodedQuery);
        encodedQueryLength = encodedQuery.size();
    }

    // write the block size
    const unsigned int dataBlockSize = nameLength +
                                       packedCigarLength +
                                       encodedQueryLength +
                                       queryLength +         // here referring to quality length
                                       tagDataLength;
    unsigned int blockSize = Constants::BAM_CORE_SIZE + dataBlockSize;
    if ( m_isBigEndian ) BamTools::SwapEndian_32(blockSize);
    m_stream.Write((char*)&blockSize, Constants::BAM_SIZEOF_INT);

    // assign the BAM core data
    uint32_t buffer[Constants::BAM_CORE_BUFFER_SIZE];
    buffer[0] = al.RefID;
    buffer[1] = al.Position;
    buffer[2] = (alignmentBin << 16) | (al.MapQuality << 8) | nameLength;
    buffer[3] = (al.AlignmentFlag << 16) | numCigarOperations;
    buffer[4] = queryLength;
    buffer[5] = al.MateRefID;
    buffer[6] = al.MatePosition;
    buffer[7] = al.InsertSize;

    // swap BAM core endian-ness, if necessary
    if ( m_isBigEndian ) {
        for ( int i = 0; i < 8; ++i )
            BamTools::SwapEndian_32(buffer[i]);
    }

    // write the BAM core
    m_stream.Write((char*)&buffer, Constants::BAM_CORE_SIZE);

    // write the query name
    m_stream.Write(al.Name.c_str(), nameLength);

    // write the packed cigar
    if ( m_isBigEndian ) {
        char* cigarData = new char[packedCigarLength]();
        memcpy(cigarData, packedCigar.data(), packedCigarLength);
        if ( m_isBigEndian ) {
            for ( size_t i = 0; i < packedCigarLength; ++i )
                BamTools::SwapEndian_32p(&cigarData[i]);
        }
        m_stream.Write(cigarData, packedCigarLength);
        delete[] cigarData; // TODO: cleanup on Write exception thrown?
    }
    else
        m_stream.Write(packedCigar.data(), packedCigarLength);

    if ( queryLength > 0 ) {

        // write the encoded query sequence
        m_stream.Write(encodedQuery.data(), encodedQueryLength);

        // write the base qualities
        char* pBaseQualities = new char[queryLength]();
        if ( al.Qualities.empty() || ( al.Qualities.size() == 1 && al.Qualities[0] == '*' ) || al.Qualities[0] == (char)0xFF )
            memset(pBaseQualities, 0xFF, queryLength); // if missing or '*', fill with invalid qual
        else {
            for ( size_t i = 0; i < queryLength; ++i )
                pBaseQualities[i] = al.Qualities.at(i) - 33; // FASTQ ASCII -> phred score conversion
        }
        m_stream.Write(pBaseQualities, queryLength);
        delete[] pBaseQualities;
    }

    // write the tag data
    if ( m_isBigEndian ) {

        char* tagData = new char[tagDataLength]();
        memcpy(tagData, al.TagData.data(), tagDataLength);

        size_t i = 0;
        while ( i < tagDataLength ) {

            i += Constants::BAM_TAG_TAGSIZE;  // skip tag chars (e.g. "RG", "NM", etc.)
            const char type = tagData[i];     // get tag type at position i
            ++i;

            switch ( type ) {

                case(Constants::BAM_TAG_TYPE_ASCII) :
                case(Constants::BAM_TAG_TYPE_INT8)  :
                case(Constants::BAM_TAG_TYPE_UINT8) :
                    ++i;
                    break;

                case(Constants::BAM_TAG_TYPE_INT16)  :
                case(Constants::BAM_TAG_TYPE_UINT16) :
                    BamTools::SwapEndian_16p(&tagData[i]);
                    i += sizeof(uint16_t);
                    break;

                case(Constants::BAM_TAG_TYPE_FLOAT)  :
                case(Constants::BAM_TAG_TYPE_INT32)  :
                case(Constants::BAM_TAG_TYPE_UINT32) :
                    BamTools::SwapEndian_32p(&tagData[i]);
                    i += sizeof(uint32_t);
                    break;

                case(Constants::BAM_TAG_TYPE_HEX) :
                case(Constants::BAM_TAG_TYPE_STRING) :
                    // no endian swapping necessary for hex-string/string data
                    while ( tagData[i] )
                        ++i;
                    // increment one more for null terminator
                    ++i;
                    break;

                case(Constants::BAM_TAG_TYPE_ARRAY) :

                {
                    // read array type
                    const char arrayType = tagData[i];
                    ++i;

                    // swap endian-ness of number of elements in place, then retrieve for loop
                    BamTools::SwapEndian_32p(&tagData[i]);
                    int32_t numElements;
                    memcpy(&numElements, &tagData[i], sizeof(uint32_t));
                    i += sizeof(uint32_t);

                    // swap endian-ness of array elements
                    for ( int j = 0; j < numElements; ++j ) {
                        switch (arrayType) {
                            case (Constants::BAM_TAG_TYPE_INT8)  :
                            case (Constants::BAM_TAG_TYPE_UINT8) :
                                // no endian-swapping necessary
                                ++i;
                                break;
                            case (Constants::BAM_TAG_TYPE_INT16)  :
                            case (Constants::BAM_TAG_TYPE_UINT16) :
                                BamTools::SwapEndian_16p(&tagData[i]);
                                i += sizeof(uint16_t);
                                break;
                            case (Constants::BAM_TAG_TYPE_FLOAT)  :
                            case (Constants::BAM_TAG_TYPE_INT32)  :
                            case (Constants::BAM_TAG_TYPE_UINT32) :
                                BamTools::SwapEndian_32p(&tagData[i]);
                                i += sizeof(uint32_t);
                                break;
                            default:
                                delete[] tagData;
                                const string message = string("invalid binary array type: ") + arrayType;
                                throw BamException("BamWriter::SaveAlignment", message);
                        }
                    }

                    break;
                }

                default :
                    delete[] tagData;
                    const string message = string("invalid tag type: ") + type;
                    throw BamException("BamWriter::SaveAlignment", message);
            }
        }

        m_stream.Write(tagData, tagDataLength);
        delete[] tagData; // TODO: cleanup on Write exception thrown?
    }
    else
        m_stream.Write(al.TagData.data(), tagDataLength);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rsi, %r14
movq %rdi, 0x48(%rsp)
movl 0x8(%rsi), %ebx
leaq 0xb8(%rsi), %r13
movq 0xc0(%rsi), %r15
subq 0xb8(%rsi), %r15
leaq 0x28(%rsi), %r12
leaq 0x17fcf(%rip), %rsi     # 0x55079
movq %r12, %rdi
callq 0x264c0
movq %rax, 0x8(%rsp)
testl %eax, %eax
je 0x3d0c4
movl 0x30(%r14), %eax
movq %rax, 0x8(%rsp)
movq 0x90(%r14), %rax
movq %rax, 0x40(%rsp)
movl 0xac(%r14), %ebp
movq $0x0, 0x18(%rsp)
movq %r14, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x274a0
movl %ebp, %esi
movl %eax, %edx
callq 0x26960
movl %eax, %ebp
leaq 0x88(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x78(%rsp), %rdx
movq %r13, %rsi
callq 0x26b10
movq 0x80(%rsp), %r13
leaq 0xa8(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
cmpl $0x0, 0x8(%rsp)
je 0x3d15d
leaq 0x98(%rsp), %rdx
movq %r12, %rsi
callq 0x27d40
movl 0xa0(%rsp), %eax
movq %rax, 0x18(%rsp)
movq 0x8(%rsp), %rax
addl %ebx, %eax
movq 0x40(%rsp), %rcx
addl %r13d, %ecx
addl %eax, %ecx
movq 0x18(%rsp), %rax
addl %ecx, %eax
addl $0x21, %eax
movl %eax, 0x14(%rsp)
movq 0x48(%rsp), %rcx
cmpb $0x1, 0x40(%rcx)
jne 0x3d18d
bswapl %eax
movl %eax, 0x14(%rsp)
leaq 0x14(%rsp), %rsi
movl $0x4, %edx
movq 0x48(%rsp), %r12
movq %r12, %rdi
callq 0x28c90
shrq $0x3, %r15
incl %ebx
movq 0xa8(%r14), %rax
movq %rax, 0x50(%rsp)
shll $0x10, %ebp
movzwl 0xb2(%r14), %eax
shll $0x8, %eax
orl %ebx, %eax
orl %ebp, %eax
movl %eax, 0x58(%rsp)
movl 0xb4(%r14), %eax
shll $0x10, %eax
orl %r15d, %eax
movl %eax, 0x5c(%rsp)
movq 0x8(%rsp), %rax
movl %eax, 0x60(%rsp)
movq 0xd0(%r14), %rax
movq %rax, 0x64(%rsp)
movl 0xd8(%r14), %eax
movl %eax, 0x6c(%rsp)
cmpb $0x1, 0x40(%r12)
movq %r12, %rbp
jne 0x3d248
xorl %eax, %eax
pxor %xmm0, %xmm0
movdqa 0x50(%rsp,%rax,4), %xmm1
movdqa %xmm1, %xmm2
punpckhbw %xmm0, %xmm2    # xmm2 = xmm2[8],xmm0[8],xmm2[9],xmm0[9],xmm2[10],xmm0[10],xmm2[11],xmm0[11],xmm2[12],xmm0[12],xmm2[13],xmm0[13],xmm2[14],xmm0[14],xmm2[15],xmm0[15]
pshuflw $0x1b, %xmm2, %xmm2     # xmm2 = xmm2[3,2,1,0,4,5,6,7]
pshufhw $0x1b, %xmm2, %xmm2     # xmm2 = xmm2[0,1,2,3,7,6,5,4]
punpcklbw %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1],xmm1[2],xmm0[2],xmm1[3],xmm0[3],xmm1[4],xmm0[4],xmm1[5],xmm0[5],xmm1[6],xmm0[6],xmm1[7],xmm0[7]
pshuflw $0x1b, %xmm1, %xmm1     # xmm1 = xmm1[3,2,1,0,4,5,6,7]
pshufhw $0x1b, %xmm1, %xmm1     # xmm1 = xmm1[0,1,2,3,7,6,5,4]
packuswb %xmm2, %xmm1
movdqa %xmm1, 0x50(%rsp,%rax,4)
addq $0x4, %rax
cmpq $0x8, %rax
jne 0x3d20e
leaq 0x50(%rsp), %rsi
movl $0x20, %edx
movq %rbp, %rdi
callq 0x28c90
movq (%r14), %rsi
movl %ebx, %edx
movq %rbp, %rdi
callq 0x28c90
movl %r13d, %r12d
cmpb $0x1, 0x40(%rbp)
jne 0x3d2cb
movq %r12, %rdi
callq 0x26070
movq %rax, %r13
movq %rax, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x26bc0
movq 0x78(%rsp), %rsi
movq %r13, %rdi
movq %r12, %rdx
callq 0x27260
testq %r12, %r12
je 0x3d2b3
xorl %eax, %eax
movl (%r13,%rax), %ecx
bswapl %ecx
movl %ecx, (%r13,%rax)
incq %rax
cmpq %rax, %r12
jne 0x3d29f
movq %rbp, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x28c90
movq %r13, %rdi
callq 0x27e60
jmp 0x3d2db
movq 0x78(%rsp), %rsi
movq %rbp, %rdi
movq %r12, %rdx
callq 0x28c90
cmpl $0x0, 0x8(%rsp)
je 0x3d385
movq 0x98(%rsp), %rsi
movl 0x18(%rsp), %edx
movq %rbp, %rdi
callq 0x28c90
movl 0x8(%rsp), %r15d
movq %r15, %rdi
callq 0x26070
movq %rax, %r12
movq %rax, %rdi
xorl %esi, %esi
movq %r15, %rdx
callq 0x26bc0
movq 0x70(%r14), %rdx
testq %rdx, %rdx
je 0x3d35f
cmpq $0x1, %rdx
jne 0x3d333
movq 0x68(%r14), %rax
movb (%rax), %cl
cmpb $0x2a, %cl
jne 0x3d339
jmp 0x3d35f
movq 0x68(%r14), %rax
movb (%rax), %cl
cmpb $-0x1, %cl
je 0x3d35f
xorl %ecx, %ecx
cmpq %rcx, %rdx
je 0x3d569
movb (%rax,%rcx), %sil
addb $-0x21, %sil
movb %sil, (%r12,%rcx)
incq %rcx
cmpq %rcx, %r15
jne 0x3d340
jmp 0x3d36f
movq %r12, %rdi
movl $0xff, %esi
movq %r15, %rdx
callq 0x26bc0
movq %rbp, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x28c90
movq %r12, %rdi
callq 0x27e60
movl 0x40(%rsp), %r15d
cmpb $0x1, 0x40(%rbp)
jne 0x3d4fc
movq %r15, %rdi
callq 0x26070
movq %rax, %r12
movq %rax, %rdi
xorl %esi, %esi
movq %r15, %rdx
callq 0x26bc0
movq 0x88(%r14), %rsi
movq %r12, %rdi
movq %r15, %rdx
callq 0x27260
testq %r15, %r15
je 0x3d510
xorl %esi, %esi
leaq 0x18964(%rip), %rax     # 0x55d34
movabsq $0x1004900010041, %rcx  # imm = 0x1004900010041
leaq 0x18977(%rip), %rdx     # 0x55d58
movb 0x2(%r12,%rsi), %bl
leaq 0x3(%rsi), %rdi
movzbl %bl, %r8d
cmpl $0x52, %r8d
jle 0x3d411
cmpl $0x65, %r8d
jg 0x3d43f
cmpl $0x53, %r8d
je 0x3d455
cmpl $0x5a, %r8d
je 0x3d42f
cmpl $0x63, %r8d
je 0x3d429
jmp 0x3d57a
addl $-0x41, %r8d
cmpl $0x8, %r8d
ja 0x3d57a
movslq (%rax,%r8,4), %r8
addq %rax, %r8
jmpq *%r8
addq $0x4, %rsi
jmp 0x3d472
leaq 0x1(%rdi), %rsi
cmpb $0x0, (%r12,%rdi)
movq %rsi, %rdi
jne 0x3d42f
jmp 0x3d472
cmpl $0x66, %r8d
je 0x3d462
cmpl $0x69, %r8d
je 0x3d462
cmpl $0x73, %r8d
jne 0x3d57a
rolw $0x8, 0x3(%r12,%rsi)
addq $0x5, %rsi
jmp 0x3d472
movl 0x3(%r12,%rsi), %edi
bswapl %edi
movl %edi, 0x3(%r12,%rsi)
addq $0x7, %rsi
cmpq %r15, %rsi
jb 0x3d3e1
jmp 0x3d510
movzbl 0x3(%r12,%rsi), %ebx
movl 0x4(%r12,%rsi), %edi
bswapl %edi
movl %edi, 0x4(%r12,%rsi)
addq $0x8, %rsi
testl %edi, %edi
jle 0x3d472
leal -0x43(%rbx), %r8d
cmpl $0x30, %r8d
ja 0x3d624
btq %r8, %rcx
jae 0x3d624
addb $-0x43, %bl
rolb $0x4, %bl
movzbl %bl, %r8d
cmpb $0x3, %bl
ja 0x3d4df
movl $0x1, %r9d
movslq (%rdx,%r8,4), %r10
addq %rdx, %r10
jmpq *%r10
rolw $0x8, (%r12,%rsi)
movl $0x2, %r9d
jmp 0x3d4f0
movl (%r12,%rsi), %r9d
bswapl %r9d
movl %r9d, (%r12,%rsi)
movl $0x4, %r9d
addq %r9, %rsi
decl %edi
jne 0x3d4bc
jmp 0x3d472
movq 0x88(%r14), %rsi
movq %rbp, %rdi
movq %r15, %rdx
callq 0x28c90
jmp 0x3d526
movq %rbp, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x28c90
movq %r12, %rdi
callq 0x27e60
movq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rax
cmpq %rax, %rdi
je 0x3d540
callq 0x27560
movq 0x78(%rsp), %rdi
leaq 0x88(%rsp), %rax
cmpq %rax, %rdi
je 0x3d557
callq 0x27560
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x18879(%rip), %rdi     # 0x55de9
movq %rdx, %rsi
xorl %eax, %eax
callq 0x284e0
movq %r12, %rdi
callq 0x27e60
leaq 0x30(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x17b40(%rip), %rsi     # 0x550d2
leaq 0x17b4b(%rip), %rdx     # 0x550e4
leaq 0x20(%rsp), %rdi
callq 0x26750
movsbl %bl, %edx
leaq 0xb8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x26e90
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d5c7
callq 0x27560
movl $0x28, %edi
callq 0x269d0
movq %rax, %r14
leaq 0x20(%rsp), %rdi
movq %r15, (%rdi)
leaq 0x187ed(%rip), %rsi     # 0x55dd0
leaq 0x187fe(%rip), %rdx     # 0x55de8
callq 0x26750
movb $0x1, %bpl
leaq 0x20(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
movq %r14, %rdi
callq 0x28480
xorl %ebp, %ebp
movq 0x2d928(%rip), %rsi     # 0x6af38
movq 0x2d961(%rip), %rdx     # 0x6af78
movq %r14, %rdi
callq 0x28a20
jmp 0x3d6c9
movq %r12, %rdi
callq 0x27e60
leaq 0x30(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x17a7a(%rip), %rsi     # 0x550b6
leaq 0x17a8e(%rip), %rdx     # 0x550d1
leaq 0x20(%rsp), %rdi
callq 0x26750
movsbl %bl, %edx
leaq 0xb8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x26e90
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d671
callq 0x27560
movl $0x28, %edi
callq 0x269d0
movq %rax, %r14
leaq 0x20(%rsp), %rdi
movq %r15, (%rdi)
leaq 0x18743(%rip), %rsi     # 0x55dd0
leaq 0x18754(%rip), %rdx     # 0x55de8
callq 0x26750
movb $0x1, %bpl
leaq 0x20(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
movq %r14, %rdi
callq 0x28480
xorl %ebp, %ebp
movq 0x2d87e(%rip), %rsi     # 0x6af38
movq 0x2d8b7(%rip), %rdx     # 0x6af78
movq %r14, %rdi
callq 0x28a20
jmp 0x3d6d1
jmp 0x3d6ea
jmp 0x3d708
jmp 0x3d731
movq %rax, %rbx
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d6e3
callq 0x27560
testb %bpl, %bpl
jne 0x3d6ed
jmp 0x3d6f5
movq %rax, %rbx
movq %r14, %rdi
callq 0x27070
leaq 0xc8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
jne 0x3d715
jmp 0x3d734
movq %rax, %rbx
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d734
callq 0x27560
jmp 0x3d734
jmp 0x3d731
jmp 0x3d731
jmp 0x3d731
jmp 0x3d731
jmp 0x3d731
jmp 0x3d731
movq %rax, %rbx
jmp 0x3d74e
jmp 0x3d731
jmp 0x3d731
movq %rax, %rbx
movq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rax
cmpq %rax, %rdi
je 0x3d74e
callq 0x27560
movq 0x78(%rsp), %rdi
leaq 0x88(%rsp), %rax
cmpq %rax, %rdi
je 0x3d765
callq 0x27560
movq %rbx, %rdi
callq 0x28c10
nop