// File: /workspace/github_cpp_makefile_star2_O3/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 $0x88, %rsp
movl %r9d, %r13d
movl %r8d, %ebp
movsd %xmm0, 0x18(%rsp)
movq %rcx, 0x20(%rsp)
movq %rdx, %rbx
movq %rsi, %r15
movq %rdi, %r14
movq 0xc8(%rsp), %rdx
leaq 0x257036(%rip), %rax    # 0x295758
movl 0x80(%rax), %r12d
movq %rbx, %rdi
callq 0x3ecb0
movq %r14, (%rsp)
movq %r14, %rdi
movl %r15d, %esi
movq %rbx, 0x8(%rsp)
movq %rbx, %rdx
movl %r12d, %ecx
movsd 0x18(%rsp), %xmm0
callq 0x3e545
testl %eax, %eax
jle 0x3e761
movl %eax, %r10d
movq (%rsp), %r8
jmp 0x3ea54
movsd 0x18(%rsp), %xmm0
movl %ebp, 0x4c(%rsp)
testq %r15, %r15
jle 0x3ec96
movq %r13, 0x68(%rsp)
movsd 0x1f2b8f(%rip), %xmm1   # 0x231310
divsd %xmm0, %xmm1
movsd %xmm1, 0x60(%rsp)
movslq %r12d, %rax
movq %rax, 0x38(%rsp)
movq 0x8(%rsp), %rbx
movq 0x28(%rbx), %rdi
leaq (,%r15,8), %rdx
movl $0xff, %esi
movq %r15, 0x50(%rsp)
callq 0x20e0
movsd 0x60(%rsp), %xmm4
movsd 0x18(%rsp), %xmm3
movq 0x50(%rsp), %r10
movq (%rbx), %rax
movq %rax, 0x30(%rsp)
movq 0x8(%rbx), %rax
movq %rax, 0x28(%rsp)
movq 0x10(%rbx), %rax
movq %rax, 0x10(%rsp)
movq 0x18(%rbx), %rax
movq %rax, 0x40(%rsp)
movq 0x20(%rbx), %r9
movq (%rsp), %r8
leaq -0x4(%r8), %r11
movl $0x1, %r15d
xorl %ebp, %ebp
movq %r9, 0x70(%rsp)
movq %rbp, %rax
shlq $0x4, %rax
movl 0x4(%r8,%rax), %r14d
movl 0x8(%r8,%rax), %edi
movl 0xc(%r8,%rax), %esi
movl $0x1, %ecx
cmpq %rsi, 0x38(%rsp)
jl 0x3e82f
movq 0x38(%rsp), %rax
xorl %edx, %edx
divq %rsi
movq %rax, %rcx
testq %rbp, %rbp
je 0x3e9a7
movq $-0x1, 0x58(%rsp)
xorl %ebx, %ebx
movq %r11, 0x80(%rsp)
movq %r15, 0x78(%rsp)
movq %r15, %r10
xorl %r15d, %r15d
xorl %r13d, %r13d
xorl %esi, %esi
movl -0x8(%r11), %r8d
cmpl %r8d, %r14d
je 0x3e8c1
movl -0x4(%r11), %edx
movq %rdi, %rax
subq %rdx, %rax
testq %rax, %rax
jle 0x3e8c1
movq %r14, %rdx
subq %r8, %rdx
movq %rdx, %r8
subq %rax, %r8
movq %r8, %r12
negq %r12
cmovsq %r8, %r12
movq 0x10(%rsp), %r8
movslq -0x8(%r8,%r10,4), %r9
addq %r12, %r9
movq 0x40(%rsp), %r8
movslq -0x8(%r8,%r10,4), %r8
addq %rax, %r8
xorps %xmm0, %xmm0
cvtsi2sd %r9, %xmm0
xorps %xmm1, %xmm1
cvtsi2sd %r8, %xmm1
movapd %xmm1, %xmm2
mulsd %xmm3, %xmm2
ucomisd %xmm2, %xmm0
jbe 0x3e8e9
movq %rcx, %rax
movq %rsi, %r9
movq %r13, %r8
decq %r10
addq $-0x10, %r11
movq %r8, %r13
movq %r9, %rsi
movq %rax, %rcx
cmpq $0x1, %r10
jg 0x3e85b
jmp 0x3e9e1
cmpq %rax, %rdx
cmovlq %rdx, %rax
movq 0x38(%rsp), %rdx
cmpq %rdx, %rax
cmovgeq %rdx, %rax
movl (%r11), %r12d
movl $0x1, %edx
cmpq %r12, %rax
jl 0x3e911
xorl %edx, %edx
divq %r12
movq %rax, %rdx
divsd %xmm1, %xmm0
xorps %xmm1, %xmm1
cvtsi2sd %rdx, %xmm1
mulsd %xmm0, %xmm1
mulsd %xmm4, %xmm1
cvttsd2si %xmm1, %rax
subq %rax, %rdx
movq 0x30(%rsp), %rax
movslq -0x8(%rax,%r10,4), %rax
addq %rdx, %rax
cmpq %rcx, %rax
jle 0x3e957
leaq -0x2(%r10), %rcx
movq %rcx, 0x58(%rsp)
xorl %ecx, %ecx
testl %r15d, %r15d
setg %cl
subl %ecx, %r15d
xorl %ebx, %ebx
jmp 0x3e982
movl 0x4c(%rsp), %edx
cmpl %edx, %ebx
jge 0x3e9d8
incl %ebx
movq 0x8(%rsp), %rax
movq 0x28(%rax), %rax
cmpq %rbp, -0x10(%rax,%r10,8)
jne 0x3e979
cmpl %edx, %r15d
jge 0x3e9d8
incl %r15d
movq %rcx, %rax
movq %rsi, %r9
movq %r13, %r8
movq 0x28(%rsp), %rcx
movq -0x10(%rcx,%r10,8), %rcx
testq %rcx, %rcx
js 0x3e8ca
movq 0x8(%rsp), %rdx
movq 0x28(%rdx), %rdx
movq %rbp, (%rdx,%rcx,8)
jmp 0x3e8ca
movq 0x30(%rsp), %rax
movl %ecx, (%rax,%rbp,4)
movq 0x28(%rsp), %rax
movq $-0x1, (%rax,%rbp,8)
movq 0x10(%rsp), %rax
xorl %ecx, %ecx
movl %ecx, (%rax,%rbp,4)
movq 0x40(%rsp), %rax
movl %ecx, (%rax,%rbp,4)
movl $0x1, (%r9,%rbp,4)
jmp 0x3ea3c
movq %rcx, %rax
movq %rsi, %r9
movq %r13, %r8
movq 0x30(%rsp), %rcx
movl %eax, (%rcx,%rbp,4)
movq 0x28(%rsp), %rax
movq 0x58(%rsp), %rcx
movq %rcx, (%rax,%rbp,8)
movq 0x10(%rsp), %rax
movl %r9d, (%rax,%rbp,4)
movq 0x40(%rsp), %rax
movl %r8d, (%rax,%rbp,4)
movq 0x70(%rsp), %r9
movl $0x1, (%r9,%rbp,4)
cmpq $-0x1, %rcx
movq (%rsp), %r8
movq 0x50(%rsp), %r10
movq 0x80(%rsp), %r11
movq 0x78(%rsp), %r15
je 0x3ea3c
movl (%r9,%rcx,4), %eax
incl %eax
movl %eax, (%r9,%rbp,4)
incq %rbp
incq %r15
addq $0x10, %r11
cmpq %r10, %rbp
jne 0x3e800
movq 0x68(%rsp), %r13
leal 0x2(,%r13,2), %eax
cltq
movq 0x8(%rsp), %rcx
movq (%rcx), %rcx
movslq %r13d, %rdx
movslq 0xc0(%rsp), %rsi
movq %rsi, 0x10(%rsp)
leaq -0x1(%rdx), %rdi
addq $0x8, %r8
movq $-0x1, %r14
xorl %r9d, %r9d
movl $0x1, %esi
movq $-0x1, %r11
movslq (%rcx,%r9,4), %rbx
cmpq %rbx, %r11
jge 0x3eae0
movl -0x4(%r8), %r11d
movl (%r8), %r14d
movq %r11, %rax
subq %r14, %rax
incq %rax
movq %r14, %r15
notq %r15
addq %rdx, %r15
movq %r11, %r12
notq %r12
addq 0x10(%rsp), %r12
movq %r14, %r13
addq %r12, %r13
cmpq %r12, %r15
cmovleq %rdi, %r13
cmpl %r11d, %r14d
cmovbeq %rsi, %rax
addq %r13, %rax
movq %rbx, %r11
movq %r9, %r14
jmp 0x3eb33
jne 0x3eb33
movl -0x4(%r8), %ebx
movq %r10, %rsi
movl (%r8), %r10d
movq %rbx, %r12
subq %r10, %r12
incq %r12
movq %r10, %r13
notq %r13
addq %rdx, %r13
movq %rbx, %rbp
notq %rbp
addq 0x10(%rsp), %rbp
movq %r10, %r15
addq %rbp, %r15
cmpq %rbp, %r13
cmovleq %rdi, %r15
cmpl %ebx, %r10d
movq %rsi, %r10
movl $0x1, %esi
cmovbeq %rsi, %r12
addq %r15, %r12
cmpq %rax, %r12
cmovlq %r9, %r14
cmovlq %r12, %rax
incq %r9
addq $0x10, %r8
cmpq %r9, %r10
jne 0x3ea94
movq 0x20(%rsp), %rbx
leaq 0x38(%rbx), %r12
movl $0x0, 0x40(%rbx)
movq %r14, %rcx
shlq $0x4, %rcx
movq (%rsp), %rdx
movl 0x8(%rdx,%rcx), %esi
movl %esi, 0x8(%rbx)
movl 0x4(%rdx,%rcx), %ecx
movl %ecx, 0x18(%rbx)
movl %r11d, 0x24(%rbx)
movl %eax, 0x20(%rbx)
movq %r12, %rdi
xorl %edx, %edx
movq 0xc8(%rsp), %rcx
callq 0x3d202
movq %rbx, %rdi
cmpl $0x1, 0xc(%rbx)
jne 0x3ec07
testq %r14, %r14
js 0x3ec7e
xorl %r13d, %r13d
xorl %eax, %eax
movq (%rsp), %r8
movq %r14, %rbx
shlq $0x4, %rbx
movl 0x4(%r8,%rbx), %ecx
movl 0x8(%r8,%rbx), %esi
movl 0x8(%rdi), %edx
movl 0x18(%rdi), %ebp
subl %esi, %edx
subl %ecx, %ebp
subq %rdx, %rbp
cmpq %rax, %rbp
je 0x3ebea
addq %r8, %rbx
movq %r12, %rdi
movl %ebp, %edx
movq 0xc8(%rsp), %rcx
callq 0x3d202
movq (%rsp), %r8
movq 0x20(%rsp), %rdi
movl 0x4(%rbx), %ecx
movl 0x8(%rbx), %esi
movq %rbp, %rax
incq %r13
movl %esi, 0x4(%rdi)
movl %ecx, 0x14(%rdi)
movq 0x8(%rsp), %rcx
movq 0x8(%rcx), %rcx
movq (%rcx,%r14,8), %r14
testq %r14, %r14
jns 0x3eba0
jmp 0x3ec81
testq %r14, %r14
js 0x3ec7e
xorl %r13d, %r13d
xorl %eax, %eax
movq (%rsp), %rdx
movq %r14, %rbx
shlq $0x4, %rbx
movl 0x8(%rdx,%rbx), %esi
movl 0x8(%rdi), %ecx
movl 0x18(%rdi), %ebp
subl %esi, %ecx
subl 0x4(%rdx,%rbx), %ebp
subq %rcx, %rbp
cmpq %rax, %rbp
jne 0x3ec3a
decl 0x40(%rdi)
movq %rax, %rbp
addq %rdx, %rbx
movq %r12, %rdi
movl %ebp, %edx
movq 0xc8(%rsp), %rcx
callq 0x3d202
movq (%rsp), %rdx
movq 0x20(%rsp), %rdi
incq %r13
movl 0x8(%rbx), %eax
movl %eax, 0x4(%rdi)
movl 0x4(%rbx), %eax
movl %eax, 0x14(%rdi)
movq 0x8(%rsp), %rax
movq 0x8(%rax), %rax
movq (%rax,%r14,8), %r14
movq %rbp, %rax
testq %r14, %r14
jns 0x3ec15
jmp 0x3ec81
xorl %r13d, %r13d
movq %r13, %rax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leal 0x2(,%r13,2), %eax
movq $-0x1, %r14
movl $0xffffffff, %r11d      # imm = 0xFFFFFFFF
jmp 0x3eb43