// File: /workspace/github_cpp_makefile_star2_O1/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 0x17f0f(%rip), %rsi     # 0x55079
movq %r12, %rdi
callq 0x264c0
movq %rax, 0x8(%rsp)
testl %eax, %eax
je 0x3d184
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 0x3d21d
leaq 0x98(%rsp), %rdx
movq %r12, %rsi
callq 0x27d50
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 0x3d24d
bswapl %eax
movl %eax, 0x14(%rsp)
leaq 0x14(%rsp), %rsi
movl $0x4, %edx
movq 0x48(%rsp), %r12
movq %r12, %rdi
callq 0x28ca0
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 0x3d308
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 0x3d2ce
leaq 0x50(%rsp), %rsi
movl $0x20, %edx
movq %rbp, %rdi
callq 0x28ca0
movq (%r14), %rsi
movl %ebx, %edx
movq %rbp, %rdi
callq 0x28ca0
movl %r13d, %r12d
cmpb $0x1, 0x40(%rbp)
jne 0x3d38b
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 0x3d373
xorl %eax, %eax
movl (%r13,%rax), %ecx
bswapl %ecx
movl %ecx, (%r13,%rax)
incq %rax
cmpq %rax, %r12
jne 0x3d35f
movq %rbp, %rdi
movq %r13, %rsi
movq %r12, %rdx
callq 0x28ca0
movq %r13, %rdi
callq 0x27e70
jmp 0x3d39b
movq 0x78(%rsp), %rsi
movq %rbp, %rdi
movq %r12, %rdx
callq 0x28ca0
cmpl $0x0, 0x8(%rsp)
je 0x3d44a
movq 0x98(%rsp), %rsi
movl 0x18(%rsp), %edx
movq %rbp, %rdi
callq 0x28ca0
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 0x3d424
cmpq $0x1, %rdx
jne 0x3d3ef
movq 0x68(%r14), %rax
cmpb $0x2a, (%rax)
je 0x3d424
movq 0x68(%r14), %rax
cmpb $-0x1, (%rax)
je 0x3d424
cmpq $0x1, %r15
movq %r15, %rcx
adcq $0x0, %rcx
xorl %esi, %esi
cmpq %rsi, %rdx
je 0x3d63f
movb (%rax,%rsi), %dil
addb $-0x21, %dil
movb %dil, (%r12,%rsi)
incq %rsi
cmpq %rsi, %rcx
jne 0x3d405
jmp 0x3d434
movq %r12, %rdi
movl $0xff, %esi
movq %r15, %rdx
callq 0x26bc0
movq %rbp, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x28ca0
movq %r12, %rdi
callq 0x27e70
movl 0x40(%rsp), %r15d
cmpb $0x1, 0x40(%rbp)
jne 0x3d5d2
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 0x3d5e6
xorl %edi, %edi
leaq 0x1889f(%rip), %rax     # 0x55d34
movabsq $0x1004900010041, %rcx  # imm = 0x1004900010041
movl $0x1, %edx
leaq 0x188ad(%rip), %rsi     # 0x55d58
movb 0x2(%r12,%rdi), %bl
leaq 0x3(%rdi), %r8
movzbl %bl, %r9d
cmpl $0x52, %r9d
jle 0x3d4db
cmpl $0x65, %r9d
jg 0x3d509
cmpl $0x53, %r9d
je 0x3d51f
cmpl $0x5a, %r9d
je 0x3d4f9
cmpl $0x63, %r9d
je 0x3d4f3
jmp 0x3d64d
addl $-0x41, %r9d
cmpl $0x8, %r9d
ja 0x3d64d
movslq (%rax,%r9,4), %r9
addq %rax, %r9
jmpq *%r9
addq $0x4, %rdi
jmp 0x3d53d
leaq 0x1(%r8), %rdi
cmpb $0x0, (%r12,%r8)
movq %rdi, %r8
jne 0x3d4f9
jmp 0x3d53d
cmpl $0x66, %r9d
je 0x3d52c
cmpl $0x69, %r9d
je 0x3d52c
cmpl $0x73, %r9d
jne 0x3d64d
rolw $0x8, 0x3(%r12,%rdi)
addq $0x5, %rdi
jmp 0x3d53d
movl 0x3(%r12,%rdi), %r8d
bswapl %r8d
movl %r8d, 0x3(%r12,%rdi)
addq $0x7, %rdi
cmpq %r15, %rdi
jb 0x3d4ab
jmp 0x3d5e6
movzbl 0x3(%r12,%rdi), %ebx
movl 0x4(%r12,%rdi), %r8d
bswapl %r8d
movl %r8d, 0x4(%r12,%rdi)
addq $0x8, %rdi
testl %r8d, %r8d
jle 0x3d53d
leal -0x43(%rbx), %r9d
cmpl $0x30, %r9d
ja 0x3d6f7
btq %r9, %rcx
jae 0x3d6f7
cmpl $0x2, %r8d
cmovll %edx, %r8d
addb $-0x43, %bl
rolb $0x4, %bl
movzbl %bl, %r9d
cmpb $0x3, %bl
ja 0x3d5b4
movl $0x1, %r10d
movslq (%rsi,%r9,4), %r11
addq %rsi, %r11
jmpq *%r11
rolw $0x8, (%r12,%rdi)
movl $0x2, %r10d
jmp 0x3d5c5
movl (%r12,%rdi), %r10d
bswapl %r10d
movl %r10d, (%r12,%rdi)
movl $0x4, %r10d
addq %r10, %rdi
decl %r8d
jne 0x3d591
jmp 0x3d53d
movq 0x88(%r14), %rsi
movq %rbp, %rdi
movq %r15, %rdx
callq 0x28ca0
jmp 0x3d5fc
movq %rbp, %rdi
movq %r12, %rsi
movq %r15, %rdx
callq 0x28ca0
movq %r12, %rdi
callq 0x27e70
movq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rax
cmpq %rax, %rdi
je 0x3d616
callq 0x27560
movq 0x78(%rsp), %rdi
leaq 0x88(%rsp), %rax
cmpq %rax, %rdi
je 0x3d62d
callq 0x27560
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x187a3(%rip), %rdi     # 0x55de9
xorl %eax, %eax
callq 0x284f0
movq %r12, %rdi
callq 0x27e70
leaq 0x30(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x17a6d(%rip), %rsi     # 0x550d2
leaq 0x17a78(%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 0x3d69a
callq 0x27560
movl $0x28, %edi
callq 0x269d0
movq %rax, %r14
leaq 0x20(%rsp), %rdi
movq %r15, (%rdi)
leaq 0x1871a(%rip), %rsi     # 0x55dd0
leaq 0x1872b(%rip), %rdx     # 0x55de8
callq 0x26750
movb $0x1, %bpl
leaq 0x20(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
movq %r14, %rdi
callq 0x28490
xorl %ebp, %ebp
movq 0x2d855(%rip), %rsi     # 0x6af38
movq 0x2d88e(%rip), %rdx     # 0x6af78
movq %r14, %rdi
callq 0x28a30
jmp 0x3d79c
movq %r12, %rdi
callq 0x27e70
leaq 0x30(%rsp), %r15
movq %r15, -0x10(%r15)
leaq 0x179a7(%rip), %rsi     # 0x550b6
leaq 0x179bb(%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 0x3d744
callq 0x27560
movl $0x28, %edi
callq 0x269d0
movq %rax, %r14
leaq 0x20(%rsp), %rdi
movq %r15, (%rdi)
leaq 0x18670(%rip), %rsi     # 0x55dd0
leaq 0x18681(%rip), %rdx     # 0x55de8
callq 0x26750
movb $0x1, %bpl
leaq 0x20(%rsp), %rsi
leaq 0xb8(%rsp), %rdx
movq %r14, %rdi
callq 0x28490
xorl %ebp, %ebp
movq 0x2d7ab(%rip), %rsi     # 0x6af38
movq 0x2d7e4(%rip), %rdx     # 0x6af78
movq %r14, %rdi
callq 0x28a30
jmp 0x3d7a4
jmp 0x3d7b8
jmp 0x3d7de
jmp 0x3d807
movq %rax, %rbx
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d7be
callq 0x27560
jmp 0x3d7be
movq %rax, %rbx
movb $0x1, %bpl
testb %bpl, %bpl
je 0x3d7cb
movq %r14, %rdi
callq 0x27070
leaq 0xc8(%rsp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
jne 0x3d7eb
jmp 0x3d80a
movq %rax, %rbx
movq 0x20(%rsp), %rdi
cmpq %r15, %rdi
je 0x3d80a
callq 0x27560
jmp 0x3d80a
jmp 0x3d807
jmp 0x3d807
jmp 0x3d807
jmp 0x3d807
jmp 0x3d807
jmp 0x3d807
movq %rax, %rbx
jmp 0x3d824
jmp 0x3d807
jmp 0x3d807
movq %rax, %rbx
movq 0x98(%rsp), %rdi
leaq 0xa8(%rsp), %rax
cmpq %rax, %rdi
je 0x3d824
callq 0x27560
movq 0x78(%rsp), %rdi
leaq 0x88(%rsp), %rax
cmpq %rax, %rdi
je 0x3d83b
callq 0x27560
movq %rbx, %rdi
callq 0x28c20
nop