// File: 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:
subq $0x1d8, %rsp            # imm = 0x1D8
movq %rsi, 0x1c8(%rsp)
movq %rdx, 0x1c0(%rsp)
movq %r8, 0x1b8(%rsp)
movq %r9, 0x1b0(%rsp)
movq %rdi, 0x1a8(%rsp)
movq %rcx, 0x1a0(%rsp)
movl 0x1c0(%rsp), %eax
movl 0x1c8(%rsp), %ecx
subl %ecx, %eax
incl %eax
movl %eax, 0x19c(%rsp)
movl 0x1b0(%rsp), %eax
movl 0x1b8(%rsp), %ecx
subl %ecx, %eax
incl %eax
movl %eax, 0x198(%rsp)
movl $0x0, 0x194(%rsp)
movl 0x19c(%rsp), %eax
movl %eax, %ecx
addl $0x3, %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x2, %eax
movl %eax, 0x190(%rsp)
movl 0x190(%rsp), %eax
movl 0x194(%rsp), %ecx
subl %ecx, %eax
movl %eax, 0x18c(%rsp)
movslq 0x18c(%rsp), %rax
movl $0x4, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x3030
movq %rax, 0x180(%rsp)
leaq -0x6d8(%rip), %rax      # 0x3c50
movq %rax, 0x88(%rsp)
movq %rax, 0x170(%rsp)
movq 0x1a8(%rsp), %rdi
callq 0x73c0
movq %rax, 0x168(%rsp)
movq 0x1a0(%rsp), %rdi
callq 0x73c0
movq %rax, 0x160(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %ecx
movl %ecx, %edx
addl $0x3, %edx
testl %ecx, %ecx
cmovsl %edx, %ecx
sarl $0x2, %ecx
addl %ecx, %eax
movl %eax, 0x15c(%rsp)
movq %rsp, %rax
leaq 0x180(%rsp), %rcx
movq %rcx, 0x90(%rsp)
movq %rcx, 0x28(%rax)
leaq 0x194(%rsp), %rcx
movq %rcx, 0x98(%rsp)
movq %rcx, 0x20(%rax)
leaq 0x15c(%rsp), %rdx
movq %rdx, 0x18(%rax)
movq %rcx, 0x10(%rax)
leaq 0x1b0(%rsp), %rcx
movq %rcx, 0xa0(%rsp)
movq %rcx, 0x8(%rax)
leaq 0x1b8(%rsp), %rcx
movq %rcx, 0xa8(%rsp)
movq %rcx, (%rax)
leaq 0x178(%rsp), %rdi
leaq 0x170(%rsp), %rsi
leaq 0x168(%rsp), %rdx
leaq 0x1c8(%rsp), %rcx
movq %rcx, 0xb0(%rsp)
leaq 0x1c0(%rsp), %r8
movq %r8, 0xb8(%rsp)
leaq 0x160(%rsp), %r9
callq 0x73f0
movq 0x88(%rsp), %rax
movq %rax, 0x148(%rsp)
movq 0x1a8(%rsp), %rdi
callq 0x73c0
movq %rax, 0x140(%rsp)
movq 0x1a0(%rsp), %rdi
callq 0x73c0
movq 0x90(%rsp), %r9
movq 0x98(%rsp), %rdi
movq 0xa0(%rsp), %rsi
movq 0xa8(%rsp), %rdx
movq 0xb0(%rsp), %rcx
movq 0xb8(%rsp), %r8
movq %rax, 0x138(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %r10d
movl %r10d, %r11d
addl $0x3, %r11d
testl %r10d, %r10d
cmovsl %r11d, %r10d
sarl $0x2, %r10d
addl %r10d, %eax
movl %eax, 0x134(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %r10d
movl %r10d, %r11d
shrl $0x1f, %r11d
addl %r11d, %r10d
sarl %r10d
addl %r10d, %eax
movl %eax, 0x130(%rsp)
movq %rsp, %rax
movq %r9, 0x28(%rax)
movq %rdi, 0x20(%rax)
leaq 0x130(%rsp), %rdi
movq %rdi, 0x18(%rax)
leaq 0x134(%rsp), %rdi
movq %rdi, 0x10(%rax)
movq %rsi, 0x8(%rax)
movq %rdx, (%rax)
leaq 0x150(%rsp), %rdi
leaq 0x148(%rsp), %rsi
leaq 0x140(%rsp), %rdx
leaq 0x138(%rsp), %r9
callq 0x7580
jmp 0x4539
leaq -0x8f0(%rip), %rax      # 0x3c50
movq %rax, 0x110(%rsp)
movq 0x1a8(%rsp), %rdi
callq 0x73c0
movq %rax, 0x108(%rsp)
movq 0x1a0(%rsp), %rdi
callq 0x73c0
movq %rax, 0x100(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %ecx
movl %ecx, %edx
shrl $0x1f, %edx
addl %edx, %ecx
sarl %ecx
addl %ecx, %eax
movl %eax, 0xfc(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %ecx
movl %ecx, %edx
leal (%rdx,%rdx,2), %ecx
leal 0x3(%rdx,%rdx,2), %edx
testl %ecx, %ecx
cmovsl %edx, %ecx
sarl $0x2, %ecx
addl %ecx, %eax
movl %eax, 0xf8(%rsp)
movq %rsp, %rax
leaq 0x180(%rsp), %rcx
movq %rcx, 0x28(%rax)
leaq 0x194(%rsp), %rcx
movq %rcx, 0x20(%rax)
leaq 0xf8(%rsp), %rcx
movq %rcx, 0x18(%rax)
leaq 0xfc(%rsp), %rcx
movq %rcx, 0x10(%rax)
leaq 0x1b0(%rsp), %rcx
movq %rcx, 0x8(%rax)
leaq 0x1b8(%rsp), %rcx
movq %rcx, (%rax)
leaq 0x118(%rsp), %rdi
leaq 0x110(%rsp), %rsi
leaq 0x108(%rsp), %rdx
leaq 0x1c8(%rsp), %rcx
leaq 0x1c0(%rsp), %r8
leaq 0x100(%rsp), %r9
callq 0x7580
jmp 0x463b
leaq -0x9f2(%rip), %rax      # 0x3c50
movq %rax, 0xe8(%rsp)
movq 0x1a8(%rsp), %rdi
callq 0x73c0
movq %rax, 0xe0(%rsp)
movq 0x1a0(%rsp), %rdi
callq 0x73c0
movq %rax, 0xd8(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %ecx
movl %ecx, %edx
leal (%rdx,%rdx,2), %ecx
leal 0x3(%rdx,%rdx,2), %edx
testl %ecx, %ecx
cmovsl %edx, %ecx
sarl $0x2, %ecx
addl %ecx, %eax
movl %eax, 0xd4(%rsp)
movl 0x194(%rsp), %eax
movl 0x18c(%rsp), %ecx
addl %ecx, %eax
movl %eax, 0xd0(%rsp)
movq %rsp, %rax
leaq 0x180(%rsp), %rcx
movq %rcx, 0x28(%rax)
leaq 0x194(%rsp), %rcx
movq %rcx, 0x20(%rax)
leaq 0xd0(%rsp), %rcx
movq %rcx, 0x18(%rax)
leaq 0xd4(%rsp), %rcx
movq %rcx, 0x10(%rax)
leaq 0x1b0(%rsp), %rcx
movq %rcx, 0x8(%rax)
leaq 0x1b8(%rsp), %rcx
movq %rcx, (%rax)
leaq 0xf0(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
leaq 0xe0(%rsp), %rdx
leaq 0x1c8(%rsp), %rcx
leaq 0x1c0(%rsp), %r8
leaq 0xd8(%rsp), %r9
callq 0x7580
jmp 0x4734
leaq 0x178(%rsp), %rdi
callq 0x3430
jmp 0x4743
leaq 0x150(%rsp), %rdi
callq 0x3430
jmp 0x4752
leaq 0x118(%rsp), %rdi
callq 0x3430
jmp 0x4761
leaq 0xf0(%rsp), %rdi
callq 0x3430
jmp 0x4770
movl $0x0, 0xcc(%rsp)
movl $0x0, 0xc8(%rsp)
movl 0xc8(%rsp), %eax
cmpl 0x18c(%rsp), %eax
jge 0x4866
movq 0x180(%rsp), %rax
movslq 0xc8(%rsp), %rcx
movss (%rax,%rcx,4), %xmm1
movq 0x180(%rsp), %rax
movslq 0xcc(%rsp), %rcx
movss (%rax,%rcx,4), %xmm0
ucomiss %xmm1, %xmm0
jbe 0x484e
movl 0xc8(%rsp), %eax
movl %eax, 0xcc(%rsp)
jmp 0x484e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x128(%rsp)
movl %eax, 0x124(%rsp)
jmp 0x4a8d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x128(%rsp)
movl %eax, 0x124(%rsp)
jmp 0x4a80
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x128(%rsp)
movl %eax, 0x124(%rsp)
jmp 0x4a73
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x128(%rsp)
movl %eax, 0x124(%rsp)
leaq 0xf0(%rsp), %rdi
callq 0x7740
jmp 0x4a73
jmp 0x4850
movl 0xc8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc8(%rsp)
jmp 0x4786
movq 0x180(%rsp), %rax
movslq 0xcc(%rsp), %rcx
movss 0x978e(%rip), %xmm0     # 0xe00c
mulss (%rax,%rcx,4), %xmm0
movl 0x19c(%rsp), %eax
movl 0x1c4(%rsp), %ecx
subl 0x1cc(%rsp), %ecx
addl $0x1, %ecx
imull %ecx, %eax
cvtsi2ss %eax, %xmm1
divss %xmm1, %xmm0
movss 0x975a(%rip), %xmm1     # 0xe008
addss %xmm1, %xmm0
movss %xmm0, 0xc4(%rsp)
movq 0x180(%rsp), %rax
movq %rax, 0x80(%rsp)
cmpq $0x0, %rax
je 0x48de
movq 0x80(%rsp), %rdi
callq 0x3330
movss 0xc4(%rsp), %xmm0
cvtss2sd %xmm0, %xmm1
movsd 0x9725(%rip), %xmm0     # 0xe018
ucomisd %xmm1, %xmm0
jbe 0x49f9
movq 0xf6c4(%rip), %rdi      # 0x13fc8
leaq 0x9b55(%rip), %rsi      # 0xe460
callq 0x3250
movq %rax, 0x78(%rsp)
jmp 0x4917
movq 0x78(%rsp), %rdi
movq 0x1a8(%rsp), %rsi
addq $0x40, %rsi
callq 0x3230
movq %rax, 0x70(%rsp)
jmp 0x4934
movq 0x70(%rsp), %rdi
leaq 0x9b51(%rip), %rsi      # 0xe491
callq 0x3250
movq %rax, 0x68(%rsp)
jmp 0x494c
movq 0x68(%rsp), %rdi
movq 0x1a0(%rsp), %rsi
addq $0x40, %rsi
callq 0x3230
movq %rax, 0x60(%rsp)
jmp 0x4969
movq 0x60(%rsp), %rdi
leaq 0x9b24(%rip), %rsi      # 0xe499
callq 0x3250
movq %rax, 0x58(%rsp)
jmp 0x4981
movq 0x58(%rsp), %rdi
movss 0xc4(%rsp), %xmm0
callq 0x31e0
movq %rax, 0x50(%rsp)
jmp 0x499b
movq 0x50(%rsp), %rdi
leaq 0x9b11(%rip), %rsi      # 0xe4b8
callq 0x3250
movq %rax, 0x48(%rsp)
jmp 0x49b3
movq 0x48(%rsp), %rdi
movsd 0x9658(%rip), %xmm0     # 0xe018
callq 0x34a0
movq %rax, 0x40(%rsp)
jmp 0x49cc
movq 0x40(%rsp), %rdi
leaq 0x9653(%rip), %rsi      # 0xe02b
callq 0x3250
movq %rax, 0x38(%rsp)
jmp 0x49e4
movq 0x38(%rsp), %rdi
movq 0xf5b8(%rip), %rsi      # 0x13fa8
callq 0x3280
jmp 0x49f7
jmp 0x49f9
movl 0xcc(%rsp), %eax
movl 0x194(%rsp), %ecx
addl %ecx, %eax
movl %eax, 0xc0(%rsp)
leaq 0x1d0(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
leaq 0xc4(%rsp), %rdx
callq 0x7710
jmp 0x4a2f
leaq 0xf0(%rsp), %rdi
callq 0x7740
leaq 0x118(%rsp), %rdi
callq 0x7740
leaq 0x150(%rsp), %rdi
callq 0x7740
leaq 0x178(%rsp), %rdi
callq 0x7740
movq 0x1d0(%rsp), %rax
addq $0x1d8, %rsp            # imm = 0x1D8
retq
leaq 0x118(%rsp), %rdi
callq 0x7740
leaq 0x150(%rsp), %rdi
callq 0x7740
leaq 0x178(%rsp), %rdi
callq 0x7740
movq 0x128(%rsp), %rdi
callq 0x3460
nopw (%rax,%rax)