// File: /workspace/github_cpp_makefile_star2_O3/gersteinlab[P]MUSIC/src/ms_signal_enrichment_utils.cpp
// Function: get_poisson_thresholds_per_win(double*, int, int, int, double, int, int)
double get_poisson_thresholds_per_win(double* signal_profile,
								int l_profile,
								int l_win,
								int win_start,
								double target_fdr,
								int min_thresh,
								int max_thresh)
{
	// Count the number of reads per window.
	double total_sig_in_cur_window = 0.0;
	for(int i = win_start; i <= win_start + l_win; i++)
	{
        if(i > 0 && i <= l_profile)
        {
			total_sig_in_cur_window += signal_profile[i];
		}
	} // i loop.

	// Get the total amount of signal in the current window.
	if(total_sig_in_cur_window == 0.0)
	{
		return(0.0);
	}

	if(l_win == 0)
	{
		return(0.0);
	}
	else
	{
		// This is the average of poisson distribution for the heights in this window.
		double avg_read_depth = total_sig_in_cur_window / l_win;
		double lambda = avg_read_depth;
		double log_lambda = xlog(lambda);

		double log_target_cdf = xlog(1.0 - target_fdr);

		// Update the log_cdf value for thresholds smaller than min_threshold.
		double current_log_cdf = -1.0 * lambda;
		double current_factor = -1.0 * lambda; // This is the probability value differentially updated in CDF computation.
		for(int thresh = 1; 
			thresh < min_thresh;
			thresh++)
		{
			double new_multiplier = xlog_div(log_lambda, xlog((double)thresh));
			current_factor = xlog_mul(current_factor, new_multiplier);
			current_log_cdf = xlog_sum(current_log_cdf, current_factor);
		}

		// For thresholds between min and max thresholds, compare the value of (log)CDF with the (log)target FDR.
		bool found_thresh = false;
		double cur_threshold = 0;
		for(int thresh = min_thresh; 
			thresh <= max_thresh && !found_thresh; 
			thresh++)
		{
			double new_multiplier = xlog_div(log_lambda, xlog((double)thresh));
			current_factor = xlog_mul(current_factor, new_multiplier);
			current_log_cdf = xlog_sum(current_log_cdf, current_factor);

			if(current_log_cdf > log_target_cdf)
			{
				found_thresh = true;
				cur_threshold = thresh; // Set the threshold in this window.
			}
		} // thresh loop.

		if(cur_threshold > 0)
		{
			return(cur_threshold);
		}
		else
		{
			return(0.0);
		}
	} // Check for positive number of reads in the window.
}

// Assembly:
testl %edx, %edx
js 0x1dfbc
pushq %rbp
pushq %r14
pushq %rbx
subq $0x50, %rsp
movl %r9d, %ebx
movl %r8d, %r14d
movapd %xmm0, %xmm3
leal (%rcx,%rdx), %eax
cmpl %eax, %ecx
cmovgl %ecx, %eax
incl %eax
xorpd %xmm0, %xmm0
testl %ecx, %ecx
setle %r8b
cmpl %esi, %ecx
setg %r9b
orb %r8b, %r9b
jne 0x1ded5
movl %ecx, %r8d
addsd (%rdi,%r8,8), %xmm0
incl %ecx
cmpl %ecx, %eax
jne 0x1debb
xorpd %xmm2, %xmm2
testl %edx, %edx
je 0x1e077
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x1def7
jnp 0x1e077
xorps %xmm1, %xmm1
cvtsi2sd %edx, %xmm1
divsd %xmm1, %xmm0
movapd %xmm0, 0x20(%rsp)
movsd %xmm3, 0x8(%rsp)
callq 0x2525c
movsd %xmm0, 0x30(%rsp)
movsd 0xc0e7(%rip), %xmm0     # 0x2a008
subsd 0x8(%rsp), %xmm0
callq 0x2525c
movapd 0x20(%rsp), %xmm1
movsd %xmm0, 0x38(%rsp)
xorpd 0x101b0(%rip), %xmm1    # 0x2e0f0
cmpl $0x2, %r14d
movapd %xmm1, 0x20(%rsp)
jl 0x1dfc5
leal -0x1(%r14), %ebp
movsd 0xc0b0(%rip), %xmm0     # 0x2a008
movapd %xmm1, %xmm2
movsd %xmm2, 0x8(%rsp)
movsd %xmm0, 0x10(%rsp)
movsd 0x10(%rsp), %xmm0
callq 0x2525c
movaps %xmm0, %xmm1
movsd 0x30(%rsp), %xmm0
callq 0x25400
movaps %xmm0, %xmm1
movapd 0x20(%rsp), %xmm0
callq 0x253c5
movapd %xmm0, %xmm1
movsd 0x8(%rsp), %xmm0
movapd %xmm1, 0x20(%rsp)
callq 0x252b0
movapd %xmm0, %xmm2
movsd 0x10(%rsp), %xmm0
addsd 0xc052(%rip), %xmm0     # 0x2a008
decl %ebp
jne 0x1df5c
jmp 0x1dfc9
xorpd %xmm2, %xmm2
jmp 0x1e07f
movapd %xmm1, %xmm2
xorpd %xmm0, %xmm0
movapd %xmm0, 0x10(%rsp)
cmpl %ebx, %r14d
jg 0x1e069
movapd %xmm0, 0x10(%rsp)
movsd %xmm2, 0x8(%rsp)
xorps %xmm0, %xmm0
cvtsi2sd %r14d, %xmm0
movapd %xmm0, 0x40(%rsp)
callq 0x2525c
movapd %xmm0, %xmm1
movsd 0x30(%rsp), %xmm0
callq 0x25400
movaps %xmm0, %xmm1
movaps 0x20(%rsp), %xmm0
callq 0x253c5
movaps %xmm0, %xmm1
movsd 0x8(%rsp), %xmm0
movaps %xmm1, 0x20(%rsp)
callq 0x252b0
movapd %xmm0, %xmm2
movsd 0x38(%rsp), %xmm1
movapd %xmm1, %xmm0
cmpltsd %xmm2, %xmm0
movapd 0x40(%rsp), %xmm3
andpd %xmm0, %xmm3
andnpd 0x10(%rsp), %xmm0
orpd %xmm3, %xmm0
movapd %xmm0, 0x10(%rsp)
cmpl %ebx, %r14d
jge 0x1e069
incl %r14d
ucomisd %xmm1, %xmm2
jbe 0x1dfe2
movapd 0x10(%rsp), %xmm2
maxsd 0xc039(%rip), %xmm2     # 0x2a0b0
addq $0x50, %rsp
popq %rbx
popq %r14
popq %rbp
movapd %xmm2, %xmm0
retq