// File: /workspace/github_cpp_makefile_star2_O1/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 $0x58, %rsp
movl %ecx, 0x10(%rsp)
movl %edx, %r13d
movl %esi, %r15d
movq %rdi, %r14
cmpb $0x1, 0x37269(%rip)     # 0x3a1ca
jne 0x2f7e
movq 0x37076(%rip), %rax     # 0x39fe0
movq (%rax), %rdi
leaq 0x2aaac(%rip), %rsi     # 0x2da20
movl %r15d, %edx
xorl %eax, %eax
callq 0x2250
pushq $-0x1
popq %rcx
movq %r14, %rdi
movl %r15d, %esi
movl $0xf4240, %edx          # imm = 0xF4240
callq 0x130bd
movq %rax, %rbx
testl %r15d, %r15d
jle 0x2fc5
pushq $0x1
popq %rax
leal 0x1(%r15), %ecx
movsd 0x28060(%rip), %xmm0    # 0x2b008
movabsq $0x3ff0000000000000, %rdx # imm = 0x3FF0000000000000
ucomisd (%rbx,%rax,8), %xmm0
jbe 0x2fbd
movq %rdx, (%rbx,%rax,8)
incq %rax
cmpq %rax, %rcx
jne 0x2fb2
movq %r15, 0x38(%rsp)
movl %r15d, %eax
cltd
idivl %r13d
movl %eax, %ebp
cmpb $0x0, 0x371f0(%rip)     # 0x3a1ca
je 0x2ff6
movq 0x36ffd(%rip), %rax     # 0x39fe0
movq (%rax), %rdi
leaq 0x2aa5d(%rip), %rsi     # 0x2da4a
movl %ebp, %edx
xorl %eax, %eax
callq 0x2250
movslq %ebp, %rax
leaq 0x10(,%rax,8), %rax
cmpl $-0x2, %ebp
pushq $-0x1
popq %r12
cmovgeq %rax, %r12
movq %r12, %rdi
callq 0x2040
movq %rax, %r15
movq %r12, %rdi
callq 0x2040
movq %rax, %r12
movl %ebp, %eax
movl %ebp, %ebp
movl %eax, 0x2c(%rsp)
testl %eax, %eax
jle 0x30ad
movabsq $0x100000000, %rax      # imm = 0x100000000
movslq %r13d, %rcx
pushq $0x1
popq %rdx
xorl %esi, %esi
andq $0x0, (%r15,%rsi,8)
andq $0x0, (%r12,%rsi,8)
cmpl $0x2, %r13d
jl 0x30a2
movl %edx, %edi
leaq (,%rdi,8), %r8
shlq $0x20, %rdi
addq %rax, %rdi
movq %rsi, %r9
imulq %rcx, %r9
addq %rcx, %r9
movsd (%r15,%rsi,8), %xmm0
movsd (%r12,%rsi,8), %xmm1
addsd (%r14,%r8), %xmm0
movsd %xmm0, (%r15,%rsi,8)
addsd (%rbx,%r8), %xmm1
movsd %xmm1, (%r12,%rsi,8)
movq %rdi, %r10
sarq $0x20, %r10
addq $0x8, %r8
addq %rax, %rdi
cmpq %r9, %r10
jl 0x3077
incq %rsi
addl %r13d, %edx
cmpq %rbp, %rsi
jne 0x3040
movl $0xf4240, %edi          # imm = 0xF4240
callq 0x23bc5
cvtsi2sd %r13d, %xmm8
movq %rax, 0x40(%rsp)
cvtsi2sdl 0x10(%rsp), %xmm0
movsd %xmm0, 0x50(%rsp)
movl 0x38(%rsp), %r14d
movq $0x0, 0x30(%rsp)
movsd 0x27f6d(%rip), %xmm6    # 0x2b050
movl $0x0, 0xc(%rsp)
movl 0x2c(%rsp), %r13d
movsd %xmm8, 0x18(%rsp)
testl %r13d, %r13d
jle 0x320b
xorpd %xmm0, %xmm0
xorl %r13d, %r13d
xorpd %xmm3, %xmm3
xorpd %xmm4, %xmm4
movsd (%r15,%r13,8), %xmm5
ucomisd %xmm5, %xmm8
ja 0x31de
movsd (%r12,%r13,8), %xmm1
ucomisd %xmm1, %xmm8
ja 0x31de
movsd %xmm3, 0x48(%rsp)
movsd %xmm0, 0x20(%rsp)
movsd %xmm4, 0x10(%rsp)
movsd 0x50(%rsp), %xmm2
divsd %xmm2, %xmm5
cvttsd2si %xmm5, %edi
divsd %xmm2, %xmm1
cvttsd2si %xmm1, %esi
movq 0x40(%rsp), %rdx
callq 0x1e240
movsd 0x2a835(%rip), %xmm1    # 0x2d9a0
ucomisd %xmm0, %xmm1
movsd (%r15,%r13,8), %xmm2
divsd (%r12,%r13,8), %xmm2
jbe 0x31ab
ucomisd 0x27ee3(%rip), %xmm2    # 0x2b068
movsd 0x27ec3(%rip), %xmm6    # 0x2b050
movsd 0x10(%rsp), %xmm4
movsd 0x20(%rsp), %xmm0
movsd 0x48(%rsp), %xmm3
jbe 0x31ec
addsd 0x27e5f(%rip), %xmm4    # 0x2b008
jmp 0x31d7
ucomisd 0x27eb5(%rip), %xmm2    # 0x2b068
movsd 0x27e95(%rip), %xmm6    # 0x2b050
movsd 0x10(%rsp), %xmm4
movsd 0x20(%rsp), %xmm0
movsd 0x48(%rsp), %xmm3
jbe 0x31d7
addsd 0x27e31(%rip), %xmm0    # 0x2b008
movsd 0x18(%rsp), %xmm8
incq %r13
cmpq %r13, %rbp
jne 0x310f
jmp 0x3217
movsd 0x27e44(%rip), %xmm1    # 0x2b038
ucomisd %xmm2, %xmm1
movsd 0x18(%rsp), %xmm8
jbe 0x31de
addsd 0x27dff(%rip), %xmm3    # 0x2b008
jmp 0x31de
xorpd %xmm4, %xmm4
xorpd %xmm3, %xmm3
xorpd %xmm0, %xmm0
testb $0x1, 0x30(%rsp)
jne 0x3253
movapd %xmm4, %xmm7
addsd %xmm0, %xmm7
movapd %xmm4, %xmm1
addsd %xmm3, %xmm1
movsd 0x27dea(%rip), %xmm5    # 0x2b020
movapd %xmm5, %xmm2
cmpltpd %xmm7, %xmm2
cmpltpd %xmm1, %xmm5
andpd %xmm2, %xmm5
movd %xmm5, %eax
andb $0x1, %al
movq %rax, 0x30(%rsp)
movapd %xmm4, %xmm1
addsd %xmm0, %xmm1
movapd %xmm0, %xmm2
divsd %xmm1, %xmm2
addsd %xmm3, %xmm4
movapd %xmm3, %xmm5
divsd %xmm4, %xmm5
cmpb $0x1, 0x36f54(%rip)     # 0x3a1ca
movl 0x2c(%rsp), %r13d
je 0x32fb
cmpl $0x1f4, 0xc(%rsp)       # imm = 0x1F4
je 0x334f
testb $0x1, 0x30(%rsp)
je 0x32ae
ucomisd 0x2a70e(%rip), %xmm2    # 0x2d9a8
ja 0x32ae
movsd 0x2a704(%rip), %xmm0    # 0x2d9a8
ucomisd %xmm5, %xmm0
jbe 0x3356
cmpl $0x2, 0x38(%rsp)
jl 0x32ce
pushq $0x1
popq %rax
movsd (%rbx,%rax,8), %xmm0
addsd %xmm6, %xmm0
movsd %xmm0, (%rbx,%rax,8)
incq %rax
cmpq %rax, %r14
jne 0x32b8
testl %r13d, %r13d
jle 0x32f2
xorl %eax, %eax
movapd %xmm8, %xmm0
mulsd %xmm6, %xmm0
addsd (%r12,%rax,8), %xmm0
movsd %xmm0, (%r12,%rax,8)
incq %rax
cmpq %rax, %rbp
jne 0x32d5
incl 0xc(%rsp)
jmp 0x30f7
movq 0x36cde(%rip), %rax     # 0x39fe0
movq (%rax), %rdi
leaq 0x2a74b(%rip), %rsi     # 0x2da57
movl 0xc(%rsp), %edx
movsd %xmm2, 0x10(%rsp)
movsd 0x10(%rsp), %xmm2
movsd %xmm5, 0x20(%rsp)
movsd 0x20(%rsp), %xmm5
movb $0x6, %al
callq 0x2250
movsd 0x20(%rsp), %xmm5
movsd 0x10(%rsp), %xmm2
movsd 0x27d0d(%rip), %xmm6    # 0x2b050
movsd 0x18(%rsp), %xmm8
jmp 0x327d
movl $0x1f4, %edx            # imm = 0x1F4
jmp 0x335a
movl 0xc(%rsp), %edx
movq 0x36c7f(%rip), %rax     # 0x39fe0
movq (%rax), %rdi
leaq 0x2a715(%rip), %rsi     # 0x2da80
movapd %xmm2, %xmm0
movapd %xmm5, %xmm1
movb $0x2, %al
callq 0x2250
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x3389
callq 0x2220
movq %r15, %rdi
callq 0x2220
movq %r12, %rdi
callq 0x2220
movq %rbx, %rax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq