// File: /workspace/github_cpp_makefile_star2_O2/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 $0x88, %rsp
movq %rcx, %rbx
movq %rdx, %rcx
movq %rdi, %r13
leaq 0x28(%rsp), %rax
movq %rsi, (%rax)
leaq 0x20(%rsp), %rax
movq %rdx, (%rax)
leaq 0x58(%rsp), %rax
movq %r8, (%rax)
leaq 0x40(%rsp), %rax
movq %r9, (%rax)
subl %esi, %ecx
leaq 0x8(%rsp), %rax
andl $0x0, (%rax)
leal 0x1(%rcx), %r12d
pushq $0x4
popq %rsi
movl %r12d, %eax
cltd
idivl %esi
movl %eax, %r15d
cltq
shlq $0x2, %rax
cmpl $-0x4, %ecx
pushq $-0x1
popq %rdi
cmovgeq %rax, %rdi
callq 0x2030
leaq 0x38(%rsp), %rcx
movq %rax, (%rcx)
movq %rcx, %r10
leaq -0x4a4(%rip), %rax      # 0x288e
leaq 0x30(%rsp), %rsi
movq %rax, (%rsi)
leaq 0x18(%rsp), %r8
movq %r13, (%r8)
leaq 0x10(%rsp), %rax
movq %rbx, (%rax)
movq %rax, %r9
pushq $0x10
popq %rcx
movl %r12d, %eax
cltd
idivl %ecx
movl %eax, %ebp
leaq 0x48(%rsp), %r14
movl %eax, (%r14)
leaq 0x50(%rsp), %rdi
movq %r8, %rdx
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
pushq %r10
leaq 0x10(%rsp), %rax
pushq %rax
pushq %r14
pushq %rax
leaq 0x60(%rsp), %rax
pushq %rax
leaq 0x80(%rsp), %rax
pushq %rax
callq 0x4424
addq $0x30, %rsp
leaq -0x50e(%rip), %rax      # 0x288e
leaq 0x18(%rsp), %rcx
movq %rax, (%rcx)
movq %r13, 0x78(%rsp)
leaq 0x10(%rsp), %rax
movq %r13, (%rax)
movq %rbx, (%r14)
movq %rbx, %r14
leaq 0x8(%rsp), %r11
movl (%r11), %ecx
addl %ecx, %ebp
leaq 0x70(%rsp), %r10
movl %ebp, (%r10)
pushq $0x8
popq %rsi
movl %r12d, 0xc(%rsp)
movl %r12d, %eax
cltd
idivl %esi
movl %eax, %r12d
addl %eax, %ecx
leaq 0x68(%rsp), %r13
movl %ecx, (%r13)
leaq 0x30(%rsp), %rdi
leaq 0x18(%rsp), %rsi
leaq 0x10(%rsp), %rdx
leaq 0x48(%rsp), %r9
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
leaq 0x38(%rsp), %rax
pushq %rax
pushq %r11
pushq %r13
pushq %r10
leaq 0x60(%rsp), %rax
pushq %rax
leaq 0x80(%rsp), %rax
pushq %rax
callq 0x44f0
addq $0x30, %rsp
leaq 0x10(%rsp), %rsi
leaq -0x5a5(%rip), %rax      # 0x288e
movq %rax, (%rsi)
leaq 0x48(%rsp), %r10
movq 0x78(%rsp), %rbx
movq %rbx, (%r10)
leaq 0x70(%rsp), %r9
movq %r14, (%r9)
movl 0x8(%rsp), %ecx
addl %ecx, %r12d
movl %r12d, 0x68(%rsp)
leal (%r15,%r15,2), %eax
cltd
pushq $0x4
popq %rdi
idivl %edi
movl %eax, %r12d
addl %eax, %ecx
leaq 0x64(%rsp), %rbp
movl %ecx, (%rbp)
leaq 0x18(%rsp), %rdi
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
movq %r10, %rdx
leaq 0x38(%rsp), %rax
pushq %rax
leaq 0x10(%rsp), %rax
pushq %rax
pushq %rbp
pushq %r13
leaq 0x60(%rsp), %rax
pushq %rax
leaq 0x80(%rsp), %r13
pushq %r13
callq 0x44f0
addq $0x30, %rsp
leaq 0x48(%rsp), %rsi
leaq -0x626(%rip), %rax      # 0x288e
movq %rax, (%rsi)
leaq 0x70(%rsp), %rdx
movq %rbx, (%rdx)
leaq 0x68(%rsp), %r9
movq %r14, (%r9)
movl 0x8(%rsp), %eax
addl %eax, %r12d
movl %r12d, 0x64(%rsp)
addl %r15d, %eax
leaq 0x84(%rsp), %r10
movl %eax, (%r10)
leaq 0x10(%rsp), %rdi
leaq 0x28(%rsp), %rcx
leaq 0x20(%rsp), %r8
leaq 0x38(%rsp), %rax
pushq %rax
leaq 0x10(%rsp), %rax
pushq %rax
pushq %r10
pushq %rbp
leaq 0x60(%rsp), %rax
pushq %rax
pushq %r13
callq 0x44f0
addq $0x30, %rsp
leaq 0x50(%rsp), %rdi
callq 0x2340
leaq 0x30(%rsp), %rdi
callq 0x2340
leaq 0x18(%rsp), %rdi
callq 0x2340
leaq 0x10(%rsp), %rdi
callq 0x2340
movq 0x38(%rsp), %rdi
xorl %eax, %eax
testl %r15d, %r15d
cmovlel %eax, %r15d
xorl %r12d, %r12d
movslq %r12d, %rcx
cmpq %rax, %r15
je 0x2f69
movss (%rdi,%rcx,4), %xmm0
ucomiss (%rdi,%rax,4), %xmm0
movl %eax, %ecx
ja 0x2f61
movl %r12d, %ecx
incq %rax
movl %ecx, %r12d
jmp 0x2f49
movl 0x24(%rsp), %eax
subl 0x2c(%rsp), %eax
incl %eax
imull 0xc(%rsp), %eax
cvtsi2ss %eax, %xmm0
movss (%rdi,%rcx,4), %xmm1
divss %xmm0, %xmm1
movss 0x307b(%rip), %xmm0     # 0x6008
subss %xmm1, %xmm0
movss %xmm0, 0xc(%rsp)
callq 0x2250
cvtss2sd 0xc(%rsp), %xmm0
movsd 0x306e(%rip), %xmm1     # 0x6018
ucomisd %xmm0, %xmm1
jbe 0x3047
movq 0x700d(%rip), %rdi      # 0x9fc8
leaq 0x349e(%rip), %rsi      # 0x6460
callq 0x21e0
addq $0x40, %rbx
movq %rax, %rdi
movq %rbx, %rsi
callq 0x21c0
leaq 0x34b4(%rip), %rsi      # 0x6491
movq %rax, %rdi
callq 0x21e0
addq $0x40, %r14
movq %rax, %rdi
movq %r14, %rsi
callq 0x21c0
leaq 0x349e(%rip), %rsi      # 0x6499
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
movss 0xc(%rsp), %xmm0
callq 0x2180
leaq 0x34a0(%rip), %rsi      # 0x64b8
movq %rax, %rdi
callq 0x21e0
movsd 0x2ff0(%rip), %xmm0     # 0x6018
movq %rax, %rdi
callq 0x22f0
leaq 0x2ff4(%rip), %rsi      # 0x602b
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x2100
addl 0x8(%rsp), %r12d
leaq 0x10(%rsp), %rdi
callq 0x45bc
leaq 0x18(%rsp), %rdi
callq 0x45bc
leaq 0x30(%rsp), %rdi
callq 0x45bc
leaq 0x50(%rsp), %rdi
callq 0x45bc
movd 0xc(%rsp), %xmm0
movd %xmm0, %eax
shlq $0x20, %rax
orq %rax, %r12
movq %r12, %rax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
jmp 0x30b8
movq %rax, %rbx
jmp 0x30c2
movq %rax, %rbx
jmp 0x30cc
jmp 0x30ab
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x45bc
leaq 0x18(%rsp), %rdi
callq 0x45bc
leaq 0x30(%rsp), %rdi
callq 0x45bc
leaq 0x50(%rsp), %rdi
callq 0x45bc
movq %rbx, %rdi
callq 0x2380