// File: /workspace/github_cpp_makefile_star2_O1/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
movq %r9, 0x48(%rsp)
movl %r8d, %ebp
movsd %xmm0, 0x30(%rsp)
movq %rcx, 0x20(%rsp)
movq %rdx, %r14
movq %rsi, %rbx
movq %rdi, %r15
movq 0xc8(%rsp), %rdx
leaq 0x24b499(%rip), %rax    # 0x28a758
movl 0x80(%rax), %r12d
movq %r14, %rdi
callq 0x3f828
movq %r15, %rdi
movl %ebx, %esi
movq %r14, %rdx
movl %r12d, %ecx
movsd 0x30(%rsp), %xmm0
callq 0x3f0dc
testl %eax, %eax
movq %r15, 0x40(%rsp)
jle 0x3f2f4
movl %eax, %edi
jmp 0x3f5bd
movl %ebp, 0x2c(%rsp)
testq %rbx, %rbx
movq %rbx, %rdi
movq %rbx, 0x10(%rsp)
jle 0x3f325
movq 0x28(%r14), %rdi
movq 0x10(%rsp), %rax
leaq (,%rax,8), %rdx
movl $0xff, %esi
callq 0x20e0
movq 0x10(%rsp), %rdi
testq %rdi, %rdi
jle 0x3f5bd
movsd 0x1e5f3a(%rip), %xmm0   # 0x225270
movsd 0x30(%rsp), %xmm4
divsd %xmm4, %xmm0
movslq %r12d, %rax
movq %rax, 0x18(%rsp)
movq (%r14), %rax
movq %rax, 0x70(%rsp)
movq 0x8(%r14), %rax
movq %rax, 0x68(%rsp)
movq 0x10(%r14), %rax
movq %rax, 0x60(%rsp)
movq 0x18(%r14), %rax
movq %rax, 0x58(%rsp)
movq 0x20(%r14), %rbx
leaq -0x4(%r15), %r12
movl $0x1, %r13d
xorl %r8d, %r8d
movq %rbx, 0x50(%rsp)
movq %r8, %rax
shlq $0x4, %rax
movl 0x4(%r15,%rax), %r10d
movl 0x8(%r15,%rax), %r11d
movl 0xc(%r15,%rax), %ecx
movl $0x1, %esi
cmpq %rcx, 0x18(%rsp)
jl 0x3f3b0
movq 0x18(%rsp), %rax
xorl %edx, %edx
divq %rcx
movq %rax, %rsi
testq %r8, %r8
je 0x3f534
movq $-0x1, 0x38(%rsp)
movq $0x0, 0x8(%rsp)
movq %r12, 0x80(%rsp)
movq %r13, 0x78(%rsp)
movq %r13, %rdi
xorl %r15d, %r15d
xorl %ebp, %ebp
xorl %r13d, %r13d
movl -0x8(%r12), %ecx
cmpl %ecx, %r10d
je 0x3f449
movl -0x4(%r12), %edx
movq %r11, %rax
subq %rdx, %rax
testq %rax, %rax
jle 0x3f449
movq %r10, %rdx
subq %rcx, %rdx
movq %rdx, %rcx
subq %rax, %rcx
movq %rcx, %r9
negq %r9
cmovsq %rcx, %r9
movq 0x10(%r14), %rcx
movq 0x18(%r14), %rbx
movslq -0x8(%rcx,%rdi,4), %rcx
addq %r9, %rcx
movslq -0x8(%rbx,%rdi,4), %r9
addq %rax, %r9
xorps %xmm1, %xmm1
cvtsi2sd %rcx, %xmm1
xorps %xmm2, %xmm2
cvtsi2sd %r9, %xmm2
movapd %xmm2, %xmm3
mulsd %xmm4, %xmm3
ucomisd %xmm3, %xmm1
jbe 0x3f471
movq %rsi, %rax
movq %r13, %rcx
movq %rbp, %r9
decq %rdi
addq $-0x10, %r12
movq %r9, %rbp
movq %rcx, %r13
movq %rax, %rsi
cmpq $0x1, %rdi
jg 0x3f3e3
jmp 0x3f54b
cmpq %rax, %rdx
cmovlq %rdx, %rax
movq 0x18(%rsp), %rdx
cmpq %rdx, %rax
cmovgeq %rdx, %rax
movl (%r12), %ebx
movl $0x1, %edx
cmpq %rbx, %rax
jl 0x3f49a
xorl %edx, %edx
divq %rbx
movq %rax, %rdx
divsd %xmm2, %xmm1
xorps %xmm2, %xmm2
cvtsi2sd %rdx, %xmm2
mulsd %xmm1, %xmm2
mulsd %xmm0, %xmm2
cvttsd2si %xmm2, %rax
subq %rax, %rdx
movq (%r14), %rax
movslq -0x8(%rax,%rdi,4), %rax
addq %rdx, %rax
cmpq %rsi, %rax
jle 0x3f4e5
leaq -0x2(%rdi), %rdx
movq %rdx, 0x38(%rsp)
xorl %edx, %edx
testl %r15d, %r15d
setg %dl
subl %edx, %r15d
movq $0x0, 0x8(%rsp)
jmp 0x3f515
movl 0x2c(%rsp), %ecx
movq 0x8(%rsp), %rdx
cmpl %ecx, %edx
jge 0x3f542
incl %edx
movq 0x28(%r14), %rax
cmpq %r8, -0x10(%rax,%rdi,8)
movq %rdx, 0x8(%rsp)
jne 0x3f50c
cmpl %ecx, %r15d
jge 0x3f542
incl %r15d
movq %rsi, %rax
movq %r13, %rcx
movq %rbp, %r9
movq 0x8(%r14), %rdx
movq -0x10(%rdx,%rdi,8), %rdx
testq %rdx, %rdx
js 0x3f452
movq 0x28(%r14), %rsi
movq %r8, (%rsi,%rdx,8)
jmp 0x3f452
movq $-0x1, %rdx
xorl %ecx, %ecx
xorl %r9d, %r9d
jmp 0x3f56f
movq %rsi, %rax
movq %r13, %rcx
movq %rbp, %r9
movq %rax, %rsi
movq 0x40(%rsp), %r15
movq 0x10(%rsp), %rdi
movq 0x50(%rsp), %rbx
movq 0x80(%rsp), %r12
movq 0x78(%rsp), %r13
movq 0x38(%rsp), %rdx
movq 0x70(%rsp), %rax
movl %esi, (%rax,%r8,4)
movq 0x68(%rsp), %rax
movq %rdx, (%rax,%r8,8)
movq 0x60(%rsp), %rax
movl %ecx, (%rax,%r8,4)
movq 0x58(%rsp), %rax
movl %r9d, (%rax,%r8,4)
movl $0x1, (%rbx,%r8,4)
cmpq $-0x1, %rdx
je 0x3f5aa
movl (%rbx,%rdx,4), %eax
incl %eax
movl %eax, (%rbx,%r8,4)
incq %r8
incq %r13
addq $0x10, %r12
cmpq %rdi, %r8
jne 0x3f381
movq 0x48(%rsp), %rdx
leal 0x2(,%rdx,2), %eax
testq %rdi, %rdi
jle 0x3f6dd
cltq
movq (%r14), %rcx
movslq %edx, %r10
movslq 0xc0(%rsp), %rdx
leaq -0x1(%r10), %rsi
movq %rsi, 0x8(%rsp)
leaq 0x8(%r15), %r8
movq $-0x1, %r13
xorl %r9d, %r9d
movl $0x1, %esi
movq $-0x1, %r11
movq %rdi, 0x10(%rsp)
movslq (%rcx,%r9,4), %rbx
cmpq %rbx, %r11
jge 0x3f656
movl -0x4(%r8), %r11d
movl (%r8), %r15d
movq %r11, %rax
subq %r15, %rax
incq %rax
movq %r15, %r12
notq %r12
addq %r10, %r12
movq %r11, %r13
notq %r13
addq %rdx, %r13
movq %r15, %rbp
addq %r13, %rbp
cmpq %r13, %r12
cmovleq 0x8(%rsp), %rbp
cmpl %r11d, %r15d
cmovbeq %rsi, %rax
addq %rbp, %rax
movq %rbx, %r11
movq %r9, %r13
jmp 0x3f6c6
jne 0x3f6c6
movl -0x4(%r8), %esi
movl (%r8), %edi
movq %rsi, %r15
subq %rdi, %r15
incq %r15
movq %rdi, %rbp
notq %rbp
addq %r10, %rbp
movq %rsi, %r12
notq %r12
addq %rdx, %r12
movq %r11, 0x18(%rsp)
movq %rdx, %r11
movq %rcx, %rdx
movq %r10, %rcx
movq %rdi, %r10
addq %r12, %r10
cmpq %r12, %rbp
cmovleq 0x8(%rsp), %r10
cmpl %esi, %edi
movl $0x1, %esi
movq 0x10(%rsp), %rdi
cmovbeq %rsi, %r15
addq %r10, %r15
movq %rcx, %r10
movq %rdx, %rcx
movq %r11, %rdx
movq 0x18(%rsp), %r11
cmpq %rax, %r15
jge 0x3f6c6
movq %rbx, %r11
movq %r9, %r13
movq %r15, %rax
incq %r9
addq $0x10, %r8
cmpq %r9, %rdi
movq 0x40(%rsp), %r15
jne 0x3f60a
jmp 0x3f6ea
movq $-0x1, %r13
movl $0xffffffff, %r11d      # imm = 0xFFFFFFFF
movq 0x20(%rsp), %rbx
leaq 0x38(%rbx), %rdi
movl $0x0, 0x40(%rbx)
movq %r13, %rcx
shlq $0x4, %rcx
movl 0x8(%r15,%rcx), %esi
movl %esi, 0x8(%rbx)
movl 0x4(%r15,%rcx), %ecx
movl %ecx, 0x18(%rbx)
movl %r11d, 0x24(%rbx)
movl %eax, 0x20(%rbx)
movq %rdi, 0x8(%rsp)
xorl %edx, %edx
movq 0xc8(%rsp), %rcx
callq 0x3dd21
movq %rbx, %rdx
cmpl $0x1, 0xc(%rbx)
jne 0x3f7a2
testq %r13, %r13
js 0x3f811
xorl %ebp, %ebp
xorl %eax, %eax
movq %r13, %rbx
shlq $0x4, %rbx
movl 0x8(%r15,%rbx), %esi
movl 0x8(%rdx), %ecx
movl 0x18(%rdx), %r12d
subl %esi, %ecx
subl 0x4(%r15,%rbx), %r12d
subq %rcx, %r12
cmpq %rax, %r12
je 0x3f781
movq 0x8(%rsp), %rdi
movl %r12d, %edx
movq 0xc8(%rsp), %rcx
callq 0x3dd21
movq 0x20(%rsp), %rdx
movq %r12, %rax
addq %r15, %rbx
incq %rbp
movl 0x8(%rbx), %ecx
movl %ecx, 0x4(%rdx)
movl 0x4(%rbx), %ecx
movl %ecx, 0x14(%rdx)
movq 0x8(%r14), %rcx
movq (%rcx,%r13,8), %r13
testq %r13, %r13
jns 0x3f742
jmp 0x3f813
testq %r13, %r13
js 0x3f811
xorl %ebp, %ebp
xorl %eax, %eax
movq %r13, %rbx
shlq $0x4, %rbx
movl 0x8(%r15,%rbx), %esi
movl 0x8(%rdx), %ecx
movl 0x18(%rdx), %r12d
subl %esi, %ecx
subl 0x4(%r15,%rbx), %r12d
subq %rcx, %r12
cmpq %rax, %r12
jne 0x3f7d3
decl 0x40(%rdx)
movq %rax, %r12
addq %r15, %rbx
movq 0x8(%rsp), %rdi
movl %r12d, %edx
movq 0xc8(%rsp), %rcx
callq 0x3dd21
movq 0x20(%rsp), %rdx
incq %rbp
movl 0x8(%rbx), %eax
movl %eax, 0x4(%rdx)
movl 0x4(%rbx), %eax
movl %eax, 0x14(%rdx)
movq 0x8(%r14), %rax
movq (%rax,%r13,8), %r13
movq %r12, %rax
testq %r13, %r13
jns 0x3f7ab
jmp 0x3f813
xorl %ebp, %ebp
movq %rbp, %rax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq