// File: maclellant[P]ReliableGoBackN/server.cpp
// Function: gremlin(char*, int, int, int)
int gremlin(char *data, int corrupt_chance, int loss_chance, int delay_chance)
{
    if (corrupt_chance < 0)
        corrupt_chance = 0;
    if (corrupt_chance > 100)
        corrupt_chance = 100;
    if (loss_chance < 0)
        loss_chance = 0;
    if (loss_chance > 100)
        loss_chance = 100;
    if (delay_chance < 0)
        delay_chance = 0;
    if (delay_chance > 100)
        delay_chance = 100;
    int corrupt_roll = rand() % 101;
    int loss_roll = rand() % 101;
    int delay_roll = rand() % 101;
    if (loss_roll <= loss_chance) 
    {
        return LOST;
    }
    if (corrupt_roll <= corrupt_chance)
    {
        int num_corrupt = rand() % 101;
        if (num_corrupt <= 70)
        {
            int corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            data[corrupt_byte] = ~data[corrupt_byte];
        }
        else if (num_corrupt <= 90)
        {
            int corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            data[corrupt_byte] = ~data[corrupt_byte];

            int prev_corrupt = corrupt_byte;
            while (prev_corrupt == corrupt_byte)
            {
                corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            }
            data[corrupt_byte] = ~data[corrupt_byte];
        }
        else
        {
            int corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            data[corrupt_byte] = ~data[corrupt_byte];

            int prev_corrupt1 = corrupt_byte;
            while (prev_corrupt1 == corrupt_byte)
            {
                corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            }
            data[corrupt_byte] = ~data[corrupt_byte];

            int prev_corrupt2 = corrupt_byte;
            while (prev_corrupt1 == corrupt_byte
                || prev_corrupt2 == corrupt_byte)
            {
                corrupt_byte = rand() % (PACKET_SIZE - HEADER_SIZE);
            }
            data[corrupt_byte] = ~data[corrupt_byte];
        }
    }
    if (delay_roll <= delay_chance)
    {
        return DELAYED;
    }
    return FINE;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
cmpl $0x0, -0x14(%rbp)
jge 0x3842
movl $0x0, -0x14(%rbp)
cmpl $0x64, -0x14(%rbp)
jle 0x384f
movl $0x64, -0x14(%rbp)
cmpl $0x0, -0x18(%rbp)
jge 0x385c
movl $0x0, -0x18(%rbp)
cmpl $0x64, -0x18(%rbp)
jle 0x3869
movl $0x64, -0x18(%rbp)
cmpl $0x0, -0x1c(%rbp)
jge 0x3876
movl $0x0, -0x1c(%rbp)
cmpl $0x64, -0x1c(%rbp)
jle 0x3883
movl $0x64, -0x1c(%rbp)
callq 0x20a0
movl $0x65, %ecx
cltd
idivl %ecx
movl %edx, -0x20(%rbp)
callq 0x20a0
movl $0x65, %ecx
cltd
idivl %ecx
movl %edx, -0x24(%rbp)
callq 0x20a0
movl $0x65, %ecx
cltd
idivl %ecx
movl %edx, -0x28(%rbp)
movl -0x24(%rbp), %eax
cmpl -0x18(%rbp), %eax
jg 0x38c7
movl $0x1, -0x4(%rbp)
jmp 0x3a67
movl -0x20(%rbp), %eax
cmpl -0x14(%rbp), %eax
jg 0x3a4f
callq 0x20a0
movl $0x65, %ecx
cltd
idivl %ecx
movl %edx, -0x2c(%rbp)
cmpl $0x46, -0x2c(%rbp)
jg 0x391a
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x30(%rbp)
movq -0x10(%rbp), %rax
movslq -0x30(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x30(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x3a4d
cmpl $0x5a, -0x2c(%rbp)
jg 0x398d
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x34(%rbp)
movq -0x10(%rbp), %rax
movslq -0x34(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x34(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x34(%rbp), %eax
movl %eax, -0x38(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x34(%rbp), %eax
jne 0x396c
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x34(%rbp)
jmp 0x3952
movq -0x10(%rbp), %rax
movslq -0x34(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x34(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x3a4b
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x3c(%rbp)
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x3c(%rbp), %eax
movl %eax, -0x40(%rbp)
movl -0x40(%rbp), %eax
cmpl -0x3c(%rbp), %eax
jne 0x39d9
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x3c(%rbp)
jmp 0x39bf
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movb %dl, (%rax,%rcx)
movl -0x3c(%rbp), %eax
movl %eax, -0x44(%rbp)
movl -0x40(%rbp), %ecx
movb $0x1, %al
cmpl -0x3c(%rbp), %ecx
movb %al, -0x45(%rbp)
je 0x3a14
movl -0x44(%rbp), %eax
cmpl -0x3c(%rbp), %eax
sete %al
movb %al, -0x45(%rbp)
movb -0x45(%rbp), %al
testb $0x1, %al
jne 0x3a1d
jmp 0x3a2f
callq 0x20a0
movl $0x1fa, %ecx            # imm = 0x1FA
cltd
idivl %ecx
movl %edx, -0x3c(%rbp)
jmp 0x39fb
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movsbl (%rax,%rcx), %eax
xorl $-0x1, %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x3a4d
jmp 0x3a4f
movl -0x28(%rbp), %eax
cmpl -0x1c(%rbp), %eax
jg 0x3a60
movl $0x2, -0x4(%rbp)
jmp 0x3a67
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x50, %rsp
popq %rbp
retq