// File: /workspace/github_cpp_makefile_star2_O3/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 $0x88, %rsp
movq %r8, %r15
movl %ecx, -0x2c(%rbp)
movl %edx, %r14d
movq %rsi, %r12
movl (%rdi), %ecx
movl 0x4(%rdi), %eax
movl %eax, 0x4(%r8)
movq %rax, -0x58(%rbp)
imull %ecx, %eax
movq %rcx, -0x50(%rbp)
movl %ecx, (%r8)
movslq %eax, %rdi
callq 0x2160
movq %rax, 0x8(%r15)
movq %rax, -0x48(%rbp)
testq %rax, %rax
je 0x2d9a
leal -0x1(%r14), %eax
shrl $0x1f, %eax
addl %r14d, %eax
decl %eax
sarl %eax
movslq (%r12), %rbx
cltq
leaq (%rax,%rax), %rcx
movq %rcx, -0x38(%rbp)
movq %rax, -0x80(%rbp)
leaq 0x1(,%rax,2), %rdi
movl %edi, %eax
leaq 0xf(,%rax,8), %rax
andq $-0x10, %rax
movq %rsp, %r15
subq %rax, %r15
movq %r15, %rsp
movq %rdi, -0x78(%rbp)
imulq %rbx, %rdi
callq 0x2160
movq %rax, -0x40(%rbp)
testl %r14d, %r14d
movq %r14, %r10
js 0x2aa5
xorl %eax, %eax
movq -0x38(%rbp), %rdx
testl %edx, %edx
movl $0x0, %ecx
cmovgl %edx, %ecx
orl $0x1, %ecx
movq -0x40(%rbp), %rdx
movq %rdx, (%r15,%rax,8)
incq %rax
addq %rbx, %rdx
cmpq %rax, %rcx
jne 0x2a96
movq %r15, -0x70(%rbp)
movl %r10d, %r15d
imull %r15d, %r15d
movb 0x368a(%rip), %al       # 0x6140
testb %al, %al
movl -0x2c(%rbp), %r9d
movq %r10, -0x68(%rbp)
je 0x2db7
movq %rsp, %r13
leal 0xf(%r15), %eax
andl $-0x10, %eax
subq %rax, %r13
movq %r13, %rsp
cmpl $0x0, -0x58(%rbp)
jle 0x2d82
movl %r15d, %eax
leaq (%rax,%r13), %rcx
movq %rcx, -0xa0(%rbp)
bsrq %rax, %rax
xorl $0x3f, %eax
addl %eax, %eax
xorq $0x7e, %rax
movq %rax, -0x98(%rbp)
movslq -0x38(%rbp), %r11
xorl %ecx, %ecx
movq %r12, -0x88(%rbp)
movslq (%r12), %rsi
testq %rsi, %rsi
jle 0x2b4a
movq -0x38(%rbp), %rax
addl %ecx, %eax
cltd
idivl -0x78(%rbp)
imull %esi, %edx
movslq %edx, %rax
addq -0x40(%rbp), %rax
movq %r11, %rdx
imulq %rsi, %rdx
addq 0x8(%r12), %rdx
xorl %edi, %edi
movb (%rdx,%rdi), %r8b
movb %r8b, (%rax,%rdi)
incq %rdi
cmpq %rdi, %rsi
jne 0x2b3a
movq %r11, -0x90(%rbp)
leaq 0x1(%rcx), %rax
movq %rax, -0x60(%rbp)
cmpl $0x0, -0x50(%rbp)
jle 0x2d57
leal 0x2(%rcx), %eax
movl $0xaaaaaaab, %r8d       # imm = 0xAAAAAAAB
imulq %r8, %rax
shrq $0x21, %rax
leal (%rax,%rax,2), %eax
negl %eax
addl %ecx, %eax
addl $0x2, %eax
movq -0x70(%rbp), %rdi
movq (%rdi,%rax,8), %rax
movq -0x80(%rbp), %rsi
addq %rsi, %rax
movq %rax, -0xa8(%rbp)
movq -0x60(%rbp), %rdx
movl %edx, %eax
imulq %r8, %rax
shrq $0x21, %rax
leal (%rax,%rax,2), %eax
subl %eax, %edx
movq (%rdi,%rdx,8), %r14
addq %rsi, %r14
movl %ecx, %eax
imulq %r8, %rax
shrq $0x21, %rax
leal (%rax,%rax,2), %eax
subl %eax, %ecx
movq (%rdi,%rcx,8), %r15
addq %rsi, %r15
xorl %ebx, %ebx
movb -0x1(%r15,%rbx), %al
movb %al, (%r13)
movb (%r15,%rbx), %al
movb %al, 0x1(%r13)
movb 0x1(%r15,%rbx), %al
movb %al, 0x2(%r13)
movb -0x1(%r14,%rbx), %al
movb %al, 0x3(%r13)
movb (%r14,%rbx), %al
movb %al, 0x4(%r13)
movb 0x1(%r14,%rbx), %al
movb %al, 0x5(%r13)
movq -0xa8(%rbp), %rcx
movb -0x1(%rcx,%rbx), %al
movb %al, 0x6(%r13)
movb (%rcx,%rbx), %al
movb %al, 0x7(%r13)
movb 0x1(%rcx,%rbx), %al
movb %al, 0x8(%r13)
testl %r10d, %r10d
je 0x2c49
movq %r13, %rdi
movq -0xa0(%rbp), %r12
movq %r12, %rsi
movq -0x98(%rbp), %rdx
callq 0x2e17
movq %r13, %rdi
movq %r12, %rsi
callq 0x2ef2
movq -0x68(%rbp), %r10
movl -0x2c(%rbp), %r9d
cmpl $0x4, %r9d
ja 0x2d4a
movl %r9d, %eax
leaq 0x13c3(%rip), %rcx      # 0x4020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb 0x4(%r13), %al
jmp 0x2d43
movq (%r13), %xmm0
movzbl 0x8(%r13), %eax
psadbw 0x138e(%rip), %xmm0     # 0x4010
movd %xmm0, %ecx
addl %eax, %ecx
imull $0xe38f, %ecx, %eax     # imm = 0xE38F
shrl $0x13, %eax
jmp 0x2d43
movd 0x2(%r13), %xmm0
punpcklbw 0x136c(%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(%r13), %eax
pshufd $0x55, %xmm0, %xmm1     # xmm1 = xmm0[1,1,1,1]
paddw %xmm0, %xmm1
movdqa %xmm1, %xmm0
psrld $0x10, %xmm0
paddw %xmm1, %xmm0
movd %xmm0, %ecx
addl %eax, %ecx
movzwl %cx, %eax
imull $0xcccd, %eax, %eax     # imm = 0xCCCD
shrl $0x12, %eax
jmp 0x2d43
movd 0x1(%r13), %xmm0
punpcklbw 0x132f(%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(%r13), %eax
movzbl 0x6(%r13), %ecx
movzbl 0x7(%r13), %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
movzwl %ax, %ecx
imull $0x2493, %ecx, %ecx     # imm = 0x2493
shrl $0x10, %ecx
subl %ecx, %eax
shrl %eax
addl %ecx, %eax
shrl $0x2, %eax
jmp 0x2d43
movzbl 0x3(%r13), %eax
movzbl 0x4(%r13), %ecx
addl %eax, %ecx
movzbl 0x5(%r13), %eax
addl %ecx, %eax
imull $0x5556, %eax, %eax     # imm = 0x5556
shrl $0x10, %eax
movq -0x48(%rbp), %rcx
movb %al, (%rcx,%rbx)
incq %rbx
cmpq %rbx, -0x50(%rbp)
jne 0x2bc6
movq -0x90(%rbp), %r11
incq %r11
movq -0x48(%rbp), %rax
addq -0x50(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x60(%rbp), %rcx
cmpq -0x58(%rbp), %rcx
movq -0x88(%rbp), %r12
jne 0x2b0f
movq -0x40(%rbp), %rdi
callq 0x2120
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x324f(%rip), %rdi      # 0x5ff0
leaq 0x137b(%rip), %rsi      # 0x4123
callq 0x20f0
movl $0x1, %edi
callq 0x2130
movl %r15d, %edi
callq 0x2230
movq -0x68(%rbp), %r10
movl -0x2c(%rbp), %r9d
jmp 0x2ac6