// File: /workspace/github_cpp_makefile_star2_O2/brianwu02[P]ImageProcessing/median.cpp
// Function: median(imageS*, imageS*, int, int, imageS*)
void median(imageP I1, imageP paddedImg, int sz, int avg_nbrs, imageP I2) {
    
    int i, total, paddedTotal;
    unsigned char *in, *out, *paddedIn, *buf;
    

    total = I1->width * I1->height;
    paddedTotal = paddedImg->height * paddedImg->width;

    I2->height = I1->height;
    I2->width = I1->width;

    I2->image = (unsigned char *) malloc(total);

    in = I1->image;
    out = I2->image;
    paddedIn = paddedImg->image;

    if (I2->image == NULL) {
        cerr << "not enough memory\n";
        exit(1);
    }

    // number of extra columns required.
    int m = (sz - 1) / 2; 
    // number of extra rows required. 
    int n = (sz - 1) / 2;

    int w = I1->width;
    int h = I1->height;
    int paddedWidth = paddedImg->width;
    int paddedHeight = paddedImg->height;

    // number of buffer rows required. a 3x3 kernel requires 3 rows, 5x5 requires 5 rows.
    int bufRowsRequired = m + n + 1;

    // allocate memory for an array that will hold (m + n + 1) row buffer.
    unsigned char *arrayOfPointers[bufRowsRequired];

    // allocate memory for the (m+n+1) row of buffers.
    buf = (unsigned char *) malloc(paddedWidth * bufRowsRequired);

    // assign pointers to each 'row' in buffer. If there are 3 rows required for the kernel image,
    // there will be 3 pointers in arrayOfPointers pointing to each portion of the buffer.
    for (int i=0; i<bufRowsRequired; i++) {
        arrayOfPointers[i] = &buf[i*paddedWidth];
    }

    // need to copy bufRowsRequired - 1 rows to the buffer.
    for (int y=0; i<(bufRowsRequired-1); y++) {
        copyToBuffer(paddedImg, y, bufRowsRequired, buf);
    }

    int kernel_size = (sz * sz);
    static const size_t v_size = kernel_size;
    

    // try to get this working for 3 * 3 kernel 
    unsigned char *r0, *r1, *r2;
    unsigned char k[kernel_size];
    for (int y=0; y<h; y++) {
        // need to copy the last row required in to the buffer. should be row = bufRowsRequired
        copyToBuffer(paddedImg, y + (bufRowsRequired-1), bufRowsRequired, buf);
        r0 = arrayOfPointers[y % 3] + m;
        r1 = arrayOfPointers[(y+1) % 3] + m;
        r2 = arrayOfPointers[(y+2) % 3] + m;
        for (int x=0; x<w; x++) {
            

            k[0] = r0[-1];
            k[1] = r0[0];
            k[2] = r0[1];
            k[3] = r1[-1];
            k[4] = r1[0];
            k[5] = r1[1];
            k[6] = r2[-1];
            k[7] = r2[0];
            k[8] = r2[1];


            std::sort(k, k + kernel_size);
            // because im really lazy right now.
            if (avg_nbrs == 0) {
                out[y*w+x] = k[4];
            } else if (avg_nbrs == 1) {
                out[y*w+x] = (k[3] + k[4] + k[5]) / 3;
            } else if (avg_nbrs == 2) {
                out[y*w+x] = (k[2] + k[3] + k[4] + k[5] + k[6]) / 5;
            } else if (avg_nbrs == 3) {
                out[y*w+x] = (k[1] + k[2] + k[3] + k[4] + k[5] + k[6] + k[7]) / 7;
            } else if (avg_nbrs == 4) {
                out[y*w+x] = (k[0] + k[1] + k[2] + k[3] + k[4] + k[5] + k[6] + k[7] + k[8]) / 9;
            }

            r0++;
            r1++;
            r2++;

        }
    }
    free(buf);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %r8, %r14
movl %ecx, -0x2c(%rbp)
movl %edx, %r13d
movq %rsi, %r15
movslq (%rdi), %rcx
movl 0x4(%rdi), %edx
movl %edx, %eax
imull %ecx, %eax
movq %rdx, -0x38(%rbp)
movl %edx, 0x4(%r8)
movq %rcx, -0x50(%rbp)
movl %ecx, (%r8)
movslq %eax, %rdi
callq 0x1100
movq %rax, 0x8(%r14)
movq %rax, -0x40(%rbp)
testq %rax, %rax
je 0x1acb
leal -0x1(%r13), %eax
pushq $0x2
popq %rcx
cltd
idivl %ecx
movslq (%r15), %rbx
cltq
leaq (%rax,%rax), %r14
movq %rax, -0x70(%rbp)
leaq 0x1(,%rax,2), %rdi
movl %edi, %eax
leaq 0xf(,%rax,8), %rax
andq $-0x10, %rax
movq %rsp, %rcx
subq %rax, %rcx
movq %rcx, -0x58(%rbp)
movq %rcx, %rsp
movq %rdi, -0x60(%rbp)
imulq %rbx, %rdi
callq 0x1100
movq %rax, %rdx
movq %r14, -0x68(%rbp)
leal 0x1(%r14), %eax
xorl %ecx, %ecx
testl %eax, %eax
cmovlel %ecx, %eax
movq %rdx, -0x48(%rbp)
movq -0x58(%rbp), %rsi
cmpq %rcx, %rax
je 0x185f
movq %rdx, (%rsi,%rcx,8)
incq %rcx
addq %rbx, %rdx
jmp 0x184e
imull %r13d, %r13d
movb 0x3897(%rip), %al       # 0x5100
movl %r13d, %ebx
testb %al, %al
je 0x1ae6
movq %rsp, %r12
addl $0xf, %r13d
andl $-0x10, %r13d
subq %r13, %r12
movq %r12, %rsp
addq %r12, %rbx
xorl %eax, %eax
movq -0x50(%rbp), %rcx
testl %ecx, %ecx
movl $0x0, %edx
cmovgl %ecx, %edx
movq %rdx, -0x98(%rbp)
movq -0x38(%rbp), %rcx
testl %ecx, %ecx
cmovlel %eax, %ecx
movq %rcx, -0x38(%rbp)
movl -0x2c(%rbp), %eax
movq %rax, -0x88(%rbp)
xorl %r13d, %r13d
movq %r15, -0x78(%rbp)
movq %rbx, -0x90(%rbp)
cmpq -0x38(%rbp), %r13
je 0x1ab3
movl %r13d, %ebx
movq -0x68(%rbp), %rax
leal (%rax,%rbx), %esi
movq %r15, %rdi
movq -0x60(%rbp), %rdx
movq -0x48(%rbp), %rcx
callq 0x1b12
movl %r13d, %eax
xorl %edx, %edx
pushq $0x3
popq %rdi
divl %edi
movq -0x58(%rbp), %rsi
movq (%rsi,%rdx,8), %r14
movq -0x70(%rbp), %rcx
addq %rcx, %r14
incq %r13
movq %r13, -0x80(%rbp)
movl %r13d, %eax
xorl %edx, %edx
divl %edi
movq (%rsi,%rdx,8), %r15
addq %rcx, %r15
leal 0x2(%rbx), %eax
xorl %edx, %edx
divl %edi
movq (%rsi,%rdx,8), %rbx
addq %rcx, %rbx
xorl %r13d, %r13d
cmpq %r13, -0x98(%rbp)
je 0x1a9a
movb -0x1(%r14,%r13), %al
movb %al, (%r12)
movb (%r14,%r13), %al
movb %al, 0x1(%r12)
movb 0x1(%r14,%r13), %al
movb %al, 0x2(%r12)
movb -0x1(%r15,%r13), %al
movb %al, 0x3(%r12)
movb (%r15,%r13), %al
movb %al, 0x4(%r12)
movb 0x1(%r15,%r13), %al
movb %al, 0x5(%r12)
movb -0x1(%rbx,%r13), %al
movb %al, 0x6(%r12)
movb (%rbx,%r13), %al
movb %al, 0x7(%r12)
movb 0x1(%rbx,%r13), %al
movb %al, 0x8(%r12)
movq %r12, %rdi
movq -0x90(%rbp), %rsi
callq 0x1b61
cmpl $0x4, -0x2c(%rbp)
ja 0x1a92
movq -0x88(%rbp), %rax
leaq 0x166f(%rip), %rcx      # 0x3020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb 0x4(%r12), %al
jmp 0x1a8a
movq (%r12), %xmm0
movzbl 0x8(%r12), %ecx
psadbw 0x1638(%rip), %xmm0     # 0x3010
movd %xmm0, %eax
addl %ecx, %eax
xorl %edx, %edx
movw $0x9, %cx
jmp 0x1a87
movd 0x2(%r12), %xmm0
punpcklbw 0x1618(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1],xmm0[2],mem[2],xmm0[3],mem[3],xmm0[4],mem[4],xmm0[5],mem[5],xmm0[6],mem[6],xmm0[7],mem[7]
movzbl 0x6(%r12), %ecx
pshufd $0x55, %xmm0, %xmm1     # xmm1 = xmm0[1,1,1,1]
paddw %xmm0, %xmm1
movdqa %xmm1, %xmm0
psrld $0x10, %xmm0
paddw %xmm1, %xmm0
movd %xmm0, %eax
addl %ecx, %eax
xorl %edx, %edx
movw $0x5, %cx
jmp 0x1a87
movd 0x1(%r12), %xmm0
punpcklbw 0x15df(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1],xmm0[2],mem[2],xmm0[3],mem[3],xmm0[4],mem[4],xmm0[5],mem[5],xmm0[6],mem[6],xmm0[7],mem[7]
movzbl 0x5(%r12), %eax
movzbl 0x6(%r12), %ecx
movzbl 0x7(%r12), %edx
addl %ecx, %edx
addl %eax, %edx
pshufd $0x55, %xmm0, %xmm1     # xmm1 = xmm0[1,1,1,1]
paddw %xmm0, %xmm1
movdqa %xmm1, %xmm0
psrld $0x10, %xmm0
paddw %xmm1, %xmm0
movd %xmm0, %eax
addl %edx, %eax
xorl %edx, %edx
movw $0x7, %cx
jmp 0x1a87
movzbl 0x3(%r12), %eax
movzbl 0x4(%r12), %ecx
addl %eax, %ecx
movzbl 0x5(%r12), %eax
addl %ecx, %eax
xorl %edx, %edx
movw $0x3, %cx
divw %cx
movq -0x40(%rbp), %rcx
movb %al, (%rcx,%r13)
incq %r13
jmp 0x1927
movq -0x40(%rbp), %rax
addq -0x50(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x78(%rbp), %r15
movq -0x80(%rbp), %r13
jmp 0x18c4
movq -0x48(%rbp), %rdi
callq 0x10c0
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x351e(%rip), %rdi      # 0x4ff0
leaq 0x164a(%rip), %rsi      # 0x3123
callq 0x10a0
pushq $0x1
popq %rdi
callq 0x10d0
leaq 0x3613(%rip), %rdi      # 0x5100
callq 0x1180
testl %eax, %eax
je 0x1874
movq %rbx, 0x35f7(%rip)      # 0x50f8
leaq 0x35f8(%rip), %rdi      # 0x5100
callq 0x1080
jmp 0x1874