// File: 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:
subq $0xb8, %rsp
movq %rdi, 0xa8(%rsp)
movl %esi, 0xa4(%rsp)
movl %edx, 0xa0(%rsp)
movl %ecx, 0x9c(%rsp)
movsd %xmm0, 0x90(%rsp)
movl %r8d, 0x8c(%rsp)
movl %r9d, 0x88(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x80(%rsp)
movl 0x9c(%rsp), %eax
movl %eax, 0x7c(%rsp)
movl 0x7c(%rsp), %eax
movl 0x9c(%rsp), %ecx
addl 0xa0(%rsp), %ecx
cmpl %ecx, %eax
jg 0x361b1
cmpl $0x0, 0x7c(%rsp)
jle 0x361a2
movl 0x7c(%rsp), %eax
cmpl 0xa4(%rsp), %eax
jg 0x361a2
movq 0xa8(%rsp), %rax
movslq 0x7c(%rsp), %rcx
movsd (%rax,%rcx,8), %xmm0
addsd 0x80(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
jmp 0x361a4
movl 0x7c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x7c(%rsp)
jmp 0x36154
movsd 0x80(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x361d6
jp 0x361d6
xorps %xmm0, %xmm0
movsd %xmm0, 0xb0(%rsp)
jmp 0x363e0
cmpl $0x0, 0xa0(%rsp)
jne 0x361f1
xorps %xmm0, %xmm0
movsd %xmm0, 0xb0(%rsp)
jmp 0x363e0
movsd 0x80(%rsp), %xmm0
cvtsi2sdl 0xa0(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp)
movsd 0x70(%rsp), %xmm0
movsd %xmm0, 0x68(%rsp)
movsd 0x68(%rsp), %xmm0
callq 0x441e0
movsd %xmm0, 0x60(%rsp)
movsd 0x1bde6(%rip), %xmm0    # 0x52018
subsd 0x90(%rsp), %xmm0
callq 0x441e0
movsd %xmm0, 0x58(%rsp)
movsd 0x1be0a(%rip), %xmm0    # 0x52058
mulsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x50(%rsp)
movsd 0x1bdf6(%rip), %xmm0    # 0x52058
mulsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movl $0x1, 0x44(%rsp)
movl 0x44(%rsp), %eax
cmpl 0x8c(%rsp), %eax
jge 0x362e9
movsd 0x60(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
cvtsi2sdl 0x44(%rsp), %xmm0
callq 0x441e0
movaps %xmm0, %xmm1
movsd 0x10(%rsp), %xmm0
callq 0x445a0
movsd %xmm0, 0x38(%rsp)
movsd 0x48(%rsp), %xmm0
movsd 0x38(%rsp), %xmm1
callq 0x44510
movsd %xmm0, 0x48(%rsp)
movsd 0x50(%rsp), %xmm0
movsd 0x48(%rsp), %xmm1
callq 0x44310
movsd %xmm0, 0x50(%rsp)
movl 0x44(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x44(%rsp)
jmp 0x36276
movb $0x0, 0x37(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x28(%rsp)
movl 0x8c(%rsp), %eax
movl %eax, 0x24(%rsp)
movl 0x24(%rsp), %ecx
xorl %eax, %eax
cmpl 0x88(%rsp), %ecx
movb %al, 0xf(%rsp)
jg 0x3631f
movb 0x37(%rsp), %al
xorb $-0x1, %al
movb %al, 0xf(%rsp)
movb 0xf(%rsp), %al
testb $0x1, %al
jne 0x3632c
jmp 0x363b4
movsd 0x60(%rsp), %xmm0
movsd %xmm0, (%rsp)
cvtsi2sdl 0x24(%rsp), %xmm0
callq 0x441e0
movaps %xmm0, %xmm1
movsd (%rsp), %xmm0
callq 0x445a0
movsd %xmm0, 0x18(%rsp)
movsd 0x48(%rsp), %xmm0
movsd 0x18(%rsp), %xmm1
callq 0x44510
movsd %xmm0, 0x48(%rsp)
movsd 0x50(%rsp), %xmm0
movsd 0x48(%rsp), %xmm1
callq 0x44310
movsd %xmm0, 0x50(%rsp)
movsd 0x50(%rsp), %xmm0
ucomisd 0x58(%rsp), %xmm0
jbe 0x363a2
movb $0x1, 0x37(%rsp)
cvtsi2sdl 0x24(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
jmp 0x363a4
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x36302
movsd 0x28(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x363d4
movsd 0x28(%rsp), %xmm0
movsd %xmm0, 0xb0(%rsp)
jmp 0x363e0
xorps %xmm0, %xmm0
movsd %xmm0, 0xb0(%rsp)
movsd 0xb0(%rsp), %xmm0
addq $0xb8, %rsp
retq
nopw %cs:(%rax,%rax)