// File: /workspace/github_cpp_makefile_star2_O2/ADAPTLab[P]MuDBSCAN/MuC_RTree.cpp
// Function: findNeighbours3(dataHdr*, int, double, std::vector<std::vector<int, std::allocator<int>>, std::allocator<std::vector<int, std::allocator<int>>>>*)
Neighbours findNeighbours3(DataHdr dataList, int pointid, double eps, vector < vector <int > >* p_cur_insert)
{

	findNeighbourCount++;
	Data point = dataList->dataClstElem + pointid;

	// if(point->haloPoint == TRUE)
	// {
	// 	fprintf(stderr, "Unexpected condition! FindNeighbours called on Remote Point!");
	// 	exit(-1);
	// }

	Group group = groupList->groupItems[point->group_id];

	Neighbours n = (Neighbours)calloc(1, sizeof(struct neighbours));
	// assert(n != NULL);
	
	n->id = pointid;

	n->neighbours_local_outer = (vectorc*)malloc(sizeof(struct vectorc));
	// assert(n->neighbours_local != NULL);
	VECTOR_INIT(n->neighbours_local_outer, INTEGER);

	n->neighbours_remote_outer = (vectorc*)malloc(sizeof(struct vectorc));
	// assert(n->neighbours_remote != NULL);
	VECTOR_INIT(n->neighbours_remote_outer, INTEGER);

	n->neighbours_local_inner=(vectorc*)malloc(sizeof(struct vectorc));
	// assert(n->neighbours_local_distance != NULL);
	VECTOR_INIT(n->neighbours_local_inner, INTEGER);

	n->neighbours_remote_inner = (vectorc*)malloc(sizeof(struct vectorc));
	// assert(n->neighbours_remote_distance != NULL);
	VECTOR_INIT(n->neighbours_remote_inner, INTEGER);

	Region region = createCellRegOfPoint(point, eps);
	Region potentialRegion;

	int inner_neighbours = 0;
	int total_neighbours = 0;
	double two = 2;
	Data temp;

	int i=0, j=0;

	//FIRST SEARCH FOR NEIGHBOURS IN THE PRESENT GROUP.
	RHdrNd hdrNdTree = group->bcell->auxCellRTree;
	findNeighboursGroup(hdrNdTree, region, point, n, eps);
	int p;
	i=0;

	// if(VECTOR_TOTAL(n->neighbours_local) != VECTOR_TOTAL(n->neighbours_local_distance) || VECTOR_TOTAL(n->neighbours_remote) != VECTOR_TOTAL(n->neighbours_remote_distance))
	// {
	// 	fprintf(stderr, "findNeighbours3 doesn't not conform to the standard!\n");
	// 	exit(-1);
	// }

	//THEN SEARCH FOR NEIGHBOURS IN THE FILTERED REACHABLE GROUPS
	Group reachableGroup,filteredGroup;
	DataPoint d;
	for(i=0; i<VECTOR_TOTAL(group->reachable_groups); i++)
	{
		int id = group->reachable_groups->intItems[i];
		Group reachableGroup = groupList->groupItems[id];
		DataPoint d = (dataList->dataClstElem + reachableGroup->master_id)->iData;
		potentialRegion = createCellRegOfDataPoint(d, eps);

		if(GisOverLap(region, potentialRegion))
		{
			filteredGroup = groupList->groupItems[id];
			j=0;
			hdrNdTree = filteredGroup->bcell->auxCellRTree;
			findNeighboursGroup(hdrNdTree, region, point, n, eps);
		}

		free(potentialRegion->iBottomLeft);
		free(potentialRegion->iTopRight);
		free(potentialRegion);
	}

	inner_neighbours = VECTOR_TOTAL(n->neighbours_remote_inner) + VECTOR_TOTAL(n->neighbours_local_inner);
	total_neighbours = VECTOR_TOTAL(n->neighbours_remote_outer) + VECTOR_TOTAL(n->neighbours_local_outer) + inner_neighbours;

	if(inner_neighbours >= MINPOINTS)
	{
		if(point->haloPoint == FALSE && point->core_tag == FALSE) totalCore++;

		point->core_tag = TRUE;
		point->ClusterID = 1;
		point->isProcessed = TRUE;

		Group g = groupList->groupItems[point->group_id];

		if(visited[point->id] != 1)
        {
            visited[point->id] = 1;
            addHelper[0] = point->id;
            VECTOR_ADD(g->corepoints, addHelper);
            VECTOR_ADD(unprocessedCore, addHelper);
        }

        int root = point->id;
        Data data;
        Data dataroot1;
        Data dataroot2;
        for(i=0;i<VECTOR_TOTAL(n->neighbours_local_inner);i++)
        {
			data = dataList->dataClstElem + n->neighbours_local_inner->intItems[i];
			if(data->haloPoint == FALSE && data->core_tag == FALSE) totalCore++;
			
			data->core_tag = TRUE;
			data->isProcessed = TRUE;
			data->ClusterID = 1;
			
			g = groupList->groupItems[data->group_id];

			if(visited[data->id] != 1)
        	{
                visited[data->id] = 1;
                addHelper[0] = data->id;
                VECTOR_ADD(g->corepoints, addHelper);
              	VECTOR_ADD(unprocessedCore, addHelper);
        	}

        	int root1 = data->id;
			int root2 = root;

			dataroot1 = dataList->dataClstElem + root1;
            dataroot2 = dataList->dataClstElem + root2;

			unionFindMerge(dataList, root1, root2, dataroot1, dataroot2);
        }

        for(i=0;i<VECTOR_TOTAL(n->neighbours_local_outer);i++)
        {
        	data = dataList->dataClstElem + n->neighbours_local_outer->intItems[i];

			if(data->ClusterID == 0 || data->core_tag == TRUE)
			{
				int root1 = data->id;
				int root2 = root;
				data->ClusterID = 1;
				dataroot1 = dataList->dataClstElem + root1;
                dataroot2 = dataList->dataClstElem + root2;

                unionFindMerge(dataList, root1, root2, dataroot1, dataroot2);
                // REMS algorithm to (union) merge the trees
                // UNION OPERATION
			}
        }

        Data dataremote;
        for(i=0;i<VECTOR_TOTAL(n->neighbours_remote_inner);i++)
        {
        	data = dataList->dataClstElem + n->neighbours_remote_inner->intItems[i];

			if(visited[data->id] != 1)
        	{
                visited[data->id] = 1;
                addHelper[0] = data->id;
                VECTOR_ADD(g->corepoints, addHelper);
              	VECTOR_ADD(unprocessedCore, addHelper);
        	}

			data->core_tag = TRUE;
			data->isProcessed = TRUE;
			data->ClusterID = 1;

			Data dataremote = data;
            (*p_cur_insert)[dataremote->actualProcessId].push_back(point->id);
            (*p_cur_insert)[dataremote->actualProcessId].push_back(dataremote->remoteIndex);
        }


        for(i=0;i<VECTOR_TOTAL(n->neighbours_remote_outer);i++)
        {
        	Data data = dataList->dataClstElem + n->neighbours_remote_outer->intItems[i];

			data->ClusterID = 1;
			dataremote = data;
            (*p_cur_insert)[dataremote->actualProcessId].push_back(point->id);
            (*p_cur_insert)[dataremote->actualProcessId].push_back(dataremote->remoteIndex);
		}
	}

	if(total_neighbours >= MINPOINTS)
	{
		Group g = groupList->groupItems[point->group_id];

		if(point->haloPoint == FALSE && point->core_tag == FALSE) totalCore++;
		
		point->core_tag = TRUE;
		point->ClusterID = 1;

		if(visited[point->id] != 1)
        {
	        visited[point->id] = 1;
	        addHelper[0] = point->id;
	        VECTOR_ADD(g->corepoints, addHelper);
            VECTOR_ADD(unprocessedCore, addHelper);
	    }
	}

	free(region->iBottomLeft);
	free(region->iTopRight);
	free(region);

	return n;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %rdx, -0x90(%rbp)
movsd %xmm0, -0x30(%rbp)
leaq 0xdde7(%rip), %rax      # 0x1439c
incl (%rax)
movq %rdi, -0x40(%rbp)
movq 0x8(%rdi), %rax
movslq %esi, %r15
movq %r15, %rcx
shlq $0x6, %rcx
leaq (%rax,%rcx), %r12
leaq 0xdd9c(%rip), %rdx      # 0x14370
movq (%rdx), %rdx
movq (%rdx), %rdx
movslq 0x20(%rax,%rcx), %rax
movq (%rdx,%rax,8), %rbx
pushq $0x1
popq %rdi
pushq $0x30
popq %r13
movq %r13, %rsi
callq 0x2180
movq %rax, %r14
movl %r15d, (%rax)
movq %r13, %rdi
movq %r13, %r15
callq 0x2320
movq %rax, 0x20(%r14)
xorl %r13d, %r13d
movq %rax, -0x48(%rbp)
movq %rax, %rdi
xorl %esi, %esi
callq 0x27ac
movq %r15, %rdi
callq 0x2320
movq %rax, 0x18(%r14)
movq %rax, -0x70(%rbp)
movq %rax, %rdi
xorl %esi, %esi
callq 0x27ac
movq %r15, %rdi
callq 0x2320
movq %rax, 0x10(%r14)
movq %rax, -0x50(%rbp)
movq %rax, %rdi
xorl %esi, %esi
callq 0x27ac
movq %r15, %rdi
callq 0x2320
movq %rax, 0x8(%r14)
movq %rax, -0x58(%rbp)
movq %rax, %rdi
xorl %esi, %esi
callq 0x27ac
movq %r12, %rdi
movsd -0x30(%rbp), %xmm0
callq 0x6b91
movq %rax, %rsi
movq 0x38(%rbx), %rax
movq 0x20(%rax), %rdi
movq %rsi, -0x88(%rbp)
movq %r12, -0x60(%rbp)
movq %r12, %rdx
movq %r14, -0x78(%rbp)
movq %r14, %rcx
movsd -0x30(%rbp), %xmm0
callq 0x642d
movq %rbx, -0x38(%rbp)
movq 0x50(%rbx), %rdi
callq 0x2831
cltq
cmpq %rax, %r13
jge 0x6757
movq 0x50(%rbx), %rax
movq 0x8(%rax), %rax
movslq (%rax,%r13,4), %r15
leaq 0xdca8(%rip), %r12      # 0x14370
movq (%r12), %rax
movq (%rax), %rax
movq (%rax,%r15,8), %rax
movq -0x40(%rbp), %rcx
movq 0x8(%rcx), %rcx
movslq 0x30(%rax), %rax
shlq $0x6, %rax
movq (%rcx,%rax), %rdi
movsd -0x30(%rbp), %xmm0
callq 0x6c32
movq %rax, %r14
movq -0x88(%rbp), %rbx
movq %rbx, %rdi
movq %rax, %rsi
callq 0x5150
testl %eax, %eax
je 0x6732
movq (%r12), %rax
movq (%rax), %rax
movq (%rax,%r15,8), %rax
movq 0x38(%rax), %rax
movq 0x20(%rax), %rdi
movq %rbx, %rsi
movq -0x60(%rbp), %rdx
movq -0x78(%rbp), %rcx
movsd -0x30(%rbp), %xmm0
callq 0x642d
movq (%r14), %rdi
callq 0x2280
movq 0x8(%r14), %rdi
callq 0x2280
movq %r14, %rdi
callq 0x2280
incq %r13
movq -0x38(%rbp), %rbx
jmp 0x66a1
movq -0x58(%rbp), %rdi
callq 0x2831
movl %eax, %ebx
movq -0x50(%rbp), %r13
movq %r13, %rdi
callq 0x2831
movl %eax, %r14d
addl %ebx, %r14d
movq -0x70(%rbp), %rdi
callq 0x2831
movl %eax, %r15d
movq -0x48(%rbp), %rdi
callq 0x2831
addl %r15d, %eax
addl %r14d, %eax
leaq 0xdb9a(%rip), %rcx      # 0x14330
movl (%rcx), %ecx
cmpl %ecx, %r14d
jl 0x6adf
movl %eax, -0x64(%rbp)
movq -0x60(%rbp), %rdx
cmpl $0x0, 0x8(%rdx)
jne 0x67bd
cmpl $0x0, 0x28(%rdx)
jne 0x67bd
leaq 0xdbed(%rip), %rax      # 0x143a8
incl (%rax)
movabsq $0x100000001, %rax      # imm = 0x100000001
movq %rax, 0x28(%rdx)
movl $0x1, 0x30(%rdx)
leaq 0xdb97(%rip), %rax      # 0x14370
movq (%rax), %rax
movq (%rax), %rax
movslq 0x20(%rdx), %rcx
movq (%rax,%rcx,8), %rcx
leaq 0xdb92(%rip), %rax      # 0x14380
movq (%rax), %rax
leaq 0x1c(%rdx), %r14
movl 0x1c(%rdx), %edx
movl %edx, -0x38(%rbp)
movslq %edx, %rbx
cmpl $0x1, (%rax,%rbx,4)
movq -0x40(%rbp), %r12
movq %rcx, -0x80(%rbp)
je 0x6846
movl $0x1, (%rax,%rbx,4)
movl (%r14), %eax
leaq 0xdb43(%rip), %rbx      # 0x14360
movq (%rbx), %rsi
movl %eax, (%rsi)
movq 0x58(%rcx), %rdi
callq 0x29f0
leaq 0xdb7e(%rip), %rax      # 0x143b0
movq (%rax), %rdi
movq (%rbx), %rsi
callq 0x29f0
movl (%r14), %eax
movl %eax, -0x38(%rbp)
movslq %eax, %rbx
xorl %r15d, %r15d
shlq $0x6, %rbx
movq %r13, %rdi
callq 0x2831
cltq
cmpq %rax, %r15
jge 0x693e
movq 0x8(%r12), %r8
movq 0x8(%r13), %rax
movslq (%rax,%r15,4), %rax
shlq $0x6, %rax
leaq (%r8,%rax), %r13
cmpl $0x0, 0x8(%r8,%rax)
leaq 0xdaee(%rip), %rax      # 0x14370
jne 0x6894
cmpl $0x0, 0x28(%r13)
jne 0x6894
leaq 0xdb16(%rip), %rcx      # 0x143a8
incl (%rcx)
movabsq $0x100000001, %rcx      # imm = 0x100000001
movq %rcx, 0x28(%r13)
movl $0x1, 0x30(%r13)
movq (%rax), %rax
movq (%rax), %rax
movslq 0x20(%r13), %rcx
movq (%rax,%rcx,8), %rdx
leaq 0xdac1(%rip), %rax      # 0x14380
movq (%rax), %rax
movl 0x1c(%r13), %esi
movslq %esi, %rcx
cmpl $0x1, (%rax,%rcx,4)
movq %rdx, -0x80(%rbp)
jne 0x68d9
movq -0x40(%rbp), %r12
jmp 0x691d
movl $0x1, (%rax,%rcx,4)
movl 0x1c(%r13), %eax
leaq 0xda75(%rip), %r12      # 0x14360
movq (%r12), %rsi
movl %eax, (%rsi)
movq 0x58(%rdx), %rdi
callq 0x29f0
leaq 0xdaaf(%rip), %rax      # 0x143b0
movq (%rax), %rdi
movq (%r12), %rsi
callq 0x29f0
movl 0x1c(%r13), %esi
movq -0x40(%rbp), %r12
movq 0x8(%r12), %r8
movslq %esi, %rcx
movq -0x50(%rbp), %r13
shlq $0x6, %rcx
addq %r8, %rcx
addq %rbx, %r8
movq %r12, %rdi
movl -0x38(%rbp), %edx
callq 0x2aa8
incq %r15
jmp 0x684d
movq %r14, -0x30(%rbp)
xorl %r15d, %r15d
movq -0x48(%rbp), %r14
movq %r14, %rdi
callq 0x2831
cltq
cmpq %rax, %r15
jge 0x69a7
movq 0x8(%r12), %r8
movq 0x8(%r14), %rax
movslq (%rax,%r15,4), %rcx
shlq $0x6, %rcx
leaq (%r8,%rcx), %rax
cmpl $0x0, 0x30(%r8,%rcx)
je 0x697b
cmpl $0x1, 0x28(%rax)
jne 0x69a2
movslq 0x1c(%rax), %rsi
movl $0x1, 0x30(%rax)
movq %rsi, %rcx
shlq $0x6, %rcx
addq %r8, %rcx
addq %rbx, %r8
movq %r12, %rdi
movl -0x38(%rbp), %edx
callq 0x2aa8
movq -0x48(%rbp), %r14
incq %r15
jmp 0x6949
xorl %r14d, %r14d
movq -0x90(%rbp), %r15
movq -0x58(%rbp), %rbx
movq %rbx, %rdi
callq 0x2831
cltq
cmpq %rax, %r14
jge 0x6a71
movq 0x8(%r12), %rcx
movq 0x8(%rbx), %rax
movslq (%rax,%r14,4), %rdx
shlq $0x6, %rdx
leaq (%rcx,%rdx), %rbx
leaq 0xd99c(%rip), %rax      # 0x14380
movq (%rax), %rax
movslq 0x1c(%rcx,%rdx), %rcx
cmpl $0x1, (%rax,%rcx,4)
je 0x6a29
movl $0x1, (%rax,%rcx,4)
movl 0x1c(%rbx), %eax
leaq 0xd95d(%rip), %r13      # 0x14360
movq (%r13), %rsi
movl %eax, (%rsi)
movq -0x80(%rbp), %rax
movq 0x58(%rax), %rdi
callq 0x29f0
leaq 0xd993(%rip), %rax      # 0x143b0
movq (%rax), %rdi
movq (%r13), %rsi
callq 0x29f0
movabsq $0x100000001, %rax      # imm = 0x100000001
movq %rax, 0x28(%rbx)
movl $0x1, 0x30(%rbx)
movslq 0xc(%rbx), %rax
imulq $0x18, %rax, %rdi
addq (%r15), %rdi
movq -0x30(%rbp), %rsi
callq 0x3b0a
movslq 0xc(%rbx), %rax
imulq $0x18, %rax, %rdi
addq (%r15), %rdi
addq $0x10, %rbx
movq %rbx, %rsi
callq 0x3b0a
incq %r14
jmp 0x69b1
xorl %r14d, %r14d
movq -0x70(%rbp), %r13
movq %r13, %rdi
callq 0x2831
cltq
cmpq %rax, %r14
jge 0x6ad3
movq 0x8(%r12), %rax
movq 0x8(%r13), %rcx
movslq (%rcx,%r14,4), %rcx
shlq $0x6, %rcx
leaq (%rax,%rcx), %rbx
addq $0x10, %rbx
movl $0x1, 0x20(%rbx)
movslq -0x4(%rbx), %rax
imulq $0x18, %rax, %rdi
addq (%r15), %rdi
movq -0x30(%rbp), %rsi
callq 0x3b0a
movslq -0x4(%rbx), %rax
imulq $0x18, %rax, %rdi
addq (%r15), %rdi
movq %rbx, %rsi
callq 0x3b0a
incq %r14
jmp 0x6a78
leaq 0xd856(%rip), %rax      # 0x14330
movl (%rax), %ecx
movl -0x64(%rbp), %eax
cmpl %ecx, %eax
movq -0x60(%rbp), %rdi
movq -0x88(%rbp), %r14
jl 0x6b65
leaq 0xd87b(%rip), %rax      # 0x14370
movq (%rax), %rax
movq (%rax), %rax
movslq 0x20(%rdi), %rcx
movq (%rax,%rcx,8), %rax
cmpl $0x0, 0x8(%rdi)
jne 0x6b18
cmpl $0x0, 0x28(%rdi)
jne 0x6b18
leaq 0xd892(%rip), %rcx      # 0x143a8
incl (%rcx)
pushq $0x1
popq %rsi
movl %esi, 0x28(%rdi)
movl %esi, 0x30(%rdi)
leaq 0xd858(%rip), %rcx      # 0x14380
movq (%rcx), %rcx
movslq 0x1c(%rdi), %rdx
cmpl %esi, (%rcx,%rdx,4)
je 0x6b65
movl $0x1, (%rcx,%rdx,4)
movl 0x1c(%rdi), %ecx
leaq 0xd81b(%rip), %rbx      # 0x14360
movq (%rbx), %rsi
movl %ecx, (%rsi)
movq 0x58(%rax), %rdi
callq 0x29f0
leaq 0xd856(%rip), %rax      # 0x143b0
movq (%rax), %rdi
movq (%rbx), %rsi
callq 0x29f0
movq (%r14), %rdi
callq 0x2280
movq 0x8(%r14), %rdi
callq 0x2280
movq %r14, %rdi
callq 0x2280
movq -0x78(%rbp), %rax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq