// File: gersteinlab[P]MUSIC/src/ms_peak_calling_utils.cpp
// Function: get_trough_posn_per_ER(double*, int, double*, int, double, int, int, int)
int get_trough_posn_per_ER(double* signal_profile, int l_profile, 
							double* multi_mapp_signal, int l_multi_map_signal, double max_multi_mapp_val,
							int ER_start, int ER_end,
							int l_trough_win)
{
	//vector<int>* maxima_posns = new vector<int>();
	//double min_max_val = 0.0;

	vector<t_extrema_node*>* maxima_nodes = new vector<t_extrema_node*>();
	vector<t_extrema_node*>* minima_nodes = new vector<t_extrema_node*>();
	int* derivative_map = new int[ER_end - ER_start + 2];
	memset(derivative_map, 0, sizeof(int) * (ER_end - ER_start + 2));
	get_extrema_per_plateaus(&signal_profile[ER_start], ER_end-ER_start+1, maxima_nodes, minima_nodes, derivative_map, 0);

	if((int)maxima_nodes->size() == 0 ||
		(int)minima_nodes->size() == 0)
	{
		return(0);
	}

	sort(maxima_nodes->begin(), maxima_nodes->end(), sort_extremas_per_decreasing_height);

	// Sort the minima with increasing height then take the top minima.
	sort(minima_nodes->begin(), minima_nodes->end(), sort_extremas_per_height);

	// Start from the top minimum and check if it is around one of the top maxima.
	vector<int>* rank_sum_per_minimum = new vector<int>();
	for(int i_min = 0; i_min < (int)minima_nodes->size(); i_min++)
	{
		t_extrema_node* prev_max = NULL;
		t_extrema_node* next_max = NULL;
		int prev_max_rank = 0;
		int next_max_rank = 0;

		for(int i_max = 0; i_max < (int)maxima_nodes->size(); i_max++)
		{
			if(prev_max == NULL &&
				maxima_nodes->at(i_max)->extrema_posn < minima_nodes->at(i_min)->extrema_posn)
			{
				prev_max_rank = i_max;
				prev_max = maxima_nodes->at(i_max);
			}

			if(next_max == NULL &&
				maxima_nodes->at(i_max)->extrema_posn > minima_nodes->at(i_min)->extrema_posn)
			{
				next_max_rank = i_max;
				next_max = maxima_nodes->at(i_max);
			}
		} // i_max loop.

		if(prev_max == NULL ||
			next_max == NULL)
		{
			rank_sum_per_minimum->push_back((int)maxima_nodes->size() + (int)maxima_nodes->size() + (int)minima_nodes->size());
			continue;
		}

		double total_multi_mapp_signal = 0;
		if(multi_mapp_signal != NULL)
		{
            for(int i = MAX(0, minima_nodes->at(i_min)->extrema_posn-l_trough_win/2); 
				i < MIN(l_multi_map_signal-1, minima_nodes->at(i_min)->extrema_posn+l_trough_win/2); i++)
            {
                total_multi_mapp_signal += multi_mapp_signal[ER_start+i];
            } // i loop.

			//for(int i = prev_max->extrema_posn; i <= next_max->extrema_posn; i++)
			//{
			//	total_multi_mapp_signal += multi_mapp_signal[ER_start+i];
			//} // i loop.
		}

		// Make sure that the region in this trough is mappable.
		// total_multi_mapp_signal / (next_max->extrema_posn - prev_max->extrema_posn+1) < max_multi_mapp_val)
		if(multi_mapp_signal == NULL ||
			total_multi_mapp_signal / l_trough_win < max_multi_mapp_val)
		{
			rank_sum_per_minimum->push_back(i_min + prev_max_rank + next_max_rank);
		}
		else
		{
			rank_sum_per_minimum->push_back((int)maxima_nodes->size() + (int)maxima_nodes->size() + (int)minima_nodes->size());
		}
	} // i_min loop.

	// Check on the number of rank sums that are generated.
	if(rank_sum_per_minimum->size() != minima_nodes->size())
	{
		fprintf(stderr, "The sanity check failed, per minimum rank sum count does not match the minima positions.\n");
		exit(0);
	}

	// Find the minimum with smallest rank-sum statistic.
	int smallest_rank_sum_stat = (int)maxima_nodes->size() + (int)maxima_nodes->size() + (int)minima_nodes->size();
	int smallest_rank_sum_min_i = 0;
	for(int i_min = 0; i_min < (int)rank_sum_per_minimum->size(); i_min++)
	{
		if(smallest_rank_sum_stat > rank_sum_per_minimum->at(i_min))
		{
			smallest_rank_sum_stat = rank_sum_per_minimum->at(i_min);
			smallest_rank_sum_min_i = i_min;
		}
	} // i_min loop.

	// This position is with respect to the beginning of the ER. Since extrema are with respect to begining of the ER, translate this coordinate.
	int trough_posn = minima_nodes->at(smallest_rank_sum_min_i)->extrema_posn + ER_start;

	delete_extrema_nodes(minima_nodes);
	delete_extrema_nodes(maxima_nodes);

	// Free the current decomposition.
	delete [] derivative_map;

	return(trough_posn);
}

