// File: /workspace/github_cpp_makefile_star2_O3/gersteinlab[P]MUSIC/src/ms_peak_calling_utils.cpp
// Function: get_control_per_chip_profile(double*, int, int, int)
double* get_control_per_chip_profile(double* signal_profile, int l_profile, int l_p_win, int l_fragment)
{
if(__DUMP_PEAK_CALLING_UTILS_MSGS__)
{
	fprintf(stderr, "Generating smoothed track for %d values.\n", l_profile);
}

	int l_average = 1000*1000;
	double* window_averaged_signal_profile = mean_filter_data(signal_profile,
																l_profile, 
																l_average,
																-1);

	// Ceil the profile.
	for(int i = 1; i <= l_profile; i++)
	{
		//window_averaged_signal_profile[i] = ceil(window_averaged_signal_profile[i]);
		if(window_averaged_signal_profile[i] < 1)
		{
			window_averaged_signal_profile[i] = 1;
		}
	} // i loop.

	double target_FPRs = 0.10;

	int n_wins = l_profile / l_p_win;

if(__DUMP_PEAK_CALLING_UTILS_MSGS__)
{
	fprintf(stderr, "%d windows.\n", n_wins);
}

	double* avg_per_l_p_win_signal = new double[n_wins+2];
	double* avg_per_l_p_win_control = new double[n_wins+2];
	for(int i_win = 0; i_win < n_wins; i_win++)
	{
		avg_per_l_p_win_signal[i_win] = 0;
		avg_per_l_p_win_control[i_win] = 0;

		for(int i = i_win*l_p_win+1; i < i_win*l_p_win + l_p_win; i++)
		{
			avg_per_l_p_win_signal[i_win] += signal_profile[i];
			avg_per_l_p_win_control[i_win] += window_averaged_signal_profile[i];
		} // i loop.
	} // i_win loop.

	// Go over per signal values, 
	double* log_factorials = buffer_log_factorials(1000*1000);
	
	// We need at least 50 windows in each denominator.
	bool have_enough_wins = false;

	int max_n_iters = 500;

	bool constraint_satisfied = false;
	double cur_p_val_FPR = 0;
	double cur_FC_FPR = 0;
	int iter_i = 0;
	for(;
		!constraint_satisfied
		; iter_i++)
	{
		double n_p_val_sig_FC_sig = 0;
		double n_p_val_sig_FC_insig = 0;
		double n_p_val_insig_FC_sig = 0;
		double n_p_val_insig_FC_insig = 0;
		for(int i_win = 0; i_win < n_wins; i_win++)
		{
			if(avg_per_l_p_win_signal[i_win] < l_p_win ||
			avg_per_l_p_win_control[i_win] < l_p_win)
			{
				continue;
			}

			//double log_p_val = get_binomial_pvalue_per_region(signal_profile, window_averaged_signal_profile,
			//													i_win*l_p_win+1, i_win*l_p_win+l_p_win,
			//													log_factorials, 1, false, 0);

			double log_p_val = get_binomial_p_val_per_enriched_background_values(avg_per_l_p_win_signal[i_win] / l_fragment, 
																				avg_per_l_p_win_control[i_win] / l_fragment, 
																				log_factorials);

			if(log_p_val < log(0.05))
			{
				if(avg_per_l_p_win_signal[i_win] / avg_per_l_p_win_control[i_win] > 2)
				{
					n_p_val_sig_FC_sig++;
				}
				else if(avg_per_l_p_win_signal[i_win] / avg_per_l_p_win_control[i_win] < 1.5)
				{
					n_p_val_sig_FC_insig++;
				}
				else
				{
					// The stuff that is insignificantly enriched, but FC is not conclusive.
				}
			} // p-val significant check.
			else
			{
				if(avg_per_l_p_win_signal[i_win] / avg_per_l_p_win_control[i_win] > 2)
				{
					n_p_val_insig_FC_sig++;
				}
				else if(avg_per_l_p_win_signal[i_win] / avg_per_l_p_win_control[i_win] < 1.5)
				{
					n_p_val_insig_FC_insig++;
				}
				else
				{
					// The stuff that is insignificantly enriched, but FC is not conclusive.
				}
			} // p-val insignificant check.
		} // i_win loop.

		// If there was never enough windows, update this.
		if(!have_enough_wins)
		{
			have_enough_wins = ((n_p_val_sig_FC_sig + n_p_val_insig_FC_sig) > 100 &&
								(n_p_val_sig_FC_sig + n_p_val_sig_FC_insig) > 100);
		}

		// Stopping criteria:
		double p_val_fpr_estimate = n_p_val_insig_FC_sig / (n_p_val_sig_FC_sig + n_p_val_insig_FC_sig);
		double FC_fpr_estimate = n_p_val_sig_FC_insig / (n_p_val_sig_FC_sig + n_p_val_sig_FC_insig); 

		cur_p_val_FPR = p_val_fpr_estimate;
		cur_FC_FPR = FC_fpr_estimate;

if(__DUMP_PEAK_CALLING_UTILS_MSGS__)
{
		fprintf(stderr, "%d. iteration, %lf/%lf=%lf, %lf/%lf=%lf\n", iter_i, 
			n_p_val_insig_FC_sig, (n_p_val_sig_FC_sig + n_p_val_insig_FC_sig), p_val_fpr_estimate, 
			n_p_val_sig_FC_insig, (n_p_val_sig_FC_sig + n_p_val_sig_FC_insig), FC_fpr_estimate);
}

		// If we have tried a lot, just give up at this iteration.
		if(iter_i >= max_n_iters)
		{
			break;
		}

		// Are we in good region? If so update the control to create a more stringent background.
		if(!have_enough_wins ||						// The number of accessible windows must increase as we make the background more stringent.
			(p_val_fpr_estimate > target_FPRs ||	// This will decrease as we make control more stringent.
			FC_fpr_estimate < target_FPRs))			// This will increase as we make control more stringent.
		{
			// Update the profile.
			for(int i = 1; i < l_profile; i++)
			{
				window_averaged_signal_profile[i] += .05;
			} // i loop.

			// Update the per window control signal.
			for(int i_win = 0; i_win < n_wins; i_win++)
			{
				avg_per_l_p_win_control[i_win] += l_p_win * 0.05;
			} // i_win loop.			
		}
		else
		{
			break;
		}
	} // signal update loop.

	fprintf(stderr, "Set the control profile in %d iterations (%.3f, %.3f)\n", iter_i, cur_p_val_FPR, cur_FC_FPR);

	delete [] log_factorials;
	delete [] avg_per_l_p_win_signal;
	delete [] avg_per_l_p_win_control;

	return(window_averaged_signal_profile);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movl %ecx, 0x20(%rsp)
movl %edx, %ebp
movl %esi, %r15d
movq %rdi, %r14
cmpb $0x1, 0x3626f(%rip)     # 0x391ca
jne 0x2f78
movq 0x3607c(%rip), %rax     # 0x38fe0
movq (%rax), %rdi
leaq 0x29ab2(%rip), %rsi     # 0x2ca20
movl %r15d, %edx
xorl %eax, %eax
callq 0x2250
pushq $-0x1
popq %rcx
movq %r14, %rdi
movl %r15d, %esi
movl $0xf4240, %edx          # imm = 0xF4240
callq 0x12db7
movq %rax, %rbx
testl %r15d, %r15d
jle 0x2fbf
pushq $0x1
popq %rax
leal 0x1(%r15), %ecx
movsd 0x27066(%rip), %xmm0    # 0x2a008
movabsq $0x3ff0000000000000, %rdx # imm = 0x3FF0000000000000
ucomisd (%rbx,%rax,8), %xmm0
jbe 0x2fb7
movq %rdx, (%rbx,%rax,8)
incq %rax
cmpq %rax, %rcx
jne 0x2fac
movq %r15, 0x48(%rsp)
movl %r15d, %eax
cltd
idivl %ebp
movl %eax, %r15d
cmpb $0x0, 0x361f6(%rip)     # 0x391ca
je 0x2ff1
movq 0x36003(%rip), %rax     # 0x38fe0
movq (%rax), %rdi
leaq 0x29a63(%rip), %rsi     # 0x2ca4a
movl %r15d, %edx
xorl %eax, %eax
callq 0x2250
leal 0x2(%r15), %eax
shlq $0x3, %rax
cmpl $-0x2, %r15d
pushq $-0x1
popq %r13
cmovgeq %rax, %r13
movq %r13, %rdi
callq 0x2040
movq %rax, %r12
movq %r13, %rdi
callq 0x2040
movq %rax, %r13
movq %r15, %rax
movl %eax, %r15d
movq %rax, 0x38(%rsp)
testl %eax, %eax
jle 0x30a7
movabsq $0x100000000, %rax      # imm = 0x100000000
movslq %ebp, %rcx
pushq $0x1
popq %rdx
xorl %esi, %esi
andq $0x0, (%r12,%rsi,8)
andq $0x0, (%r13,%rsi,8)
leaq 0x1(%rsi), %rdi
cmpl $0x2, %ebp
jl 0x309d
movl %edx, %r8d
leaq (,%r8,8), %r9
shlq $0x20, %r8
addq %rax, %r8
movq %rdi, %r10
imulq %rcx, %r10
xorpd %xmm0, %xmm0
xorpd %xmm1, %xmm1
addsd (%r14,%r9), %xmm1
movsd %xmm1, (%r12,%rsi,8)
addsd (%rbx,%r9), %xmm0
movsd %xmm0, (%r13,%rsi,8)
movq %r8, %r11
sarq $0x20, %r11
addq $0x8, %r9
addq %rax, %r8
cmpq %r10, %r11
jl 0x3071
addl %ebp, %edx
movq %rdi, %rsi
cmpq %r15, %rdi
jne 0x303c
movl $0xf4240, %edi          # imm = 0xF4240
callq 0x236bc
cvtsi2sd %ebp, %xmm7
movq %rax, 0x50(%rsp)
cvtsi2sdl 0x20(%rsp), %xmm0
movsd %xmm0, 0x60(%rsp)
movl 0x48(%rsp), %r14d
movq $0x0, 0x40(%rsp)
movsd 0x26f73(%rip), %xmm8    # 0x2a050
movl $0x0, 0xc(%rsp)
movq 0x38(%rsp), %rbp
movsd %xmm7, 0x10(%rsp)
testl %ebp, %ebp
jle 0x3215
xorpd %xmm6, %xmm6
xorl %ebp, %ebp
xorpd %xmm3, %xmm3
xorpd %xmm4, %xmm4
movsd (%r12,%rbp,8), %xmm1
ucomisd %xmm1, %xmm7
ja 0x31e9
movsd (%r13,%rbp,8), %xmm2
ucomisd %xmm2, %xmm7
ja 0x31e9
movsd %xmm3, 0x58(%rsp)
movsd %xmm6, 0x18(%rsp)
movapd %xmm4, 0x20(%rsp)
movapd %xmm1, %xmm0
movsd %xmm1, 0x70(%rsp)
movsd 0x60(%rsp), %xmm1
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %edi
movapd %xmm2, %xmm0
divsd %xmm1, %xmm0
cvttsd2si %xmm0, %esi
movq 0x50(%rsp), %rdx
movsd %xmm2, 0x68(%rsp)
callq 0x1ddb2
movsd 0x2982b(%rip), %xmm1    # 0x2c9a0
ucomisd %xmm0, %xmm1
movsd 0x70(%rsp), %xmm1
divsd 0x68(%rsp), %xmm1
jbe 0x31b6
ucomisd 0x26ed9(%rip), %xmm1    # 0x2a068
movsd 0x26eb8(%rip), %xmm8    # 0x2a050
movapd 0x20(%rsp), %xmm4
movsd 0x18(%rsp), %xmm6
movsd 0x58(%rsp), %xmm3
jbe 0x31f7
addsd 0x26e54(%rip), %xmm4    # 0x2a008
jmp 0x31e3
ucomisd 0x26eaa(%rip), %xmm1    # 0x2a068
movsd 0x26e89(%rip), %xmm8    # 0x2a050
movapd 0x20(%rsp), %xmm4
movsd 0x18(%rsp), %xmm6
movsd 0x58(%rsp), %xmm3
jbe 0x31e3
addsd 0x26e25(%rip), %xmm6    # 0x2a008
movsd 0x10(%rsp), %xmm7
incq %rbp
cmpq %rbp, %r15
jne 0x3106
jmp 0x3221
movsd 0x26e39(%rip), %xmm0    # 0x2a038
ucomisd %xmm1, %xmm0
movsd 0x10(%rsp), %xmm7
jbe 0x31e9
addsd 0x26df5(%rip), %xmm3    # 0x2a008
jmp 0x31e9
xorpd %xmm4, %xmm4
xorpd %xmm3, %xmm3
xorpd %xmm6, %xmm6
movapd %xmm4, %xmm1
addsd %xmm6, %xmm1
addsd %xmm3, %xmm4
testb $0x1, 0x40(%rsp)
jne 0x3259
movsd 0x26de4(%rip), %xmm2    # 0x2a020
movapd %xmm2, %xmm0
cmpltpd %xmm1, %xmm0
cmpltpd %xmm4, %xmm2
andpd %xmm0, %xmm2
movd %xmm2, %eax
andb $0x1, %al
movq %rax, 0x40(%rsp)
movq 0x38(%rsp), %rbp
movapd %xmm6, %xmm2
divsd %xmm1, %xmm2
movapd %xmm3, %xmm5
divsd %xmm4, %xmm5
cmpb $0x1, 0x35f55(%rip)     # 0x391ca
je 0x32fb
cmpl $0x1f4, 0xc(%rsp)       # imm = 0x1F4
je 0x334d
testb $0x1, 0x40(%rsp)
je 0x32ac
ucomisd 0x29710(%rip), %xmm2    # 0x2c9a8
ja 0x32ac
movsd 0x29706(%rip), %xmm0    # 0x2c9a8
ucomisd %xmm5, %xmm0
jbe 0x334d
cmpl $0x2, 0x48(%rsp)
jl 0x32cd
pushq $0x1
popq %rax
movsd (%rbx,%rax,8), %xmm0
addsd %xmm8, %xmm0
movsd %xmm0, (%rbx,%rax,8)
incq %rax
cmpq %rax, %r14
jne 0x32b6
testl %ebp, %ebp
jle 0x32f2
xorl %eax, %eax
movapd %xmm7, %xmm0
mulsd %xmm8, %xmm0
addsd (%r13,%rax,8), %xmm0
movsd %xmm0, (%r13,%rax,8)
incq %rax
cmpq %rax, %r15
jne 0x32d3
incl 0xc(%rsp)
jmp 0x30f0
movq 0x35cde(%rip), %rax     # 0x38fe0
movq (%rax), %rdi
leaq 0x2974b(%rip), %rsi     # 0x2ca57
movl 0xc(%rsp), %edx
movapd %xmm6, %xmm0
movsd %xmm2, 0x20(%rsp)
movsd 0x20(%rsp), %xmm2
movb $0x6, %al
movsd %xmm5, 0x18(%rsp)
callq 0x2250
movsd 0x18(%rsp), %xmm5
movsd 0x20(%rsp), %xmm2
movsd 0x26d0e(%rip), %xmm8    # 0x2a050
movsd 0x10(%rsp), %xmm7
jmp 0x327b
movq 0x35c8c(%rip), %rax     # 0x38fe0
movq (%rax), %rdi
leaq 0x29722(%rip), %rsi     # 0x2ca80
movl 0xc(%rsp), %edx
movapd %xmm2, %xmm0
movapd %xmm5, %xmm1
movb $0x2, %al
callq 0x2250
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x3380
callq 0x2220
movq %r12, %rdi
callq 0x2220
movq %r13, %rdi
callq 0x2220
movq %rbx, %rax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq