// File: /workspace/github_cpp_makefile_star2_O2/chhylp123[P]hifiasm/Hash_Table.cpp
// Function: chain_DP(k_mer_hit*, long long, Chain_Data*, overlap_region*, double, int, int, int, void*)
long long chain_DP(k_mer_hit* a, long long a_n, Chain_Data* dp, overlap_region* result, 
              double band_width_threshold, int max_skip, int x_readLen, int y_readLen, void *km)
{
    long long i, j;
    long long self_pos, pos, max_j, max_i, max_score, score;
    long long distance_pos, distance_self_pos, distance_gap,  distance_min;
    ///double band_width_threshold = 0.05;
    double band_width_penalty = 1 / band_width_threshold;
    long long min_score = asm_opt.k_mer_length;
    long long max_indels, max_self_length;
    double gap_rate;
    long long total_indels, total_self_length;
	int32_t ret;
    
    resize_Chain_Data(dp, a_n, km);

	ret = ha_chain_check(a, a_n, dp, min_score, band_width_threshold);
	if (ret > 0) {
		a_n = ret;
		goto skip_dp;
	}

    // fill the score and backtrack arrays
	for (i = 0; i < a_n; ++i) dp->tmp[i] = -1;
	for (i = 0; i < a_n; ++i) 
    {
		int n_chn_skip = 0;
		int n_max_skip = 0;

        pos = a[i].offset;
        self_pos = a[i].self_offset;
        max_j = -1;
        max_score = normal_w(min_score, (int64_t)a[i].cnt);
        max_indels = 0;
        max_self_length = 0;

        ///may have a pre-cut condition for j
        for (j = i - 1; j >= 0; --j) 
        {
            distance_pos = pos - a[j].offset;
            distance_self_pos = self_pos - a[j].self_offset;
            ///a has been sorted by a[].offset
            ///note for a, we do not have any two elements that have both equal offsets and self_offsets
            ///but there maybe two elements that have equal offsets or equal self_offsets
            if(distance_pos == 0 || distance_self_pos <= 0)
            {
                continue;
            }

            distance_gap = distance_pos > distance_self_pos? distance_pos - distance_self_pos : distance_self_pos - distance_pos;
            
            total_indels = dp->indels[j] + distance_gap;
            total_self_length = dp->self_length[j] + distance_self_pos;
            if(total_indels > band_width_threshold * total_self_length)
            {
                continue;
            }

            ///min distance
            distance_min = distance_pos < distance_self_pos? distance_pos:distance_self_pos;
            score = distance_min < min_score? distance_min : min_score;
            ///need to be fixed in r305
			///if (!a[j].good) score = (score >> 1) + (score & 1);
            score = normal_w(score, (int64_t)a[j].cnt);

            gap_rate = (double)((double)(total_indels)/(double)(total_self_length));
            ///if the gap rate > 0.06, score will be negative
            score -= (long long)(gap_rate * score * band_width_penalty);

            score += dp->score[j];

			///find a new max score
			if (score > max_score) {///must use > instead of >=
				max_score = score;
				max_j = j;
				max_indels = total_indels;
				max_self_length = total_self_length;
				n_max_skip = 0;
				if (n_chn_skip > 0) --n_chn_skip;
			} else {
				if (++n_max_skip > max_skip)
					break;
				if (dp->tmp[j] == i) {
					if (++n_chn_skip > max_skip)
						break;
				}
			}
			if (dp->pre[j] >= 0) dp->tmp[dp->pre[j]] = i;
        }

        dp->score[i] = max_score;
        dp->pre[i] = max_j;
        dp->indels[i] = max_indels;
        dp->self_length[i] = max_self_length;
        dp->occ[i] = 1;
        if(max_j != -1) dp->occ[i] = dp->occ[max_j] + 1;
    }

    ///debug_chain(a, a_n, dp);
    // if((*result).x_id == 2162668 && (*result).y_id == 182804) print_chain(a, a_n, dp, 10);
    
skip_dp:

    max_score = -1;
    max_i = -1;
    long long mini_xLen = x_readLen * 2 + 2, tmp_xLen;
    for (i = 0; i < a_n; ++i) 
    {
        if(dp->score[i] > max_score)
        {
            max_score = dp->score[i];
            max_i = i;
            mini_xLen = get_chainLen(a[i].self_offset, a[i].self_offset, x_readLen, 
                                     a[i].offset, a[i].offset, y_readLen);
        }
        else if(dp->score[i] == max_score)
        {
            tmp_xLen = get_chainLen(a[i].self_offset, a[i].self_offset, x_readLen, 
                                    a[i].offset, a[i].offset, y_readLen);

            if(tmp_xLen < mini_xLen)
            {
                max_score = dp->score[i];
                max_i = i;

                mini_xLen = tmp_xLen;
            }
        }
        
    }

    clear_fake_cigar(&(result->f_cigar));
    ///note a has been sorted by offset, that means has been sorted by query offset
    i = max_i;
    result->x_pos_e = a[i].self_offset;
    result->y_pos_e = a[i].offset;
    result->shared_seed = max_score;
    result->overlapLen = mini_xLen;

    distance_self_pos = result->x_pos_e - a[i].self_offset;
    distance_pos = result->y_pos_e - a[i].offset;
    long long pre_distance_gap = distance_pos - distance_self_pos;
    ///record first site
    ///the length of f_cigar should be at least 1
    ///record the offset of reference
    add_fake_cigar(&(result->f_cigar), a[i].self_offset, pre_distance_gap, km);
    long long chainLen = 0;
    if(result->x_pos_strand == 1)
    {
        while (i >= 0)
        {
            distance_self_pos = result->x_pos_e - a[i].self_offset;
            distance_pos = result->y_pos_e - a[i].offset;
            distance_gap = distance_pos - distance_self_pos;
            if(distance_gap != pre_distance_gap)
            {
                pre_distance_gap = distance_gap;
                ///record this site
                add_fake_cigar(&(result->f_cigar), a[i].self_offset, pre_distance_gap, km);
            }

            chainLen++;
            result->x_pos_s = a[i].self_offset;
            result->y_pos_s = a[i].offset;
            i = dp->pre[i];
        }
    }
    else
    {
        while (i >= 0)
        {
            distance_self_pos = result->x_pos_e - a[i].self_offset;
            distance_pos = result->y_pos_e - a[i].offset;
            distance_gap = distance_pos - distance_self_pos;
            if(distance_gap == pre_distance_gap)
            {
                result->f_cigar.length--;
                add_fake_cigar(&(result->f_cigar), a[i].self_offset, pre_distance_gap, km);
            }
            else
            {
                pre_distance_gap = distance_gap;
                add_fake_cigar(&(result->f_cigar), a[i].self_offset, pre_distance_gap, km);
            }

            chainLen++;
            result->x_pos_s = a[i].self_offset;
            result->y_pos_s = a[i].offset;
            i = dp->pre[i];
        }
    }
    return chainLen;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %r9, 0x58(%rsp)
movl %r8d, %ebp
movsd %xmm0, 0x48(%rsp)
movq %rcx, 0x18(%rsp)
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %rbx
movq 0xa8(%rsp), %rdx
leaq 0x2403cf(%rip), %rax    # 0x253758
movl 0x80(%rax), %r12d
movq %r14, %rdi
callq 0x1383e
movq %rbx, 0x10(%rsp)
movq %rbx, %rdi
movl %r15d, %esi
movq %r14, %rdx
movl %r12d, %ecx
movsd 0x48(%rsp), %xmm0
callq 0x131d8
testl %eax, %eax
jle 0x135e1
movl %eax, %esi
movq 0x18(%rsp), %r12
movq 0x10(%rsp), %rdx
movq 0x58(%rsp), %rcx
leal 0x2(,%rcx,2), %eax
movslq %eax, %r13
movslq %ecx, %rax
movq %rax, 0x28(%rsp)
movslq 0xa0(%rsp), %rax
movq %rax, 0x30(%rsp)
leaq 0x8(%rdx), %rbp
pushq $-0x1
popq %rbx
xorl %r15d, %r15d
movq %rbx, %r8
movq %rsi, 0x38(%rsp)
cmpq %r15, %rsi
je 0x1348f
movq (%r14), %rax
movslq (%rax,%r15,4), %r12
cmpq %r12, %rbx
jge 0x13440
movl -0x4(%rbp), %ecx
movl (%rbp), %edi
movq %rdi, %rsi
movq 0x28(%rsp), %rdx
movq %rcx, %r8
movq 0x30(%rsp), %r9
callq 0x12ff0
movq 0x38(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %rax, %r13
movq %r15, %r8
jmp 0x1347b
jne 0x13478
movl -0x4(%rbp), %ecx
movl (%rbp), %edi
movq %rdi, %rsi
movq 0x28(%rsp), %rdx
movq %r8, %r12
movq %rcx, %r8
movq 0x30(%rsp), %r9
callq 0x12ff0
movq %r12, %r8
movq 0x38(%rsp), %rsi
movq 0x10(%rsp), %rdx
cmpq %r13, %rax
cmovlq %r15, %r8
cmovlq %rax, %r13
movq %rbx, %r12
incq %r15
addq $0x10, %rbp
movq %r12, %rbx
movq 0x18(%rsp), %r12
jmp 0x133fe
leaq 0x38(%r12), %rdi
andl $0x0, 0x40(%r12)
movq %r8, %r15
movq %r8, %rax
shlq $0x4, %rax
movl 0x8(%rdx,%rax), %esi
movl %esi, 0x8(%r12)
movl 0x4(%rdx,%rax), %eax
movl %eax, 0x18(%r12)
movl %ebx, 0x24(%r12)
movl %r13d, 0x20(%r12)
movq %rdi, 0x18(%rsp)
xorl %edx, %edx
movq 0xa8(%rsp), %rcx
callq 0x11af6
cmpl $0x1, 0xc(%r12)
jne 0x1355a
xorl %eax, %eax
xorl %ebp, %ebp
movq 0x10(%rsp), %rdi
movq %r15, %r8
testq %r8, %r8
js 0x135cf
movq %r8, %rbx
shlq $0x4, %rbx
movl 0x4(%rdi,%rbx), %ecx
movl 0x8(%rdi,%rbx), %esi
movl 0x8(%r12), %edx
movl 0x18(%r12), %r13d
subl %esi, %edx
subl %ecx, %r13d
subq %rdx, %r13
cmpq %rax, %r13
je 0x13543
addq %rdi, %rbx
movq 0x18(%rsp), %rdi
movl %r13d, %edx
movq 0xa8(%rsp), %rcx
movq %r8, %r15
callq 0x11af6
movq %r15, %r8
movq 0x10(%rsp), %rdi
movl 0x4(%rbx), %ecx
movl 0x8(%rbx), %esi
movq %r13, %rax
incq %rbp
movl %esi, 0x4(%r12)
movl %ecx, 0x14(%r12)
movq 0x8(%r14), %rcx
movq (%rcx,%r8,8), %r8
jmp 0x134e8
xorl %eax, %eax
xorl %ebp, %ebp
movq %r15, %rbx
testq %rbx, %rbx
movq 0x10(%rsp), %rdx
js 0x135cf
movq %rbx, %r15
shlq $0x4, %rbx
movl 0x8(%rdx,%rbx), %esi
movl 0x8(%r12), %ecx
movl 0x18(%r12), %r13d
subl %esi, %ecx
subl 0x4(%rdx,%rbx), %r13d
subq %rcx, %r13
cmpq %rax, %r13
jne 0x13597
decl 0x40(%r12)
movq %rax, %r13
addq %rdx, %rbx
movq 0x18(%rsp), %rdi
movl %r13d, %edx
movq 0xa8(%rsp), %rcx
callq 0x11af6
incq %rbp
movl 0x8(%rbx), %eax
movl %eax, 0x4(%r12)
movl 0x4(%rbx), %eax
movl %eax, 0x14(%r12)
movq 0x8(%r14), %rax
movq (%rax,%r15,8), %rbx
movq %r13, %rax
jmp 0x13561
movq %rbp, %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x1cfcb7(%rip), %xmm0   # 0x1e32a0
movsd 0x48(%rsp), %xmm4
divsd %xmm4, %xmm0
movslq %r12d, %rax
movq %rax, 0x40(%rsp)
xorl %eax, %eax
testq %r15, %r15
cmovleq %rax, %r15
movq 0x18(%rsp), %r12
movq 0x10(%rsp), %rdx
movq %r15, %rsi
cmpq %rax, %rsi
je 0x13624
movq 0x28(%r14), %rcx
orq $-0x1, (%rcx,%rax,8)
incq %rax
jmp 0x13611
leaq -0x4(%rdx), %rax
movq %rax, 0x60(%rsp)
xorl %r9d, %r9d
movq %rsi, 0x38(%rsp)
cmpq %rsi, %r9
je 0x133c8
movq %r9, %rax
shlq $0x4, %rax
movl 0x4(%rdx,%rax), %r11d
movl 0x8(%rdx,%rax), %r12d
movl 0xc(%rdx,%rax), %ecx
pushq $0x1
popq %rax
cmpq %rcx, 0x40(%rsp)
jl 0x13667
movq 0x40(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, 0x28(%rsp)
movq $0x0, 0x30(%rsp)
movq $0x0, 0x50(%rsp)
pushq $-0x1
popq %r15
movq %r9, %rax
movl $0x0, 0xc(%rsp)
movl $0x0, 0x24(%rsp)
movq %rax, %rdx
shlq $0x4, %rdx
addq 0x60(%rsp), %rdx
movq %rax, %r8
testq %r8, %r8
jle 0x137dd
movl %ebp, %edi
movl -0x8(%rdx), %ecx
cmpl %ecx, %r11d
je 0x1370b
movl -0x4(%rdx), %esi
movq %r12, %rax
subq %rsi, %rax
testq %rax, %rax
jle 0x1370b
movq %r11, %rbx
subq %rcx, %rbx
movq %rbx, %rcx
subq %rax, %rcx
movq %rcx, %rsi
negq %rsi
cmovsq %rcx, %rsi
movq 0x10(%r14), %rcx
movq 0x18(%r14), %r10
movslq -0x4(%rcx,%r8,4), %r13
addq %rsi, %r13
movslq -0x4(%r10,%r8,4), %rbp
addq %rax, %rbp
cvtsi2sd %r13, %xmm1
cvtsi2sd %rbp, %xmm2
movapd %xmm2, %xmm3
mulsd %xmm4, %xmm3
ucomisd %xmm3, %xmm1
jbe 0x13716
addq $-0x10, %rdx
decq %r8
movl %edi, %ebp
jmp 0x136a4
cmpq %rax, %rbx
cmovlq %rbx, %rax
movq 0x40(%rsp), %rsi
cmpq %rsi, %rax
cmovgeq %rsi, %rax
movl (%rdx), %esi
pushq $0x1
popq %rdx
cmpq %rsi, %rax
jl 0x1373b
xorl %edx, %edx
divq %rsi
movq %rax, %rdx
leaq -0x1(%r8), %rax
divsd %xmm2, %xmm1
cvtsi2sd %rdx, %xmm2
mulsd %xmm1, %xmm2
mulsd %xmm0, %xmm2
cvttsd2si %xmm2, %rsi
subq %rsi, %rdx
movq (%r14), %rbx
movslq -0x4(%rbx,%r8,4), %rsi
addq %rdx, %rsi
cmpq 0x28(%rsp), %rsi
jle 0x13799
xorl %ecx, %ecx
movl 0xc(%rsp), %edx
testl %edx, %edx
setg %cl
subl %ecx, %edx
movl %edx, 0xc(%rsp)
movl $0x0, 0x24(%rsp)
movq %rsi, 0x28(%rsp)
movq %r13, 0x30(%rsp)
movq %rbp, 0x50(%rsp)
movq %rax, %r15
movl %edi, %ebp
jmp 0x137be
movl %edi, %ebp
movl 0x24(%rsp), %edx
cmpl %edi, %edx
jge 0x137e8
incl %edx
movl %edx, 0x24(%rsp)
movq 0x28(%r14), %rdx
cmpq %r9, -0x8(%rdx,%r8,8)
jne 0x137be
cmpl %ebp, 0xc(%rsp)
jge 0x137e8
incl 0xc(%rsp)
movq 0x8(%r14), %rcx
movq -0x8(%rcx,%r8,8), %rcx
testq %rcx, %rcx
js 0x13695
movq 0x28(%r14), %rdx
movq %r9, (%rdx,%rcx,8)
jmp 0x13695
movq (%r14), %rbx
movq 0x10(%r14), %rcx
movq 0x18(%r14), %r10
movq 0x28(%rsp), %rax
movl %eax, (%rbx,%r9,4)
movq 0x8(%r14), %rax
movq %r15, (%rax,%r9,8)
movq 0x30(%rsp), %rax
movl %eax, (%rcx,%r9,4)
movq 0x50(%rsp), %rax
movl %eax, (%r10,%r9,4)
movq 0x20(%r14), %rax
movl $0x1, (%rax,%r9,4)
cmpq $-0x1, %r15
movq 0x18(%rsp), %r12
je 0x1382c
movl (%rax,%r15,4), %ecx
incl %ecx
movl %ecx, (%rax,%r9,4)
incq %r9
movq 0x10(%rsp), %rdx
movq 0x38(%rsp), %rsi
jmp 0x13635