// File: /workspace/github_cpp_makefile_star2_O1/gersteinlab[P]MUSIC/src/ms_filter_utils.cpp
// Function: median_filter_data(double*, int, int, int)
double* median_filter_data(double* track_data,
	int l_track_data, 
	int l_averaging_win,
	int skip_value) // This is the value to be skipped from the window values.
{
	// Do copying from start to end.
    double* cur_filtered_track = new double[l_track_data + 2];

	int n_signal_wins = 0;
	int half_l_averaging = l_averaging_win / 2;

	// Set the maximum value for the histogram.
	int MAX_VAL = -1000*1000;
	int MIN_VAL = 1000*1000;
	for(int i_sig = 1; i_sig <= l_track_data; i_sig++)
	{
		if(MAX_VAL < (int)(track_data[i_sig]))
		{
			MAX_VAL = (int)(track_data[i_sig]);
		}

		if(MIN_VAL > (int)(track_data[i_sig]))
		{
			MIN_VAL = (int)(track_data[i_sig]);
		}
	} // i_sig loop.

	// Make sure that this is the maximum.
	MAX_VAL += 1000;
	MIN_VAL -= 1000;
		
	// Initialize the current pdf.
	int* cur_win_pdf = NULL;
	int cur_win_max = 0;
	int cur_win_min = 1000*1000;
	double* cur_win_vals = new double[l_averaging_win + 2];
	int prev_avg_start = 0;
	int prev_avg_end = 0;

	// Go over all the positions as the middle of the filtering window.
	for(int cur_win_mid = 1; cur_win_mid <= l_track_data; cur_win_mid++)
	{
		int cur_avg_start = (cur_win_mid > half_l_averaging)?(cur_win_mid - half_l_averaging):(1);
		int cur_avg_end = (cur_win_mid + half_l_averaging <= l_track_data)?(cur_win_mid + half_l_averaging):(l_track_data);
		if(cur_win_pdf == NULL)
		{
			cur_win_pdf = new int[MAX_VAL - MIN_VAL+ 2];
			memset(cur_win_pdf, 0, sizeof(int) * (MAX_VAL - MIN_VAL + 1));
			//t_string::set_byte_buffer(cur_win_pdf, sizeof(int) * (MAX_VAL - MIN_VAL + 1), 0);
			cur_win_pdf -= MIN_VAL;

			// Generate the pdf, get the minimum and maximum in the current window.
			for(int i = cur_avg_start; i <= cur_avg_end; i++)
			{
				if(track_data[i] != skip_value)
				{
					cur_win_pdf[(int)(track_data[i])]++;

					if(cur_win_max < track_data[i])
					{
						cur_win_max = (int)track_data[i];
					}
					
					if(cur_win_min > track_data[i])
					{
						cur_win_min = (int)track_data[i];
					}
				} // skip_Value check.
			} // i loop.
		} // cur_win_pdf is NULL check.
		else
		{
			// Remove the old values from the pdf, add the new values.
			for(int i = prev_avg_start; i < cur_avg_start; i++)
			{
				if(track_data[i] != skip_value)
				{
					cur_win_pdf[(int)(track_data[i])]--;
				}
			} // i loop.

			// Update the min and max only for the values that are new in this window.
			for(int i = prev_avg_end+1; i <= cur_avg_end; i++)
			{
				if(track_data[i] != skip_value)
				{
					cur_win_pdf[(int)(track_data[i])]++;

					if(cur_win_max < track_data[i])
					{
						cur_win_max = (int)track_data[i];
					}
					
					if(cur_win_min > track_data[i])
					{
						cur_win_min = (int)track_data[i];
					}
				} // skip_value check.
			}

			// Sanity Check: The total # of points must be equal to the window length.
			int n_total_pts = 0;
			for(int i = cur_win_min; i <= cur_win_max; i++)
			{
				if(i != skip_value)
				{
					n_total_pts += cur_win_pdf[i];
				}
			} // i loop.
		} // cur_win_pdf is NULL check.

		// Count the total number of points without the skip value.
		int n_total = 0;
		for(int i = cur_win_min; i <= cur_win_max; i++)
		{
			if(i != skip_value)
			{
				n_total += cur_win_pdf[i];
			}
		} // i loop.
		
		// Generate the window median.
		int cur_win_median = 0;
		int n_cur_total = 0;
		for(int i = cur_win_min; i <= cur_win_max; i++)
		{
			if(i != skip_value)
			{
				n_cur_total += cur_win_pdf[i];
				if(n_cur_total > n_total/2)
				{
					// We found the median, can break out of the loop.
					cur_win_median = i;
					break;
				}
			}
		} // i loop.

		// Track the minimum and maximum from the histogram to update them for the current window.
		int updated_win_min = 0;			
		for(int i = cur_win_min; i <= cur_win_max; i++)
		{
			if(i != skip_value)
			{
				if(cur_win_pdf[i] > 0)
				{
					updated_win_min = i;
					break;
				}
			} // skip_value check.
		} // i loop.

		int updated_win_max = 0;
		for(int i = cur_win_max; i >= cur_win_min; i--)
		{
			if(i != skip_value)
			{
				if(cur_win_pdf[i] > 0)
				{
					updated_win_max = i;
					break;
				}
			} // skip_value check.
		} // i loop.

		// Set the median.
		//int median_per_pdf = cur_win_median;
		cur_filtered_track[cur_win_mid] = cur_win_median;

		// Update the previous averaging window limits.
		prev_avg_start = cur_avg_start;
		prev_avg_end = cur_avg_end;
		cur_win_min = updated_win_min;
		cur_win_max = updated_win_max;

#undef _QSORT_CHECK_
#ifdef _QSORT_CHECK_
		// Get the median via qsort and compare as a sanity check.
		int n_valid_vals = 0;
		for(int i = cur_avg_start; i <= cur_avg_end; i++)
		{
			if(track_data[i] != skip_value)
			{
				cur_win_vals[n_valid_vals] = track_data[i];
				n_valid_vals++;
			}
		} // i loop.
		qsort(cur_win_vals, n_valid_vals, sizeof(double), sort_doubles_descending);
		//per_win_profile[n_signal_wins] = cur_win_vals[l_averaging_win/2];

		if(cur_win_vals[n_valid_vals/2] != median_per_pdf)
		{
			fprintf(stderr, "Medians do not match: %d, %d:\n", (int)cur_win_vals[n_valid_vals/2], median_per_pdf);
			for(int i = cur_avg_start; i <= cur_avg_end; i++)
			{
				fprintf(stderr, "%lf ", track_data[i]);
			} // i loop.
			fprintf(stderr, "\n");
			getc(stdin);
		}
#endif // _QSORT_CHECK_

		n_signal_wins++;
	} // main signal filtering loop.

	// Free pdf memory.
	delete [] cur_win_vals;
	delete [] (cur_win_pdf+MIN_VAL);

	return(cur_filtered_track);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movl %ecx, %ebp
movl %edx, %r12d
movl %esi, %r14d
movq %rdi, %r15
movslq %esi, %rbx
leaq 0x10(,%rbx,8), %rax
cmpl $-0x2, %ebx
movq $-0x1, %rdi
cmovgeq %rax, %rdi
callq 0x2040
movq %rax, 0x28(%rsp)
testl %ebx, %ebx
jle 0x132b0
leal 0x1(%r14), %edx
movl $0xf4240, %edi          # imm = 0xF4240
movl $0xfff0bdc0, %eax       # imm = 0xFFF0BDC0
movl $0x1, %esi
movq %r14, %r11
cvttsd2si (%r15,%rsi,8), %ecx
cmpl %ecx, %eax
cmovlel %ecx, %eax
cmpl %ecx, %edi
cmovll %edi, %ecx
incq %rsi
movl %ecx, %edi
cmpq %rsi, %rdx
jne 0x13294
jmp 0x132bd
movl $0xfff0bdc0, %eax       # imm = 0xFFF0BDC0
movl $0xf4240, %ecx          # imm = 0xF4240
movq %r14, %r11
leal -0x3e8(%rcx), %edx
movslq %edx, %rdi
testl %r11d, %r11d
movq %rdi, 0x30(%rsp)
jle 0x135f7
movl %r12d, %edx
shrl $0x1f, %edx
addl %r12d, %edx
sarl %edx
cvtsi2sd %ebp, %xmm2
subl %ecx, %eax
leal 0x7d0(%rax), %ecx
leal 0x7d2(%rax), %esi
movslq %esi, %rsi
shlq $0x2, %rsi
cmpl $-0x2, %ecx
movq $-0x1, %rcx
cmovgeq %rsi, %rcx
movq %rcx, 0x48(%rsp)
addl $0x7d1, %eax            # imm = 0x7D1
cltq
shlq $0x2, %rax
movq %rax, 0x40(%rsp)
negq %rdi
movq %rdi, 0x38(%rsp)
movslq %edx, %rax
movq %rax, 0x58(%rsp)
leal 0x1(%r11), %eax
movq %rax, 0x50(%rsp)
movslq %ebp, %rbx
movq %rbx, 0x18(%rsp)
negq %rbx
movl $0xf4240, %r12d         # imm = 0xF4240
movl $0x1, %r14d
xorl %r8d, %r8d
xorl %r13d, %r13d
xorl %eax, %eax
movq %r11, 0x8(%rsp)
xorl %ebp, %ebp
movsd %xmm2, 0x20(%rsp)
movl %r8d, %edx
movl %ebp, %ecx
movl %r14d, %r8d
movq 0x58(%rsp), %rsi
subl %esi, %r8d
cmpq %rsi, %r14
movl $0x1, %edi
cmovlel %edi, %r8d
leal (%rsi,%r14), %ebp
cmpl %r11d, %ebp
cmovgel %r11d, %ebp
testq %rax, %rax
movl %r8d, 0x4(%rsp)
je 0x13415
cmpl %r8d, %edx
jge 0x133c0
movslq %edx, %rdx
movslq %r8d, %rsi
movsd (%r15,%rdx,8), %xmm0
ucomisd %xmm2, %xmm0
jne 0x133ae
jnp 0x133b8
cvttsd2si %xmm0, %edi
movslq %edi, %rdi
decl (%rax,%rdi,4)
incq %rdx
cmpq %rdx, %rsi
jne 0x133a0
cmpl %ebp, %ecx
jge 0x134bb
movslq %ecx, %rcx
movslq %ebp, %rdx
movsd 0x8(%r15,%rcx,8), %xmm0
ucomisd %xmm2, %xmm0
jne 0x133dd
jnp 0x13408
cvttsd2si %xmm0, %esi
movslq %esi, %rdi
incl (%rax,%rdi,4)
xorps %xmm1, %xmm1
cvtsi2sd %r13d, %xmm1
ucomisd %xmm1, %xmm0
cmoval %edi, %r13d
xorps %xmm1, %xmm1
cvtsi2sd %r12d, %xmm1
ucomisd %xmm0, %xmm1
jbe 0x13408
movl %esi, %r12d
incq %rcx
cmpq %rdx, %rcx
jl 0x133ce
jmp 0x134bb
movq 0x48(%rsp), %rdi
callq 0x2040
movq %rbp, 0x10(%rsp)
movq %rax, %rbp
movq %rax, %rdi
xorl %esi, %esi
movq 0x40(%rsp), %rdx
callq 0x20f0
movl 0x4(%rsp), %r8d
movq 0x38(%rsp), %rax
leaq (,%rax,4), %rax
addq %rbp, %rax
movq 0x10(%rsp), %rbp
cmpl %ebp, %r8d
jle 0x13465
movl %r12d, %edx
movq 0x8(%rsp), %r11
movsd 0x20(%rsp), %xmm2
jmp 0x134be
movslq %r8d, %rcx
movslq %ebp, %rdx
decq %rcx
movq 0x8(%rsp), %r11
movsd 0x20(%rsp), %xmm2
movsd 0x8(%r15,%rcx,8), %xmm0
ucomisd %xmm2, %xmm0
jne 0x13488
jnp 0x134b3
cvttsd2si %xmm0, %esi
movslq %esi, %rdi
incl (%rax,%rdi,4)
xorps %xmm1, %xmm1
cvtsi2sd %r13d, %xmm1
ucomisd %xmm1, %xmm0
cmoval %edi, %r13d
xorps %xmm1, %xmm1
cvtsi2sd %r12d, %xmm1
ucomisd %xmm0, %xmm1
jbe 0x134b3
movl %esi, %r12d
incq %rcx
cmpq %rdx, %rcx
jl 0x13479
movl %r12d, %edx
xorl %edi, %edi
movslq %edx, %rcx
cmpl %r13d, %edx
jg 0x13504
movq 0x18(%rsp), %rsi
subq %rcx, %rsi
leaq (%rax,%rcx,4), %rdi
movl %r13d, %r8d
subl %ecx, %r8d
incl %r8d
xorl %r10d, %r10d
xorl %r9d, %r9d
cmpq %r10, %rsi
je 0x134ec
addl (%rdi,%r10,4), %r9d
incq %r10
cmpl %r10d, %r8d
jne 0x134e3
movl %r9d, %edi
shrl $0x1f, %edi
addl %r9d, %edi
sarl %edi
movl 0x4(%rsp), %r8d
xorpd %xmm0, %xmm0
movl %edx, %r10d
movl %r13d, %esi
notl %esi
cmpl %r13d, %edx
movq %r10, 0x60(%rsp)
jg 0x13568
movq %rbp, 0x10(%rsp)
movq 0x18(%rsp), %r9
subq %rcx, %r9
leaq (%rax,%rcx,4), %r11
leaq (%rsi,%r10), %r12
xorl %r10d, %r10d
xorl %ebp, %ebp
cmpq %r10, %r9
je 0x13541
addl (%r11,%r10,4), %ebp
cmpl %edi, %ebp
jg 0x1354e
incq %r10
movl %r12d, %r8d
addl %r10d, %r8d
jne 0x13534
jmp 0x13559
addl %edx, %r10d
xorps %xmm0, %xmm0
cvtsi2sd %r10d, %xmm0
movq 0x8(%rsp), %r11
movq 0x10(%rsp), %rbp
movl 0x4(%rsp), %r8d
xorl %edi, %edi
movl $0x0, %r12d
cmpl %r13d, %edx
jg 0x135ad
movq 0x18(%rsp), %r9
subq %rcx, %r9
leaq (%rax,%rcx,4), %r10
addq 0x60(%rsp), %rsi
xorl %r12d, %r12d
cmpq %r12, %r9
je 0x13595
cmpl $0x0, (%r10,%r12,4)
jg 0x135a5
incq %r12
movl %esi, %r8d
addl %r12d, %r8d
jne 0x13589
xorl %r12d, %r12d
jmp 0x135a8
addl %edx, %r12d
movl 0x4(%rsp), %r8d
cmpl %edx, %r13d
jl 0x135d9
movslq %r13d, %rdx
incq %rdx
leaq (%rbx,%rdx), %rsi
cmpq $0x1, %rsi
je 0x135c9
cmpl $0x0, -0x4(%rax,%rdx,4)
jg 0x135d6
decl %r13d
decq %rdx
cmpq %rcx, %rdx
jg 0x135b8
jmp 0x135d9
movl %r13d, %edi
movq 0x28(%rsp), %rcx
movsd %xmm0, (%rcx,%r14,8)
incq %r14
movl %edi, %r13d
cmpq 0x50(%rsp), %r14
jne 0x13360
jmp 0x135f9
xorl %eax, %eax
testq %rax, %rax
je 0x1360c
movq 0x30(%rsp), %rcx
leaq (%rax,%rcx,4), %rdi
callq 0x2220
movq 0x28(%rsp), %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq