// File: /workspace/github_cpp_makefile_star2_O3/iibrahimli[P]adsa_project/src/../include/util.hpp
// Function: x_correlate(BMP_image const&, std::pair<int, int>, std::pair<int, int>, BMP_image const&, std::pair<int, int>, std::pair<int, int>)
std::pair<int, float> x_correlate(const BMP_image& a, std::pair<int, int> a_start, std::pair<int, int> a_end,
                                  const BMP_image& b, std::pair<int, int> b_start, std::pair<int, int> b_end)
{
    // each thread correlates 1/4th of total shift space
    int width_a = a_end.first - a_start.first + 1;
    int width_b = b_end.first - b_start.first + 1;

    // shift space
    // int sh_start = -width_b/4+1;
    // TODO restore this
    int sh_start = 0;                  // all images are shifted in one direction
    int sh_end = width_a/4;
    int sh_len = sh_end - sh_start;

    // end result is combination of threads' results, threads write here
    sim_t *res = new sim_t[sh_len];

    // starting threads with their corresponding regions
    // it's ugly, I know
    std::thread t1(&x_correlate_region, std::ref(a), a_start, a_end, std::ref(b), b_start, b_end, sh_start, sh_start+sh_len/4, sh_start, res);
    std::thread t2(&x_correlate_region, std::ref(a), a_start, a_end, std::ref(b), b_start, b_end, sh_start+sh_len/4, sh_start+sh_len/2, sh_start, res);
    std::thread t3(&x_correlate_region, std::ref(a), a_start, a_end, std::ref(b), b_start, b_end, sh_start+sh_len/2, sh_start+sh_len*3/4, sh_start, res);
    std::thread t4(&x_correlate_region, std::ref(a), a_start, a_end, std::ref(b), b_start, b_end, sh_start+sh_len*3/4, sh_start+sh_len, sh_start, res);
    
    // waiting for threads to finish
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    // find minimum activation
    int fs = 0;
    for(int i=0; i<sh_len; ++i) if(res[i] < res[fs]) fs = i;

    // score (confidence) is calculated linearly: 1 at 0 diff, 0 at maximum possible diff
    float score = res[fs] * -1/(width_a*(a_end.second - a_start.second + 1)) + 1;
    
    // -------------------------------------------------------------------------
    // for(int i=0; i<sh_len-1; ++i){
    //     std::cout << res[i] << ",";
    // }
    // std::cout << res[sh_len-1] << std::endl;
    // -------------------------------------------------------------------------

    delete[] res;

    if(score < SCORE_THRESHOLD){
        std::cout << "Warning: correlation between regions of images '" << a.filenm << "' and '" << b.filenm
                  << "' resulted in a match scoring " << score << ", lower than threshold (" << SCORE_THRESHOLD << ")" << std::endl;
    }

    return { fs+sh_start, score };
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %rcx, %r12
movq %rcx, 0x30(%rsp)
movq %rdi, %r13
movq %rdi, 0x78(%rsp)
movl %edx, %ecx
subl %esi, %ecx
leal 0x1(%rcx), %eax
leal 0x8(%rcx), %r15d
testl %eax, %eax
cmovnsl %eax, %r15d
leal 0x10(%rcx), %ebx
testl %eax, %eax
cmovnsl %eax, %ebx
leaq 0x20(%rsp), %rdi
movq %rdx, (%rdi)
leal 0x4(%rcx), %r14d
testl %eax, %eax
leaq 0x28(%rsp), %rdx
movq %rsi, (%rdx)
leaq 0x68(%rsp), %rdx
movq %r8, (%rdx)
leaq 0x48(%rsp), %rdx
movq %r9, (%rdx)
leaq 0x8(%rsp), %rdx
movl %eax, 0xc(%rsp)
cmovnsl %eax, %r14d
movl $0x0, (%rdx)
sarl $0x2, %r14d
movslq %r14d, %rax
shlq $0x2, %rax
movq %rcx, 0x50(%rsp)
cmpl $-0x4, %ecx
movq $-0x1, %rdi
cmovgeq %rax, %rdi
callq 0x2030
leaq 0x40(%rsp), %rcx
movq %rax, (%rcx)
movq %rcx, %rax
leaq -0x74b(%rip), %rcx      # 0x2c05
leaq 0x38(%rsp), %rsi
movq %rcx, (%rsi)
leaq 0x18(%rsp), %rcx
movq %r13, (%rcx)
movq %rcx, %rdx
leaq 0x10(%rsp), %rcx
movq %r12, (%rcx)
movq %rcx, %r9
sarl $0x4, %ebx
leaq 0x58(%rsp), %rbp
movl %ebx, (%rbp)
leaq 0x60(%rsp), %rdi
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
pushq %rax
leaq 0x10(%rsp), %r13
pushq %r13
pushq %rbp
pushq %r13
leaq 0x68(%rsp), %rax
pushq %rax
leaq 0x90(%rsp), %r12
pushq %r12
callq 0x5194
addq $0x30, %rsp
leaq -0x7ae(%rip), %rax      # 0x2c05
leaq 0x18(%rsp), %rcx
movq %rax, (%rcx)
movq 0x78(%rsp), %rcx
leaq 0x10(%rsp), %rax
movq %rcx, (%rax)
movq 0x30(%rsp), %rax
movq %rax, (%rbp)
movq %r12, %r11
movl (%r13), %eax
addl %eax, %ebx
leaq 0x88(%rsp), %r10
movl %ebx, (%r10)
sarl $0x3, %r15d
addl %r15d, %eax
leaq 0x80(%rsp), %r12
movl %eax, (%r12)
leaq 0x38(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x10(%rsp), %rdx
leaq 0x58(%rsp), %r9
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
leaq 0x40(%rsp), %rax
pushq %rax
pushq %r13
pushq %r12
pushq %r10
leaq 0x68(%rsp), %rax
pushq %rax
pushq %r11
callq 0x527c
addq $0x30, %rsp
leaq 0x10(%rsp), %rsi
leaq -0x83a(%rip), %rax      # 0x2c05
movq %rax, (%rsi)
leaq 0x58(%rsp), %rdx
movq 0x78(%rsp), %rbx
movq %rbx, (%rdx)
leaq 0x88(%rsp), %r9
movq 0x30(%rsp), %rax
movq %rax, (%r9)
movl 0x8(%rsp), %eax
addl %eax, %r15d
movl %r15d, 0x80(%rsp)
leal (%r14,%r14,2), %ecx
leal (%r14,%r14,2), %ebp
addl $0x3, %ebp
testl %ecx, %ecx
cmovnsl %ecx, %ebp
sarl $0x2, %ebp
addl %ebp, %eax
leaq 0x74(%rsp), %r15
movl %eax, (%r15)
leaq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
leaq 0x40(%rsp), %rax
pushq %rax
leaq 0x10(%rsp), %r13
pushq %r13
pushq %r15
pushq %r12
leaq 0x68(%rsp), %rax
pushq %rax
leaq 0x90(%rsp), %rax
pushq %rax
callq 0x527c
addq $0x30, %rsp
leaq 0x58(%rsp), %rsi
leaq -0x8ca(%rip), %rax      # 0x2c05
movq %rax, (%rsi)
leaq 0x88(%rsp), %rdx
movq %rbx, (%rdx)
leaq 0x80(%rsp), %r9
movq 0x30(%rsp), %rax
movq %rax, (%r9)
movl 0x8(%rsp), %eax
addl %eax, %ebp
movl %ebp, 0x74(%rsp)
addl %r14d, %eax
leaq 0x94(%rsp), %r10
movl %eax, (%r10)
leaq 0x10(%rsp), %rdi
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
leaq 0x40(%rsp), %rax
pushq %rax
pushq %r13
pushq %r10
pushq %r15
leaq 0x68(%rsp), %rax
pushq %rax
leaq 0x90(%rsp), %rax
pushq %rax
callq 0x527c
addq $0x30, %rsp
leaq 0x60(%rsp), %rdi
callq 0x2360
leaq 0x38(%rsp), %rdi
callq 0x2360
leaq 0x18(%rsp), %rdi
callq 0x2360
leaq 0x10(%rsp), %rdi
callq 0x2360
xorl %r15d, %r15d
movq 0x40(%rsp), %rdi
cmpl $0x3, 0x50(%rsp)
jl 0x359f
cmpl $0x2, %r14d
movl $0x1, %eax
cmovgel %r14d, %eax
xorl %ecx, %ecx
xorl %edx, %edx
movslq %edx, %rsi
movss (%rdi,%rsi,4), %xmm0
ucomiss (%rdi,%rcx,4), %xmm0
movl %ecx, %r15d
ja 0x3594
movl %edx, %r15d
incq %rcx
movl %r15d, %edx
cmpq %rcx, %rax
jne 0x3580
movl 0x24(%rsp), %eax
subl 0x2c(%rsp), %eax
incl %eax
imull 0xc(%rsp), %eax
movslq %r15d, %rcx
xorps %xmm0, %xmm0
cvtsi2ss %eax, %xmm0
movss (%rdi,%rcx,4), %xmm1
divss %xmm0, %xmm1
movss 0x3a3f(%rip), %xmm0     # 0x7008
subss %xmm1, %xmm0
movss %xmm0, 0xc(%rsp)
callq 0x2290
xorps %xmm1, %xmm1
cvtss2sd 0xc(%rsp), %xmm1
movsd 0x3a2f(%rip), %xmm0     # 0x7018
movsd %xmm1, 0x50(%rsp)
ucomisd %xmm1, %xmm0
jbe 0x36db
movq 0x69c8(%rip), %rdi      # 0x9fc8
leaq 0x3e59(%rip), %rsi      # 0x7460
movl $0x30, %edx
callq 0x2250
movq 0x40(%rbx), %rsi
movq 0x48(%rbx), %rdx
movq 0x69a8(%rip), %rdi      # 0x9fc8
callq 0x2250
movq %rax, %r14
leaq 0x3e62(%rip), %rsi      # 0x7491
movl $0x7, %edx
movq %rax, %rdi
callq 0x2250
movq 0x30(%rsp), %rax
movq 0x40(%rax), %rsi
movq 0x48(%rax), %rdx
movq %r14, %rdi
callq 0x2250
movq %rax, %rbx
leaq 0x3e3e(%rip), %rsi      # 0x7499
movl $0x1e, %edx
movq %rax, %rdi
callq 0x2250
movq %rbx, %rdi
movsd 0x50(%rsp), %xmm0
callq 0x2310
movq %rax, %rbx
leaq 0x3e38(%rip), %rsi      # 0x74b8
movl $0x18, %edx
movq %rax, %rdi
callq 0x2250
movsd 0x3983(%rip), %xmm0     # 0x7018
movq %rbx, %rdi
callq 0x2310
movq %rax, %rbx
leaq 0x3984(%rip), %rsi      # 0x702b
movl $0x1, %edx
movq %rax, %rdi
callq 0x2250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x21f0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2040
movq %rax, %rdi
callq 0x2170
cmpq $0x0, 0x10(%rsp)
jne 0x3726
cmpq $0x0, 0x18(%rsp)
jne 0x372b
cmpq $0x0, 0x38(%rsp)
jne 0x3730
cmpq $0x0, 0x60(%rsp)
jne 0x3735
addl 0x8(%rsp), %r15d
movd 0xc(%rsp), %xmm0
movd %xmm0, %eax
shlq $0x20, %rax
orq %rax, %r15
movq %r15, %rax
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2080
callq 0x2080
callq 0x2080
callq 0x2080
jmp 0x374a
jmp 0x3752
jmp 0x375a
jmp 0x3742
cmpq $0x0, 0x10(%rsp)
jne 0x376a
cmpq $0x0, 0x18(%rsp)
jne 0x376f
cmpq $0x0, 0x38(%rsp)
jne 0x3774
cmpq $0x0, 0x60(%rsp)
jne 0x3779
movq %rax, %rdi
callq 0x23a0
callq 0x2080
callq 0x2080
callq 0x2080
callq 0x2080