// File: medvedevgroup[P]varmatch/src/wholegenome.cpp
// Function: WholeGenome::MatchingSingleClusterBaseExtending(int, int, std::vector<DiploidVariant, std::allocator<DiploidVariant>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, int, std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>**, std::vector<int, std::allocator<int>>&, int, int, int, int, int)
bool WholeGenome::MatchingSingleClusterBaseExtending(int cluster_index,
                                                    int thread_index,
                                                    vector<DiploidVariant> & variant_list,
                                                    string & subsequence,
                                                    int offset,
                                                    multimap<int, int> * choices_by_pos[],
                                                    vector<int> & sync_points,
                                                    int chr_id,
                                                    int score_unit,
                                                    int match_mode,
                                                    int score_scheme,
                                                    int threshold_index){
    //--------------for unit test------------------------------
    //dout << variant_list.size() << endl;

    //int chr_id = 0;
    //-------------end unit test-------------------------------

    //cout << chr_id << "," << cluster_index << "," << variant_list.size() << endl;

    // so a legal sync_points vector contains at least two
    // first is the end of variant, there should be at least one variant
    // second is the end of subsequence, there should be at least one nt not influenced by a variant

    list<SequencePath> current_path_list;
    list<SequencePath> next_path_list;
    SequencePath sp(subsequence.length(), variant_list.size());
    SequencePath best_path = sp;
    current_path_list.push_back(sp);
    int considered_path_num = 0;
    int mode_index = GetIndexFromMatchScore(score_unit, match_mode, score_scheme);
    while(current_path_list.size() != 0){
        bool reach_sync_point = true;
        // extend path before reaches sync points
        //cout << "\t" << current_path_list.size() << "," << considered_path_num << endl;
        
        while(current_path_list.size() != 0){
            SequencePath path = current_path_list.front();
            current_path_list.pop_front();
            considered_path_num ++;
            if (considered_path_num >= MAX_SEARCH_SPACE){
                //cout << "direct matching large variant cluster" << endl;
                //cout << variant_list.size() << "," << considered_path_num << endl;
                return MatchingSingleClusterDirectly(cluster_index, 
                    thread_index, 
                    mode_index, 
                    threshold_index, 
                    chr_id,
                    variant_list);
            }
            //dout << path.current_genome_pos << ":" << current_path_list.size() << endl;
            //PrintPath(path);
            int variant_need_decision = -1;
            int is_extend = PathExtendOneStep(path, choices_by_pos, subsequence, sync_points, match_mode, variant_need_decision);
            //cout << variant_need_decision << endl;
            //PrintPath(path);
            if(is_extend == -1){
                // discard path
                continue;
            }
            else if(is_extend == 0){
                next_path_list.push_back(path);
                // here the path is supposed to reach the next sync point
                // so it goes into next path list, and decrease the number of current path list
            }else if(is_extend == 1){
                if(match_mode == 0){
                    // PathMakeDecision(path,
                    //                  variant_list,
                    //                  choices_by_pos,
                    //                  current_path_list,
                    //                  subsequence,
                    //                  score_unit,
                    //                  match_mode,
                    //                  score_scheme);

                    VariantMakeDecision(path,
                                         variant_list,
                                         current_path_list,
                                         subsequence,
                                         score_unit,
                                         match_mode,
                                         score_scheme,
                                         variant_need_decision);
                }else{
                    // PathMakeDecisionNoGenotype(path,
                    //                            variant_list,
                    //                            choices_by_pos,
                    //                            current_path_list,
                    //                            subsequence,
                    //                            score_unit,
                    //                            match_mode,
                    //                            score_scheme);

                    VariantMakeDecisionNoGenotype(path,
                                                 variant_list,
                                                 current_path_list,
                                                 subsequence,
                                                 score_unit,
                                                 match_mode,
                                                 score_scheme,
                                                 variant_need_decision);
                }
            }else if(is_extend == 2){
                if(path.score > best_path.score){
                    best_path = path; // only when you reach the very end can you be considered as best path
                    //PrintPath(best_path);
                }
            }
        }
        current_path_list = next_path_list;
        next_path_list.clear();
        if(current_path_list.size() > 0){
            //int current_genome_pos = current_path_list.front().current_genome_pos;
            // after revise, we do not need this check
            //if(sync_points.find(current_genome_pos) != sync_points.end()){
                //dout << "converge paths at position: " << current_genome_pos << endl;
                //dout << "before converge: " << current_path_list.size() << endl;
                ConvergePaths(current_path_list);
                //dout << "after converge: " << current_path_list.size() << endl;
            //}
        }
    }
    current_path_list.clear();
    next_path_list.clear();
    // print best_path
    if(best_path.score <= 0) return false;
    // if(considered_path_num > max_path_num_by_mode_by_thread[thread_index][mode_index]){
    //     max_path_num_by_mode_by_thread[thread_index][mode_index] = considered_path_num;
    // }
    //dout << "new method: " << best_path.score << endl;

    //PrintPath(best_path);

    //==========================output ======================

    //return true;
    if(match_mode == 0){
        ConstructMatchRecord(best_path,
                             variant_list,
                             subsequence,
                             offset,
                             thread_index,
                             chr_id,
                             mode_index,
                             threshold_index);
    }else{
        ConstructMatchRecordNoGenotype(best_path,
                                       variant_list,
                                       subsequence,
                                       offset,
                                       thread_index,
                                       chr_id,
                                       mode_index,
                                       threshold_index);
    }
    return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x540, %rsp            # imm = 0x540
movl 0x40(%rbp), %eax
movl 0x38(%rbp), %eax
movl 0x30(%rbp), %eax
movl 0x28(%rbp), %eax
movl 0x20(%rbp), %eax
movq 0x18(%rbp), %rax
movq 0x10(%rbp), %rax
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movl %r9d, -0x2c(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x518(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x35150
leaq -0x60(%rbp), %rdi
callq 0x35150
movq -0x28(%rbp), %rdi
callq 0x6630
movl %eax, -0x510(%rbp)
movq -0x20(%rbp), %rdi
callq 0x335b0
movl -0x510(%rbp), %esi
movl %eax, %edx
leaq -0x1e0(%rbp), %rdi
callq 0x35170
jmp 0x20c73
leaq -0x370(%rbp), %rdi
leaq -0x1e0(%rbp), %rsi
callq 0x34b20
jmp 0x20c88
leaq -0x48(%rbp), %rdi
leaq -0x1e0(%rbp), %rsi
callq 0x34fe0
jmp 0x20c9a
movq -0x518(%rbp), %rdi
movl $0x0, -0x374(%rbp)
movl 0x28(%rbp), %esi
movl 0x30(%rbp), %edx
movl 0x38(%rbp), %ecx
callq 0x35500
movl %eax, -0x51c(%rbp)
jmp 0x20cc1
movl -0x51c(%rbp), %eax
movl %eax, -0x378(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x35560
cmpq $0x0, %rax
je 0x20fc2
movb $0x1, -0x379(%rbp)
leaq -0x48(%rbp), %rdi
callq 0x35560
cmpq $0x0, %rax
je 0x20f82
leaq -0x48(%rbp), %rdi
callq 0x35590
movq %rax, %rsi
leaq -0x500(%rbp), %rdi
callq 0x34b20
jmp 0x20d14
leaq -0x48(%rbp), %rdi
callq 0x355c0
movl -0x374(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x374(%rbp)
cmpl $0x7530, -0x374(%rbp)   # imm = 0x7530
jl 0x20df0
movq -0x518(%rbp), %rdi
movl -0x14(%rbp), %esi
movl -0x18(%rbp), %edx
movl -0x378(%rbp), %ecx
movl 0x40(%rbp), %r8d
movl 0x20(%rbp), %r9d
movq -0x20(%rbp), %r10
movq %rsp, %rax
movq %r10, (%rax)
callq 0x27770
movb %al, -0x51d(%rbp)
jmp 0x20d6e
movb -0x51d(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
movl $0x1, -0x504(%rbp)
jmp 0x20f4b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1e8(%rbp)
movl %eax, -0x1ec(%rbp)
jmp 0x210d8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1e8(%rbp)
movl %eax, -0x1ec(%rbp)
jmp 0x210cc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1e8(%rbp)
movl %eax, -0x1ec(%rbp)
jmp 0x210c0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x1e8(%rbp)
movl %eax, -0x1ec(%rbp)
leaq -0x500(%rbp), %rdi
callq 0x35020
jmp 0x210c0
movq -0x518(%rbp), %rdi
movl $0xffffffff, -0x508(%rbp) # imm = 0xFFFFFFFF
movq 0x10(%rbp), %rdx
movq -0x28(%rbp), %rcx
movq 0x18(%rbp), %r8
movl 0x30(%rbp), %r9d
movq %rsp, %rax
leaq -0x508(%rbp), %rsi
movq %rsi, (%rax)
leaq -0x500(%rbp), %rsi
callq 0x21d30
movl %eax, -0x524(%rbp)
jmp 0x20e32
movl -0x524(%rbp), %eax
movl %eax, -0x50c(%rbp)
cmpl $-0x1, -0x50c(%rbp)
jne 0x20e56
movl $0x4, -0x504(%rbp)
jmp 0x20f4b
cmpl $0x0, -0x50c(%rbp)
jne 0x20e76
leaq -0x60(%rbp), %rdi
leaq -0x500(%rbp), %rsi
callq 0x34fe0
jmp 0x20e71
jmp 0x20f3f
cmpl $0x1, -0x50c(%rbp)
jne 0x20f0b
cmpl $0x0, 0x30(%rbp)
jne 0x20ec9
movq -0x518(%rbp), %rdi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %r8
movl 0x28(%rbp), %r9d
movl 0x30(%rbp), %ecx
movl 0x38(%rbp), %esi
movl -0x508(%rbp), %r10d
movq %rsp, %rax
movl %r10d, 0x10(%rax)
movl %esi, 0x8(%rax)
movl %ecx, (%rax)
leaq -0x500(%rbp), %rsi
leaq -0x48(%rbp), %rcx
callq 0x23f30
jmp 0x20ec7
jmp 0x20f09
movq -0x518(%rbp), %rdi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %r8
movl 0x28(%rbp), %r9d
movl 0x30(%rbp), %ecx
movl 0x38(%rbp), %esi
movl -0x508(%rbp), %r10d
movq %rsp, %rax
movl %r10d, 0x10(%rax)
movl %esi, 0x8(%rax)
movl %ecx, (%rax)
leaq -0x500(%rbp), %rsi
leaq -0x48(%rbp), %rcx
callq 0x24ab0
jmp 0x20f07
jmp 0x20f09
jmp 0x20f3d
cmpl $0x2, -0x50c(%rbp)
jne 0x20f3b
movl -0x3a8(%rbp), %eax
cmpl -0x218(%rbp), %eax
jle 0x20f39
leaq -0x370(%rbp), %rdi
leaq -0x500(%rbp), %rsi
callq 0x355f0
jmp 0x20f37
jmp 0x20f39
jmp 0x20f3b
jmp 0x20f3d
jmp 0x20f3f
jmp 0x20f41
movl $0x0, -0x504(%rbp)
leaq -0x500(%rbp), %rdi
callq 0x35020
movl -0x504(%rbp), %eax
movl %eax, -0x528(%rbp)
testl %eax, %eax
je 0x20f7d
jmp 0x20f69
movl -0x528(%rbp), %eax
subl $0x4, %eax
je 0x20ce7
jmp 0x21088
jmp 0x20ce7
leaq -0x48(%rbp), %rdi
leaq -0x60(%rbp), %rsi
callq 0x35750
jmp 0x20f91
leaq -0x60(%rbp), %rdi
callq 0x357b0
leaq -0x48(%rbp), %rdi
callq 0x35560
cmpq $0x0, %rax
jbe 0x20fbd
movq -0x518(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x283c0
jmp 0x20fbb
jmp 0x20fbd
jmp 0x20ccd
leaq -0x48(%rbp), %rdi
callq 0x357b0
leaq -0x60(%rbp), %rdi
callq 0x357b0
cmpl $0x0, -0x218(%rbp)
jg 0x20ff0
movb $0x0, -0x1(%rbp)
movl $0x1, -0x504(%rbp)
jmp 0x21088
cmpl $0x0, 0x30(%rbp)
jne 0x21038
movq -0x518(%rbp), %rdi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %rcx
movl -0x2c(%rbp), %r8d
movl -0x18(%rbp), %r9d
movl 0x20(%rbp), %esi
movl -0x378(%rbp), %r10d
movl 0x40(%rbp), %r11d
movq %rsp, %rax
movl %r11d, 0x10(%rax)
movl %r10d, 0x8(%rax)
movl %esi, (%rax)
leaq -0x370(%rbp), %rsi
callq 0x28620
jmp 0x21036
jmp 0x2107a
movq -0x518(%rbp), %rdi
movq -0x20(%rbp), %rdx
movq -0x28(%rbp), %rcx
movl -0x2c(%rbp), %r8d
movl -0x18(%rbp), %r9d
movl 0x20(%rbp), %esi
movl -0x378(%rbp), %r10d
movl 0x40(%rbp), %r11d
movq %rsp, %rax
movl %r11d, 0x10(%rax)
movl %r10d, 0x8(%rax)
movl %esi, (%rax)
leaq -0x370(%rbp), %rsi
callq 0x29740
jmp 0x21078
jmp 0x2107a
movb $0x1, -0x1(%rbp)
movl $0x1, -0x504(%rbp)
leaq -0x370(%rbp), %rdi
callq 0x35020
leaq -0x1e0(%rbp), %rdi
callq 0x35020
leaq -0x60(%rbp), %rdi
callq 0x357e0
leaq -0x48(%rbp), %rdi
callq 0x357e0
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x540, %rsp            # imm = 0x540
popq %rbp
retq
leaq -0x370(%rbp), %rdi
callq 0x35020
leaq -0x1e0(%rbp), %rdi
callq 0x35020
leaq -0x60(%rbp), %rdi
callq 0x357e0
leaq -0x48(%rbp), %rdi
callq 0x357e0
movq -0x1e8(%rbp), %rdi
callq 0x6750
nopw %cs:(%rax,%rax)