// File: /workspace/github_cpp_makefile_star2_O2/schneebergerlab[P]GameteBinning/asPollinator_1.0.cpp
// Function: correct_haplotype3_with_pmClusterCnt(std::map<int, POLLEN, std::less<int>, std::allocator<std::pair<int const, POLLEN>>>, std::map<int, POLLEN, std::less<int>, std::allocator<std::pair<int const, POLLEN>>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>*)
bool correct_haplotype3_with_pmClusterCnt(map<int, POLLEN> maCluster,
                                          map<int, POLLEN> paCluster,
                                          string*          matGT,
                                          string*          patGT)
{
    // this is stage 3 correction: use 'P/M' counts in Paternal and Maternal clusters to correct point phasing    
    /*
        1) WITHOUT CORRECTION:    
             Paternal cluster at position i: P=50, M=02, u=200
             Maternal cluster at position i: P=03, M=45, u=250           
        2) WITH    CORRECTION:
             Paternal cluster at position i: P=02, M=50, u=200
             Maternal cluster at position i: P=45, M=03, u=250  
        
        struct CLUSCNT
        {
            int Pcnt;
            int Mcnt;
            int ucnt;
        };               
    */
    if((*patGT).size() != (*matGT).size() )
    {
        cout << "   Error: inconsistency in haplotype lengths. " << endl;
        return false;
    } 
    unsigned long markerNum = (*patGT).size();
    // 0. initialization on counts for two clusters
    map<int, CLUSCNT> maClusterCnt;
    map<int, CLUSCNT> paClusterCnt;        
    for(int ci = 0; ci < markerNum; ci ++)
    {
        CLUSCNT posCNT;
        posCNT.Pcnt = 0;
        posCNT.Mcnt = 0;
        posCNT.ucnt = 0;
        paClusterCnt.insert(std::pair<int, CLUSCNT>(ci, posCNT));
        maClusterCnt.insert(std::pair<int, CLUSCNT>(ci, posCNT));        
    }
    //
    map<int, POLLEN>::iterator ppitr;
    map<int, POLLEN>::iterator ppitr_end;
    map<int, CLUSCNT>::iterator cntitr;
    // 1. check maternal cluster attached to 0_m_mkr: matGT
    ppitr     = maCluster.begin();
    ppitr_end = maCluster.end();
    while(ppitr != ppitr_end)
    {
        POLLEN ptmp         = (*ppitr).second;
        string this_pattern = ptmp.poPat; // MMMMPPMMMMMMuM...MMMuMMMM
        // check P/M/u
        for(int ci = 0; ci < markerNum; ci ++)
        {
            // get "P" or "M" at current position
            string posPattern = this_pattern.substr(ci, 1);
            CLUSCNT posCNT;
            get_PM_count(posPattern, &posCNT);            
            // 
            cntitr = maClusterCnt.find(ci);
            // update
            (*cntitr).second.Pcnt += posCNT.Pcnt;
            (*cntitr).second.Mcnt += posCNT.Mcnt;
            (*cntitr).second.ucnt += posCNT.ucnt;
        }
        //
        ppitr ++;
    }
    // 2. check paternal cluster attached to 0_p_mkr: patGT
    ppitr     = paCluster.begin();
    ppitr_end = paCluster.end();
    while(ppitr != ppitr_end)
    {
        POLLEN ptmp         = (*ppitr).second;
        string this_pattern = ptmp.poPat; // PPPPMMPPPuPPPP...PPPPPuPP
        // check P/M/u
        for(int ci = 0; ci < markerNum; ci ++)
        {
            // get "P" or "M" at current position
            string posPattern = this_pattern.substr(ci, 1);
            CLUSCNT posCNT;
            get_PM_count(posPattern, &posCNT);            
            // 
            cntitr = paClusterCnt.find(ci);
            // update
            (*cntitr).second.Pcnt += posCNT.Pcnt;
            (*cntitr).second.Mcnt += posCNT.Mcnt;
            (*cntitr).second.ucnt += posCNT.ucnt;
        }
        //
        ppitr ++;
    }
    // 3. correct haplotypes according to counts
    for(int ci=0; ci<markerNum; ci ++)
    {
        // get counts on P/M in paternal cluster for current position
        map<int, CLUSCNT>::iterator pacitr = paClusterCnt.find(ci);
        assert(pacitr != paClusterCnt.end() );
        CLUSCNT paPosCNT = (*pacitr).second;
        // get counts on P/M in maternal cluster for current position
        map<int, CLUSCNT>::iterator macitr = maClusterCnt.find(ci);
        assert(macitr != maClusterCnt.end() );
        CLUSCNT maPosCNT = (*macitr).second;     
        // swap paternal/maternal haplotypes
        if( (paPosCNT.Pcnt<paPosCNT.Mcnt) && 
            (maPosCNT.Pcnt>maPosCNT.Mcnt)    )
        {
            string mattype = (*matGT).substr(ci, 1); // "P/M" at maternal pattern
            string pattype = (*patGT).substr(ci, 1); // "P/M" at paternal pattern
            (*matGT).replace(ci, 1, pattype);
            (*patGT).replace(ci, 1, mattype);
        }
    }  
    cout << "   Check: 3rd corrected haplotypes: " << endl
         << "\t"  << *matGT                        << endl
         << "\t"  << *patGT                        << endl;
    //    
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1a8, %rsp            # imm = 0x1A8
movq %rsi, 0x28(%rsp)
movq %rcx, 0x18(%rsp)
movq 0x8(%rcx), %rbx
movq %rdx, 0x20(%rsp)
movq 0x8(%rdx), %rax
movq %rax, 0x60(%rsp)
cmpq %rax, %rbx
jne 0xaf52
movq %rdi, %rbp
leaq 0xc8(%rsp), %rax
andl $0x0, (%rax)
andq $0x0, 0x8(%rax)
movq %rax, 0x10(%rax)
movq %rax, 0x18(%rax)
andq $0x0, 0x20(%rax)
leaq 0x98(%rsp), %rax
andl $0x0, (%rax)
andq $0x0, 0x8(%rax)
movq %rax, 0x10(%rax)
movq %rax, 0x18(%rax)
andq $0x0, 0x20(%rax)
xorl %r13d, %r13d
leaq 0x90(%rsp), %r12
leaq 0xf0(%rsp), %r14
leaq 0xc0(%rsp), %r15
cmpq %r13, %rbx
je 0xaf72
movl %r13d, 0xf0(%rsp)
andq $0x0, 0xf4(%rsp)
andl $0x0, 0xfc(%rsp)
movq %r12, %rdi
movq %r14, %rsi
callq 0x10f1e
movl %r13d, 0xf0(%rsp)
andq $0x0, 0xf4(%rsp)
andl $0x0, 0xfc(%rsp)
movq %r15, %rdi
movq %r14, %rsi
callq 0x10f1e
incq %r13
jmp 0xaf00
movq 0x1107f(%rip), %rdi     # 0x1bfd8
leaq 0x8cf3(%rip), %rsi      # 0x13c53
callq 0x3260
movq %rax, %rdi
callq 0x3140
jmp 0xb2e5
movq 0x18(%rbp), %rax
addq $0x8, %rbp
movq %rbp, 0x68(%rsp)
leaq 0x70(%rsp), %r14
leaq 0x40(%rsp), %r13
leaq 0x188(%rsp), %r12
leaq 0xc0(%rsp), %rbp
leaq 0xc(%rsp), %r15
cmpq 0x68(%rsp), %rax
je 0xb06f
movq %rax, 0x10(%rsp)
leaq 0x28(%rax), %rsi
leaq 0xf0(%rsp), %rdi
callq 0xe396
movq %r14, %rdi
leaq 0x130(%rsp), %rsi
callq 0x3300
xorl %eax, %eax
movl %eax, 0xc(%rsp)
movslq %eax, %rdx
cmpq %rdx, %rbx
jbe 0xb041
movq %r13, %rdi
movq %r14, %rsi
pushq $0x1
popq %rcx
callq 0x3290
movq %r12, %rdi
movq %r13, %rsi
callq 0x3300
movq %r12, %rdi
leaq 0x30(%rsp), %rsi
callq 0xdc9a
movq %r12, %rdi
callq 0x3120
movq %rbp, %rdi
movq %r15, %rsi
callq 0x110a8
movq 0x30(%rsp), %xmm0
movq 0x24(%rax), %xmm1
paddd %xmm0, %xmm1
movq %xmm1, 0x24(%rax)
movl 0x38(%rsp), %ecx
addl %ecx, 0x2c(%rax)
movq %r13, %rdi
callq 0x3120
movl 0xc(%rsp), %eax
incl %eax
jmp 0xafd1
movq 0x10(%rsp), %rdi
callq 0x31c0
movq %rax, 0x10(%rsp)
movq %r14, %rdi
callq 0x3120
leaq 0xf0(%rsp), %rdi
callq 0xe2b0
movq 0x10(%rsp), %rax
jmp 0xaf9e
movq 0x28(%rsp), %rax
movq 0x18(%rax), %rcx
addq $0x8, %rax
movq %rax, 0x28(%rsp)
leaq 0x70(%rsp), %r13
leaq 0x40(%rsp), %r15
leaq 0x168(%rsp), %r12
leaq 0x90(%rsp), %r14
leaq 0xc(%rsp), %rbp
cmpq 0x28(%rsp), %rcx
je 0xb171
movq %rcx, 0x10(%rsp)
leaq 0x28(%rcx), %rsi
leaq 0xf0(%rsp), %rdi
callq 0xe396
movq %r13, %rdi
leaq 0x130(%rsp), %rsi
callq 0x3300
xorl %eax, %eax
movl %eax, 0xc(%rsp)
movslq %eax, %rdx
cmpq %rdx, %rbx
jbe 0xb143
movq %r15, %rdi
movq %r13, %rsi
pushq $0x1
popq %rcx
callq 0x3290
movq %r12, %rdi
movq %r15, %rsi
callq 0x3300
movq %r12, %rdi
leaq 0x30(%rsp), %rsi
callq 0xdc9a
movq %r12, %rdi
callq 0x3120
movq %r14, %rdi
movq %rbp, %rsi
callq 0x110a8
movq 0x30(%rsp), %xmm0
movq 0x24(%rax), %xmm1
paddd %xmm0, %xmm1
movq %xmm1, 0x24(%rax)
movl 0x38(%rsp), %ecx
addl %ecx, 0x2c(%rax)
movq %r15, %rdi
callq 0x3120
movl 0xc(%rsp), %eax
incl %eax
jmp 0xb0d3
movq 0x10(%rsp), %rdi
callq 0x31c0
movq %rax, 0x10(%rsp)
movq %r13, %rdi
callq 0x3120
leaq 0xf0(%rsp), %rdi
callq 0xe2b0
movq 0x10(%rsp), %rcx
jmp 0xb0a0
xorl %eax, %eax
leaq 0xf0(%rsp), %r15
pushq $0x1
popq %r12
leaq 0x70(%rsp), %r14
movl %eax, 0x40(%rsp)
cltq
cmpq %rax, %rbx
jbe 0xb268
leaq 0x90(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x110a8
leaq 0x98(%rsp), %rcx
cmpq %rcx, %rax
je 0xb2ff
movq %r14, %r13
movq %r15, %r14
movl 0x24(%rax), %ebp
movl 0x28(%rax), %r15d
leaq 0xc0(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x110a8
leaq 0xc8(%rsp), %rcx
cmpq %rcx, %rax
je 0xb31e
cmpl %r15d, %ebp
movq %r14, %r15
movq %r13, %r14
jge 0xb25d
movl 0x24(%rax), %ecx
cmpl 0x28(%rax), %ecx
jle 0xb25d
movslq 0x40(%rsp), %rdx
movq %r15, %rdi
movq 0x20(%rsp), %rsi
movq %r12, %rcx
callq 0x3290
movslq 0x40(%rsp), %rdx
movq %r14, %rdi
movq 0x18(%rsp), %rsi
movq %r12, %rcx
callq 0x3290
movslq 0x40(%rsp), %rsi
movq 0x20(%rsp), %rdi
movq %r12, %rdx
movq %r14, %rcx
callq 0x30f0
movslq 0x40(%rsp), %rsi
movq 0x18(%rsp), %rdi
movq %r12, %rdx
movq %r15, %rcx
callq 0x30f0
movq %r14, %rdi
callq 0x3120
movq %r15, %rdi
callq 0x3120
movl 0x40(%rsp), %eax
incl %eax
jmp 0xb184
movq 0x10d69(%rip), %rdi     # 0x1bfd8
leaq 0x8aa8(%rip), %rsi      # 0x13d1e
callq 0x3260
movq %rax, %rdi
callq 0x3140
leaq 0x8c3c(%rip), %rsi      # 0x13ec6
movq %rax, %rdi
callq 0x3260
movq %rax, %rdi
movq 0x20(%rsp), %rsi
callq 0x3240
movq %rax, %rdi
callq 0x3140
leaq 0x8c18(%rip), %rsi      # 0x13ec6
movq %rax, %rdi
callq 0x3260
movq %rax, %rdi
movq 0x18(%rsp), %rsi
callq 0x3240
movq %rax, %rdi
callq 0x3140
leaq 0x90(%rsp), %rdi
callq 0xf6d0
leaq 0xc0(%rsp), %rdi
callq 0xf6d0
cmpq 0x60(%rsp), %rbx
sete %al
addq $0x1a8, %rsp            # imm = 0x1A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x897c(%rip), %rdi      # 0x13c82
leaq 0x87be(%rip), %rsi      # 0x13acb
leaq 0x898b(%rip), %rcx      # 0x13c9f
movl $0x6a5, %edx            # imm = 0x6A5
callq 0x3190
leaq 0x89dc(%rip), %rdi      # 0x13d01
leaq 0x879f(%rip), %rsi      # 0x13acb
leaq 0x896c(%rip), %rcx      # 0x13c9f
movl $0x6a9, %edx            # imm = 0x6A9
callq 0x3190
movq %rax, %rbx
jmp 0xb353
jmp 0xb373
jmp 0xb373
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x3120
leaq 0xf0(%rsp), %rdi
callq 0x3120
jmp 0xb3a9
jmp 0xb373
jmp 0xb373
jmp 0xb373
jmp 0xb36c
jmp 0xb373
movq %rax, %rbx
jmp 0xb39c
jmp 0xb373
movq %rax, %rbx
jmp 0xb3a9
jmp 0xb380
jmp 0xb380
jmp 0xb38f
jmp 0xb380
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x3120
jmp 0xb392
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x3120
leaq 0xf0(%rsp), %rdi
callq 0xe2b0
leaq 0x90(%rsp), %rdi
callq 0xf6d0
leaq 0xc0(%rsp), %rdi
callq 0xf6d0
movq %rbx, %rdi
callq 0x3410