// File: /workspace/github_cpp_makefile_star2_O2/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 $0xe8, %rsp
movq %rsi, %r15
movq %rdi, %r14
movl 0x8(%rsi), %eax
movq %rax, 0x58(%rsp)
leaq 0xb8(%rsi), %rax
movq %rax, 0x20(%rsp)
movq 0xc0(%rsi), %r13
subq 0xb8(%rsi), %r13
leaq 0x28(%rsi), %r12
leaq 0x15167(%rip), %rsi     # 0x5b079
movq %r12, %rdi
callq 0x35790
movq $0x0, 0x10(%rsp)
testb %al, %al
jne 0x45f30
movl 0x30(%r15), %eax
movq %rax, 0x10(%rsp)
movq 0x90(%r15), %rax
movq %rax, 0x50(%rsp)
movl 0xac(%r15), %ebx
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x32eb0
movl %ebx, %esi
movl %eax, %edx
callq 0x31e00
movl %eax, %ebp
leaq 0x98(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq 0x88(%rsp), %rdx
movq 0x20(%rsp), %rsi
callq 0x31fe0
leaq 0xd8(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movq 0x90(%rsp), %rcx
movq %rcx, 0x20(%rsp)
movb $0x0, (%rax)
cmpl $0x0, 0x10(%rsp)
je 0x45fc1
leaq 0xc8(%rsp), %rdx
movq %r12, %rsi
callq 0x33ad0
movl 0xd0(%rsp), %edx
jmp 0x45fc3
xorl %edx, %edx
movq 0x10(%rsp), %rax
movq 0x58(%rsp), %rcx
addl %ecx, %eax
movq 0x50(%rsp), %rcx
movq 0x20(%rsp), %rsi
addl %esi, %ecx
addl %eax, %ecx
movq %rdx, 0x48(%rsp)
leal (%rdx,%rcx), %eax
addl $0x21, %eax
movl %eax, 0x1c(%rsp)
cmpb $0x1, 0x40(%r14)
jne 0x45ff9
bswapl %eax
movl %eax, 0x1c(%rsp)
leaq 0x1c(%rsp), %rsi
pushq $0x4
popq %rdx
movq %r14, %r12
movq %r14, %rdi
callq 0x34f70
shrq $0x3, %r13
movq 0x58(%rsp), %rcx
incl %ecx
movq 0xa8(%r15), %rax
movq %rax, 0x60(%rsp)
shll $0x10, %ebp
movzwl 0xb2(%r15), %eax
shll $0x8, %eax
movq %rcx, %rbx
orl %ecx, %eax
orl %ebp, %eax
movl %eax, 0x68(%rsp)
movl 0xb4(%r15), %eax
shll $0x10, %eax
orl %r13d, %eax
movl %eax, 0x6c(%rsp)
movq 0x10(%rsp), %rax
movl %eax, 0x70(%rsp)
movq 0xd0(%r15), %rax
movq %rax, 0x74(%rsp)
movl 0xd8(%r15), %eax
movl %eax, 0x7c(%rsp)
cmpb $0x1, 0x40(%r12)
movq 0x48(%rsp), %rbp
jne 0x46091
xorl %eax, %eax
cmpq $0x8, %rax
je 0x46091
movl 0x60(%rsp,%rax,4), %ecx
bswapl %ecx
movl %ecx, 0x60(%rsp,%rax,4)
incq %rax
jmp 0x4607c
leaq 0x60(%rsp), %rsi
pushq $0x20
popq %rdx
movq %r14, %r13
movq %r14, %rdi
callq 0x34f70
movq (%r15), %rsi
movl %ebx, %edx
movq %r13, %rdi
callq 0x34f70
movl 0x20(%rsp), %r12d
cmpb $0x1, 0x40(%r13)
jne 0x46100
movq %r12, %rdi
callq 0x31080
movq %rax, %r13
xorl %ebp, %ebp
movq %rax, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x320d0
movq 0x88(%rsp), %rsi
movq %r13, %rdi
movq %r12, %rdx
callq 0x32b40
cmpq %rbp, %r12
je 0x46115
movl (%r13,%rbp), %eax
bswapl %eax
movl %eax, (%r13,%rbp)
incq %rbp
jmp 0x460ea
movq 0x88(%rsp), %rsi
movq %r13, %rdi
movq %r12, %rdx
callq 0x34f70
jmp 0x46130
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x34f70
movq %r13, %rdi
callq 0x33c60
movq 0x48(%rsp), %rbp
cmpl $0x0, 0x10(%rsp)
je 0x461d9
movq 0xc8(%rsp), %rsi
movl %ebp, %edx
movq %r14, %rdi
callq 0x34f70
movl 0x10(%rsp), %r12d
movq %r12, %rdi
callq 0x31080
movq %rax, %r13
movq %rax, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x320d0
movq 0x70(%r15), %rax
testq %rax, %rax
je 0x461b3
leaq 0x68(%r15), %rbp
cmpq $0x1, %rax
jne 0x46189
movq (%rbp), %rax
movb (%rax), %al
cmpb $0x2a, %al
jne 0x4618f
jmp 0x461b3
movq (%rbp), %rax
movb (%rax), %al
cmpb $-0x1, %al
je 0x461b3
xorl %ebx, %ebx
cmpq %rbx, %r12
je 0x461c3
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x33930
movb (%rax), %al
addb $-0x21, %al
movb %al, (%r13,%rbx)
incq %rbx
jmp 0x46195
movq %r13, %rdi
movl $0xff, %esi
movq %r12, %rdx
callq 0x320d0
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x34f70
movq %r13, %rdi
callq 0x33c60
movl 0x50(%rsp), %r12d
cmpb $0x1, 0x40(%r14)
jne 0x4634f
movq %r12, %rdi
callq 0x31080
movq %rax, %r13
movq %rax, %rdi
xorl %esi, %esi
movq %r12, %rdx
callq 0x320d0
movq 0x88(%r15), %rsi
movq %r13, %rdi
movq %r12, %rdx
callq 0x32b40
leaq 0x15b5e(%rip), %rax     # 0x5bd78
pushq $0x1
popq %rcx
movabsq $0x4800000040, %rdx     # imm = 0x4800000040
movabsq $0x100000001, %rsi      # imm = 0x100000001
movabsq $0x1000000010000, %rbx  # imm = 0x1000000010000
pushq $0x2
popq %r8
xorl %r9d, %r9d
movq %r14, %rdi
cmpq %r12, %r9
jae 0x46363
movb 0x2(%r13,%r9), %bpl
leaq 0x3(%r9), %r10
movzbl %bpl, %r11d
leal -0x41(%r11), %r15d
cmpl $0x8, %r15d
jbe 0x46291
cmpl $0x53, %r11d
je 0x462cb
cmpl $0x73, %r11d
je 0x462cb
cmpl $0x63, %r11d
movq %r14, %rdi
je 0x4629e
cmpl $0x66, %r11d
je 0x462b5
cmpl $0x69, %r11d
je 0x462b5
cmpl $0x5a, %r11d
je 0x462a4
jmp 0x46436
movslq (%rax,%r15,4), %r11
addq %rax, %r11
movq %r14, %rdi
jmpq *%r11
addq $0x4, %r9
jmp 0x46245
leaq 0x1(%r10), %r9
cmpb $0x0, (%r13,%r10)
movq %r9, %r10
jne 0x462a4
jmp 0x46245
movl 0x3(%r13,%r9), %r10d
bswapl %r10d
movl %r10d, 0x3(%r13,%r9)
addq $0x7, %r9
jmp 0x46245
rolw $0x8, 0x3(%r13,%r9)
addq $0x5, %r9
jmp 0x46242
movzbl 0x3(%r13,%r9), %r15d
movl 0x4(%r13,%r9), %r10d
bswapl %r10d
movl %r10d, 0x4(%r13,%r9)
addq $0x8, %r9
testl %r10d, %r10d
movl $0x0, %edi
cmovlel %edi, %r10d
pushq $0x4
popq %rdi
subl $0x1, %r10d
jb 0x46242
leal -0x43(%r15), %r11d
cmpl $0x30, %r11d
ja 0x463a2
btq %r11, %rdx
jb 0x4633a
btq %r11, %rsi
movq %rcx, %rbp
jb 0x4634a
btq %r11, %rbx
jae 0x463a2
rolw $0x8, (%r13,%r9)
movq %r8, %rbp
jmp 0x4634a
movl (%r13,%r9), %r11d
bswapl %r11d
movl %r11d, (%r13,%r9)
movq %rdi, %rbp
addq %rbp, %r9
jmp 0x46301
movq %r14, %rdi
movq 0x88(%r15), %rsi
movq %r12, %rdx
callq 0x34f70
jmp 0x46376
movq %r13, %rsi
movq %r12, %rdx
callq 0x34f70
movq %r13, %rdi
callq 0x33c60
leaq 0xc8(%rsp), %rdi
callq 0x33a00
leaq 0x88(%rsp), %rdi
callq 0x33a00
addq $0xe8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r13, %rdi
callq 0x33c60
leaq 0x14d05(%rip), %rsi     # 0x5b0b6
leaq 0x28(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x31b30
movsbl %r15b, %edx
leaq 0xa8(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x32560
leaq 0x28(%rsp), %rdi
callq 0x33a00
pushq $0x28
popq %rdi
callq 0x31e70
movq %rax, %r14
leaq 0x15a12(%rip), %rsi     # 0x5be04
leaq 0x28(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x31b30
movb $0x1, %bpl
leaq 0x28(%rsp), %rsi
leaq 0xa8(%rsp), %rdx
movq %r14, %rdi
callq 0x344c0
xorl %ebp, %ebp
movq 0x2eb16(%rip), %rsi     # 0x74f38
movq 0x2eb4f(%rip), %rdx     # 0x74f78
movq %r14, %rdi
callq 0x34c90
jmp 0x464c5
movq %r13, %rdi
callq 0x33c60
leaq 0x14c8d(%rip), %rsi     # 0x5b0d2
leaq 0x28(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x31b30
movsbl %bpl, %edx
leaq 0xa8(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x32560
leaq 0x28(%rsp), %rdi
callq 0x33a00
pushq $0x28
popq %rdi
callq 0x31e70
movq %rax, %r14
leaq 0x1597e(%rip), %rsi     # 0x5be04
leaq 0x28(%rsp), %rdi
leaq 0xf(%rsp), %rdx
callq 0x31b30
movb $0x1, %bpl
leaq 0x28(%rsp), %rsi
leaq 0xa8(%rsp), %rdx
movq %r14, %rdi
callq 0x344c0
xorl %ebp, %ebp
movq 0x2ea82(%rip), %rsi     # 0x74f38
movq 0x2eabb(%rip), %rdx     # 0x74f78
movq %r14, %rdi
callq 0x34c90
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
testb %bpl, %bpl
jne 0x464dc
jmp 0x464e4
movq %rax, %rbx
movq %r14, %rdi
callq 0x327c0
leaq 0xa8(%rsp), %rdi
callq 0x33a00
jmp 0x4655b
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
testb %bpl, %bpl
jne 0x4650a
jmp 0x46512
movq %rax, %rbx
movq %r14, %rdi
callq 0x327c0
leaq 0xa8(%rsp), %rdi
callq 0x33a00
jmp 0x4655b
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
jmp 0x4655b
jmp 0x46558
jmp 0x46558
jmp 0x46558
jmp 0x4653c
jmp 0x46558
jmp 0x46558
movq %rax, %rbx
jmp 0x46568
jmp 0x46558
jmp 0x46558
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x33a00
jmp 0x4655b
jmp 0x46558
jmp 0x46558
movq %rax, %rbx
leaq 0xc8(%rsp), %rdi
callq 0x33a00
leaq 0x88(%rsp), %rdi
callq 0x33a00
movq %rbx, %rdi
callq 0x34ed0
movq %rax, %rdi
callq 0x39b2f
nop