// Assembly:
subq $0x158, %rsp            # imm = 0x158
movl 0x160(%rsp), %eax
movq %rdi, 0x148(%rsp)
movl %esi, 0x144(%rsp)
movq %rdx, 0x138(%rsp)
movl %ecx, 0x134(%rsp)
movsd %xmm0, 0x128(%rsp)
movl %r8d, 0x124(%rsp)
movl %r9d, 0x120(%rsp)
movl $0x18, %edi
callq 0x2190
movq %rax, %rdi
movq %rdi, 0x80(%rsp)
xorl %esi, %esi
movl $0x18, %edx
callq 0x2110
movq 0x80(%rsp), %rdi
callq 0x1ae90
movq 0x80(%rsp), %rax
movq %rax, 0x118(%rsp)
movl $0x18, %edi
callq 0x2190
movq %rax, %rdi
movq %rdi, 0x88(%rsp)
xorl %esi, %esi
movl $0x18, %edx
callq 0x2110
movq 0x88(%rsp), %rdi
callq 0x1ae90
movq 0x88(%rsp), %rax
movq %rax, 0x110(%rsp)
movl 0x120(%rsp), %eax
subl 0x124(%rsp), %eax
addl $0x2, %eax
cltq
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x2040
movq %rax, 0x108(%rsp)
movq 0x108(%rsp), %rdi
movl 0x120(%rsp), %eax
subl 0x124(%rsp), %eax
addl $0x2, %eax
movslq %eax, %rdx
shlq $0x2, %rdx
xorl %esi, %esi
callq 0x2110
movq 0x148(%rsp), %rdi
movslq 0x124(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rdi
movl 0x120(%rsp), %esi
subl 0x124(%rsp), %esi
addl $0x1, %esi
movq 0x118(%rsp), %rdx
movq 0x110(%rsp), %rcx
movq 0x108(%rsp), %r8
xorl %r9d, %r9d
callq 0x409a0
movq 0x118(%rsp), %rdi
callq 0x1aea0
cmpl $0x0, %eax
je 0x199e0
movq 0x110(%rsp), %rdi
callq 0x1aea0
cmpl $0x0, %eax
jne 0x199f0
movl $0x0, 0x154(%rsp)
jmp 0x1a0de
movq 0x118(%rsp), %rdi
callq 0x1af10
movq %rax, 0x100(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1af40
movq %rax, 0xf8(%rsp)
movq 0x100(%rsp), %rdi
movq 0xf8(%rsp), %rsi
leaq 0x2804f(%rip), %rdx     # 0x41a80
callq 0x1aec0
movq 0x110(%rsp), %rdi
callq 0x1af10
movq %rax, 0xf0(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1af40
movq %rax, 0xe8(%rsp)
movq 0xf0(%rsp), %rdi
movq 0xe8(%rsp), %rsi
leaq 0x28039(%rip), %rdx     # 0x41ab0
callq 0x1aec0
movl $0x18, %edi
callq 0x2190
movq %rax, %rdi
movq %rdi, 0x78(%rsp)
xorl %esi, %esi
movl $0x18, %edx
callq 0x2110
movq 0x78(%rsp), %rdi
callq 0xc290
movq 0x78(%rsp), %rax
movq %rax, 0xe0(%rsp)
movl $0x0, 0xdc(%rsp)
movl 0xdc(%rsp), %eax
movl %eax, 0x74(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x74(%rsp), %eax
cmpl %ecx, %eax
jge 0x19f36
movq $0x0, 0xd0(%rsp)
movq $0x0, 0xc8(%rsp)
movl $0x0, 0xc4(%rsp)
movl $0x0, 0xc0(%rsp)
movl $0x0, 0xbc(%rsp)
movl 0xbc(%rsp), %eax
movl %eax, 0x70(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x70(%rsp), %eax
cmpl %ecx, %eax
jge 0x19c4f
cmpq $0x0, 0xd0(%rsp)
jne 0x19bbd
movq 0x118(%rsp), %rdi
movslq 0xbc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %eax
movl %eax, 0x6c(%rsp)
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq %rax, %rcx
movl 0x6c(%rsp), %eax
movq (%rcx), %rcx
cmpl (%rcx), %eax
jge 0x19bbd
movl 0xbc(%rsp), %eax
movl %eax, 0xc4(%rsp)
movq 0x118(%rsp), %rdi
movslq 0xbc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movq %rax, 0xd0(%rsp)
cmpq $0x0, 0xc8(%rsp)
jne 0x19c37
movq 0x118(%rsp), %rdi
movslq 0xbc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %eax
movl %eax, 0x68(%rsp)
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq %rax, %rcx
movl 0x68(%rsp), %eax
movq (%rcx), %rcx
cmpl (%rcx), %eax
jle 0x19c37
movl 0xbc(%rsp), %eax
movl %eax, 0xc0(%rsp)
movq 0x118(%rsp), %rdi
movslq 0xbc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movq %rax, 0xc8(%rsp)
jmp 0x19c39
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xbc(%rsp)
jmp 0x19b1c
cmpq $0x0, 0xd0(%rsp)
je 0x19c65
cmpq $0x0, 0xc8(%rsp)
jne 0x19cd1
movq 0xe0(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movl %eax, 0x54(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x54(%rsp), %eax
addl %ecx, %eax
movl %eax, 0x64(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1aea0
movq 0x58(%rsp), %rdi
movq %rax, %rcx
movl 0x64(%rsp), %eax
addl %ecx, %eax
movl %eax, 0xb8(%rsp)
leaq 0xb8(%rsp), %rsi
callq 0xc420
jmp 0x19f20
xorps %xmm0, %xmm0
movsd %xmm0, 0xb0(%rsp)
cmpq $0x0, 0x138(%rsp)
je 0x19e54
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %ecx
movl 0x160(%rsp), %eax
movl $0x2, %esi
cltd
idivl %esi
subl %eax, %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jle 0x19d25
xorl %eax, %eax
movl %eax, 0x50(%rsp)
jmp 0x19d5e
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %eax
movl %eax, 0x4c(%rsp)
movl 0x160(%rsp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl 0x4c(%rsp), %eax
subl %ecx, %eax
movl %eax, 0x50(%rsp)
movl 0x50(%rsp), %eax
movl %eax, 0xac(%rsp)
movl 0xac(%rsp), %eax
movl %eax, 0x44(%rsp)
movl 0x134(%rsp), %eax
subl $0x1, %eax
movl %eax, 0x48(%rsp)
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %ecx
movl 0x160(%rsp), %eax
movl $0x2, %esi
cltd
idivl %esi
movl %eax, %edx
movl 0x48(%rsp), %eax
addl %edx, %ecx
cmpl %ecx, %eax
jle 0x19df2
movq 0x110(%rsp), %rdi
movslq 0xdc(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %eax
movl %eax, 0x3c(%rsp)
movl 0x160(%rsp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movl 0x3c(%rsp), %eax
addl %ecx, %eax
movl %eax, 0x40(%rsp)
jmp 0x19e00
movl 0x134(%rsp), %eax
subl $0x1, %eax
movl %eax, 0x40(%rsp)
movl 0x44(%rsp), %eax
movl 0x40(%rsp), %ecx
cmpl %ecx, %eax
jge 0x19e52
movq 0x138(%rsp), %rax
movl 0x124(%rsp), %ecx
addl 0xac(%rsp), %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
addsd 0xb0(%rsp), %xmm0
movsd %xmm0, 0xb0(%rsp)
movl 0xac(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xac(%rsp)
jmp 0x19d69
jmp 0x19e54
cmpq $0x0, 0x138(%rsp)
je 0x19e84
movsd 0xb0(%rsp), %xmm1
cvtsi2sdl 0x160(%rsp), %xmm0
divsd %xmm0, %xmm1
movsd 0x128(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x19eb7
movq 0xe0(%rsp), %rdi
movl 0xdc(%rsp), %eax
addl 0xc4(%rsp), %eax
addl 0xc0(%rsp), %eax
movl %eax, 0xa8(%rsp)
leaq 0xa8(%rsp), %rsi
callq 0xc420
jmp 0x19f1e
movq 0xe0(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movl %eax, 0x2c(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x2c(%rsp), %eax
addl %ecx, %eax
movl %eax, 0x38(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1aea0
movq 0x30(%rsp), %rdi
movq %rax, %rcx
movl 0x38(%rsp), %eax
addl %ecx, %eax
movl %eax, 0xa4(%rsp)
leaq 0xa4(%rsp), %rsi
callq 0xc420
jmp 0x19f20
movl 0xdc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xdc(%rsp)
jmp 0x19abc
movq 0xe0(%rsp), %rdi
callq 0xc2a0
movq %rax, 0x20(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movq 0x20(%rsp), %rax
cmpq %rcx, %rax
je 0x19f81
movq 0x4b077(%rip), %rax     # 0x64fe0
movq (%rax), %rdi
leaq 0x3b64c(%rip), %rsi     # 0x555bf
movb $0x0, %al
callq 0x2250
xorl %edi, %edi
callq 0x21f0
movq 0x118(%rsp), %rdi
callq 0x1aea0
movl %eax, 0x18(%rsp)
movq 0x118(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x18(%rsp), %eax
addl %ecx, %eax
movl %eax, 0x1c(%rsp)
movq 0x110(%rsp), %rdi
callq 0x1aea0
movq %rax, %rcx
movl 0x1c(%rsp), %eax
addl %ecx, %eax
movl %eax, 0xa0(%rsp)
movl $0x0, 0x9c(%rsp)
movl $0x0, 0x98(%rsp)
movl 0x98(%rsp), %eax
movl %eax, 0x14(%rsp)
movq 0xe0(%rsp), %rdi
callq 0xc2a0
movq %rax, %rcx
movl 0x14(%rsp), %eax
cmpl %ecx, %eax
jge 0x1a071
movl 0xa0(%rsp), %eax
movl %eax, 0x10(%rsp)
movq 0xe0(%rsp), %rdi
movslq 0x98(%rsp), %rsi
callq 0xc2c0
movq %rax, %rcx
movl 0x10(%rsp), %eax
cmpl (%rcx), %eax
jle 0x1a059
movq 0xe0(%rsp), %rdi
movslq 0x98(%rsp), %rsi
callq 0xc2c0
movl (%rax), %eax
movl %eax, 0xa0(%rsp)
movl 0x98(%rsp), %eax
movl %eax, 0x9c(%rsp)
jmp 0x1a05b
movl 0x98(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x98(%rsp)
jmp 0x19fdf
movq 0x110(%rsp), %rdi
movslq 0x9c(%rsp), %rsi
callq 0x1af70
movq (%rax), %rax
movl (%rax), %eax
addl 0x124(%rsp), %eax
movl %eax, 0x94(%rsp)
movq 0x110(%rsp), %rdi
callq 0x41ae0
movq 0x118(%rsp), %rdi
callq 0x41ae0
movq 0x108(%rsp), %rax
movq %rax, 0x8(%rsp)
cmpq $0x0, %rax
je 0x1a0d0
movq 0x8(%rsp), %rdi
callq 0x2220
movl 0x94(%rsp), %eax
movl %eax, 0x154(%rsp)
movl 0x154(%rsp), %eax
addq $0x158, %rsp            # imm = 0x158
retq
nopl (%rax)