// File: devanshdalal[P]cloud-computing-concepts-part-2/MP1Node.cpp
// Function: MP1Node::recvCallBack(void*, char*, int)
bool MP1Node::recvCallBack(void *env, char *data, int size)
{
    /*
	 * Your code goes here
	 */
    MessageHdr *msg = (MessageHdr *)data;
    const auto current_time = par->getcurrtime();
    // multicast the membership list.
    vector<MemberListEntry> &memberList = memberNode->memberList;
    switch (msg->msgType)
    {
    case JOINREQ: // this is the introducer.
    {
        AddNode(*(int *)(msg + 1));

        size_t msgsize = sizeof(MessageHdr) + memberList.size() * sizeof(int);
        // cout << "msgsize: " << sizeof(MessageHdr) << " " << sizeof(joinaddr->addr) << " " << sizeof(long) << " " << 1 << "\n";
        MessageHdr *message = (MessageHdr *)malloc(msgsize * sizeof(char));
        message->msgType = JOINREP;
        int *fields = (int *)(message + 1);
        for (int i = 0; i < memberList.size(); ++i)
        {
            fields[i] = memberList[i].getid();
        }
        // multicast to the group.
        PublishToAll(*message, msgsize);
    }
    break;

    case JOINREP:
    {
        // std::cout << "JOINREP " << this_node_ << "\n";
        int nodes = (size - sizeof(MessageHdr)) / sizeof(int);
        int *fields = (int *)(msg + 1);
        for (int i = 0; i < nodes; ++i)
        {
            if (m_.find(fields[i]) != m_.end())
                continue;
            AddNode(fields[i]);
        }
    }
    break;

    case PING:
    {
        const int &src = *(int *)(msg + 1);
        const int &dest = *((int *)(msg + 1) + 1);
        // std::cout << "PING " << this_node_ << " " << src << " " << dest << "\n";
        if (dest == this_node_)
        {
            // send a PONG to the requesting node.
            auto *message = CreateMessage(PONG, this_node_, src);
            Address a(std::to_string(src) + ":0");
            // memcpy(&a.addr, (char *)(msg + 1), sizeof(a.addr));
            emulNet->ENsend(&memberNode->addr, &a, (char *)message, MSGSIZE); // no need to check status
            // local_state_[src] = {FINALWAITING, current_time + WAITING_TIMEOUT, -1};
            free(msg);
        }
        else
        {
            // std::cout << "Indirect PING\n";
            // send a PING to the requested node and later send PONG back to the client to the requesting node.
            auto *message = CreateMessage(PING, this_node_, dest);
            Address a(std::to_string(dest) + ":0");
            emulNet->ENsend(&memberNode->addr, &a, (char *)message, MSGSIZE); // no need to check status
            local_state_[dest] = {FINALWAITING, current_time + WAITING_TIMEOUT, src};
            free(msg);
        }
    }
    break;

    case PONG:
    {
        const int &src = *(int *)(msg + 1);
        // const int &dest = *((int *)(msg + 1) + 1);
        // std::cout << "PONG " << this_node_ << " " << src << " " << dest << "\n";
        auto it = local_state_.find(src);
        if (it != local_state_.end())
        {
            NodeStatus &status = it->second;
            // std::cout << "PONG2 " << status.state << "a\n";
            switch (status.state)
            {
            case TIMEOUTWAITING:
                break;
            case SWIMWAITING:
                break;
            case FINALWAITING:
            {
                // std::cout << "FINALWAITING\n";
                auto *message = CreateMessage(PONG, src, status.node);
                Address a(std::to_string(status.node) + ":0");
                emulNet->ENsend(&memberNode->addr, &a, (char *)message, MSGSIZE);
                free(msg);
            }
            break;
            default:
                break;
            }
        }
        local_state_.erase(src);
        for (auto jt = local_state_.begin(); jt != local_state_.end(); ++jt)
        {
            // std::cout << "local_stateeee: " << jt->first << " " << jt->second.state << " " << jt->second.timeout << jt->second.node << "\n";
        }
        if (m_.find(src) == m_.end())
        {
            // std::cout << "Special case\n";
            // AddNode(src);
        }
    }
    break;

    case FAILED:
    {
        const int &failed = *(int *)(msg + 1);
        // std::cout << "FAILED " << failed << " " << this_node_ << " " << (m_.find(failed) != m_.end()) << " " << m_.size() << " " << memberList.size() << "\n";
        if (m_.find(failed) != m_.end())
        {
            m_.erase(failed);
            for (int i = 0; i < memberList.size(); ++i)
            {
                if (memberList[i].getid() == failed)
                {
                    memberList.erase(memberList.begin() + i);
                    break;
                }
            }
            Address a(std::to_string(failed) + ":0");
#ifdef DEBUGLOG
            log->logNodeRemove(&memberNode->addr, &a);
#endif
        }
    }
    break;

    default:
        break;
    }
    return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2c0, %rsp            # imm = 0x2C0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x278(%rbp)
movq -0x18(%rbp), %rcx
movq %rcx, -0x28(%rbp)
movq 0x18(%rax), %rdi
callq 0x17080
movl %eax, %ecx
movq -0x278(%rbp), %rax
movl %ecx, -0x2c(%rbp)
movq 0x20(%rax), %rax
addq $0x28, %rax
movq %rax, -0x38(%rbp)
movq -0x28(%rbp), %rax
movl (%rax), %eax
movq %rax, -0x270(%rbp)
subq $0x4, %rax
ja 0x5dcb
movq -0x270(%rbp), %rax
leaq 0x24ad1(%rip), %rcx     # 0x2a004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x278(%rbp), %rdi
movq -0x28(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x4f80
movq -0x38(%rbp), %rdi
callq 0x6ad0
shlq $0x2, %rax
addq $0x4, %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
shlq $0x0, %rdi
callq 0x4460
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movl $0x1, (%rax)
movq -0x48(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x50(%rbp)
movl $0x0, -0x54(%rbp)
movslq -0x54(%rbp), %rax
movq %rax, -0x280(%rbp)
movq -0x38(%rbp), %rdi
callq 0x6ad0
movq %rax, %rcx
movq -0x280(%rbp), %rax
cmpq %rcx, %rax
jae 0x55e2
movq -0x38(%rbp), %rdi
movslq -0x54(%rbp), %rsi
callq 0x6b00
movq %rax, %rdi
callq 0x172a0
movl %eax, %edx
movq -0x50(%rbp), %rax
movslq -0x54(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
jmp 0x5592
movq -0x278(%rbp), %rdi
movq -0x48(%rbp), %rsi
movq -0x40(%rbp), %rdx
callq 0x5df0
jmp 0x5dcd
movslq -0x1c(%rbp), %rax
subq $0x4, %rax
shrq $0x2, %rax
movl %eax, -0x58(%rbp)
movq -0x28(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x60(%rbp)
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x58(%rbp), %eax
jge 0x5693
movq -0x278(%rbp), %rdi
addq $0x30, %rdi
movq -0x60(%rbp), %rsi
movslq -0x64(%rbp), %rax
shlq $0x2, %rax
addq %rax, %rsi
callq 0x6670
movq -0x278(%rbp), %rdi
movq %rax, -0x70(%rbp)
addq $0x30, %rdi
callq 0x66a0
movq %rax, -0x78(%rbp)
leaq -0x70(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x6640
testb $0x1, %al
jne 0x566f
jmp 0x5671
jmp 0x5688
movq -0x278(%rbp), %rdi
movq -0x60(%rbp), %rax
movslq -0x64(%rbp), %rcx
movl (%rax,%rcx,4), %esi
callq 0x4f80
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x561d
jmp 0x5dcd
movq -0x278(%rbp), %rcx
movq -0x28(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x80(%rbp)
movq -0x28(%rbp), %rax
addq $0x4, %rax
addq $0x4, %rax
movq %rax, -0x88(%rbp)
movq -0x88(%rbp), %rax
movl (%rax), %eax
cmpl 0xa4(%rcx), %eax
jne 0x57d6
movq -0x278(%rbp), %rax
movl 0xa4(%rax), %esi
movq -0x80(%rbp), %rax
movl (%rax), %edx
movl $0x4, %edi
callq 0x6010
movq %rax, -0x90(%rbp)
movq -0x80(%rbp), %rax
movl (%rax), %esi
leaq -0xd8(%rbp), %rdi
movq %rdi, -0x288(%rbp)
callq 0x67e0
movq -0x288(%rbp), %rsi
leaq 0x24974(%rip), %rdx     # 0x2a092
leaq -0xb8(%rbp), %rdi
callq 0x6790
jmp 0x572c
leaq -0x96(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x6900
jmp 0x5741
leaq -0xb8(%rbp), %rdi
callq 0x41e0
leaq -0xd8(%rbp), %rdi
callq 0x41e0
movq -0x278(%rbp), %rax
movq 0x8(%rax), %rdi
movq 0x20(%rax), %rsi
addq $0x8, %rsi
movq -0x90(%rbp), %rcx
leaq -0x96(%rbp), %rdx
movl $0xc, %r8d
callq 0xcad0
movq -0x28(%rbp), %rdi
callq 0x43e0
jmp 0x5938
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
jmp 0x57c5
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
leaq -0xb8(%rbp), %rdi
callq 0x41e0
leaq -0xd8(%rbp), %rdi
callq 0x41e0
jmp 0x5dda
movq -0x278(%rbp), %rax
movl 0xa4(%rax), %esi
movq -0x88(%rbp), %rax
movl (%rax), %edx
movl $0x3, %edi
callq 0x6010
movq %rax, -0xf0(%rbp)
movq -0x88(%rbp), %rax
movl (%rax), %esi
leaq -0x138(%rbp), %rdi
movq %rdi, -0x290(%rbp)
callq 0x67e0
movq -0x290(%rbp), %rsi
leaq 0x2486b(%rip), %rdx     # 0x2a092
leaq -0x118(%rbp), %rdi
callq 0x6790
jmp 0x5835
leaq -0xf6(%rbp), %rdi
leaq -0x118(%rbp), %rsi
callq 0x6900
jmp 0x584a
leaq -0x118(%rbp), %rdi
callq 0x41e0
leaq -0x138(%rbp), %rdi
callq 0x41e0
movq -0x278(%rbp), %rax
movq 0x8(%rax), %rdi
movq 0x20(%rax), %rsi
addq $0x8, %rsi
movq -0xf0(%rbp), %rcx
leaq -0xf6(%rbp), %rdx
movl $0xc, %r8d
callq 0xcad0
movq -0x278(%rbp), %rdi
movl $0x2, -0x150(%rbp)
movl -0x2c(%rbp), %eax
addl $0xa, %eax
cltq
movq %rax, -0x148(%rbp)
movq -0x80(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x140(%rbp)
addq $0x68, %rdi
movq -0x88(%rbp), %rsi
callq 0x6b20
movq -0x150(%rbp), %rcx
movq %rcx, (%rax)
movq -0x148(%rbp), %rcx
movq %rcx, 0x8(%rax)
movq -0x140(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq -0x28(%rbp), %rdi
callq 0x43e0
jmp 0x5938
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
jmp 0x5927
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
leaq -0x118(%rbp), %rdi
callq 0x41e0
leaq -0x138(%rbp), %rdi
callq 0x41e0
jmp 0x5dda
jmp 0x5dcd
movq -0x278(%rbp), %rdi
movq -0x28(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x158(%rbp)
addq $0x68, %rdi
movq -0x158(%rbp), %rsi
callq 0x6b50
movq -0x278(%rbp), %rdi
movq %rax, -0x160(%rbp)
addq $0x68, %rdi
callq 0x6bb0
movq %rax, -0x168(%rbp)
leaq -0x160(%rbp), %rdi
leaq -0x168(%rbp), %rsi
callq 0x6b80
testb $0x1, %al
jne 0x599d
jmp 0x5af8
leaq -0x160(%rbp), %rdi
callq 0x6be0
addq $0x8, %rax
movq %rax, -0x170(%rbp)
movq -0x170(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x294(%rbp)
testl %eax, %eax
je 0x59e6
jmp 0x59c9
movl -0x294(%rbp), %eax
subl $0x1, %eax
je 0x59eb
jmp 0x59d6
movl -0x294(%rbp), %eax
subl $0x2, %eax
je 0x59f0
jmp 0x5af4
jmp 0x5af6
jmp 0x5af6
movq -0x158(%rbp), %rax
movl (%rax), %esi
movq -0x170(%rbp), %rax
movl 0x10(%rax), %edx
movl $0x4, %edi
callq 0x6010
movq %rax, -0x178(%rbp)
movq -0x170(%rbp), %rax
movl 0x10(%rax), %esi
leaq -0x1c0(%rbp), %rdi
movq %rdi, -0x2a0(%rbp)
callq 0x67e0
movq -0x2a0(%rbp), %rsi
leaq 0x24653(%rip), %rdx     # 0x2a092
leaq -0x1a0(%rbp), %rdi
callq 0x6790
jmp 0x5a4d
leaq -0x17e(%rbp), %rdi
leaq -0x1a0(%rbp), %rsi
callq 0x6900
jmp 0x5a62
leaq -0x1a0(%rbp), %rdi
callq 0x41e0
leaq -0x1c0(%rbp), %rdi
callq 0x41e0
movq -0x278(%rbp), %rax
movq 0x8(%rax), %rdi
movq 0x20(%rax), %rsi
addq $0x8, %rsi
movq -0x178(%rbp), %rcx
leaq -0x17e(%rbp), %rdx
movl $0xc, %r8d
callq 0xcad0
movq -0x28(%rbp), %rdi
callq 0x43e0
jmp 0x5af6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
jmp 0x5ae3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
leaq -0x1a0(%rbp), %rdi
callq 0x41e0
leaq -0x1c0(%rbp), %rdi
callq 0x41e0
jmp 0x5dda
jmp 0x5af6
jmp 0x5af8
movq -0x278(%rbp), %rdi
addq $0x68, %rdi
movq -0x158(%rbp), %rsi
callq 0x6c10
movq -0x278(%rbp), %rdi
addq $0x68, %rdi
callq 0x6c40
movq %rax, -0x1c8(%rbp)
movq -0x278(%rbp), %rdi
addq $0x68, %rdi
callq 0x6bb0
movq %rax, -0x1d0(%rbp)
leaq -0x1c8(%rbp), %rdi
leaq -0x1d0(%rbp), %rsi
callq 0x6b80
testb $0x1, %al
jne 0x5b56
jmp 0x5b66
jmp 0x5b58
leaq -0x1c8(%rbp), %rdi
callq 0x6c70
jmp 0x5b26
movq -0x278(%rbp), %rdi
addq $0x30, %rdi
movq -0x158(%rbp), %rsi
callq 0x6670
movq -0x278(%rbp), %rdi
movq %rax, -0x1d8(%rbp)
addq $0x30, %rdi
callq 0x66a0
movq %rax, -0x1e0(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq -0x1e0(%rbp), %rsi
callq 0x6ca0
testb $0x1, %al
jne 0x5bb4
jmp 0x5bb6
jmp 0x5bb6
jmp 0x5dcd
movq -0x278(%rbp), %rdi
movq -0x28(%rbp), %rax
addq $0x4, %rax
movq %rax, -0x1e8(%rbp)
addq $0x30, %rdi
movq -0x1e8(%rbp), %rsi
callq 0x6670
movq -0x278(%rbp), %rdi
movq %rax, -0x1f0(%rbp)
addq $0x30, %rdi
callq 0x66a0
movq %rax, -0x1f8(%rbp)
leaq -0x1f0(%rbp), %rdi
leaq -0x1f8(%rbp), %rsi
callq 0x6640
testb $0x1, %al
jne 0x5c1b
jmp 0x5dc9
movq -0x278(%rbp), %rdi
addq $0x30, %rdi
movq -0x1e8(%rbp), %rsi
callq 0x6cd0
movl $0x0, -0x1fc(%rbp)
movslq -0x1fc(%rbp), %rax
movq %rax, -0x2a8(%rbp)
movq -0x38(%rbp), %rdi
callq 0x6ad0
movq %rax, %rcx
movq -0x2a8(%rbp), %rax
cmpq %rcx, %rax
jae 0x5d03
movq -0x38(%rbp), %rdi
movslq -0x1fc(%rbp), %rsi
callq 0x6b00
movq %rax, %rdi
callq 0x172a0
movq -0x1e8(%rbp), %rcx
cmpl (%rcx), %eax
jne 0x5ced
movq -0x38(%rbp), %rax
movq %rax, -0x2b0(%rbp)
movq -0x38(%rbp), %rdi
callq 0x6d70
movq %rax, -0x218(%rbp)
movslq -0x1fc(%rbp), %rsi
leaq -0x218(%rbp), %rdi
callq 0x6da0
movq %rax, -0x210(%rbp)
leaq -0x208(%rbp), %rdi
leaq -0x210(%rbp), %rsi
callq 0x6de0
movq -0x2b0(%rbp), %rdi
movq -0x208(%rbp), %rsi
callq 0x6d00
movq %rax, -0x220(%rbp)
jmp 0x5d03
jmp 0x5cef
movl -0x1fc(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1fc(%rbp)
jmp 0x5c3c
movq -0x1e8(%rbp), %rax
movl (%rax), %esi
leaq -0x268(%rbp), %rdi
movq %rdi, -0x2b8(%rbp)
callq 0x67e0
movq -0x2b8(%rbp), %rsi
leaq 0x24365(%rip), %rdx     # 0x2a092
leaq -0x248(%rbp), %rdi
callq 0x6790
jmp 0x5d3b
leaq -0x226(%rbp), %rdi
leaq -0x248(%rbp), %rsi
callq 0x6900
jmp 0x5d50
leaq -0x248(%rbp), %rdi
callq 0x41e0
leaq -0x268(%rbp), %rdi
callq 0x41e0
movq -0x278(%rbp), %rax
movq 0x10(%rax), %rdi
movq 0x20(%rax), %rsi
addq $0x8, %rsi
leaq -0x226(%rbp), %rdx
callq 0x16440
jmp 0x5dc9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
jmp 0x5dbb
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
leaq -0x248(%rbp), %rdi
callq 0x41e0
leaq -0x268(%rbp), %rdi
callq 0x41e0
jmp 0x5dda
jmp 0x5dcd
jmp 0x5dcd
movb $0x1, %al
andb $0x1, %al
addq $0x2c0, %rsp            # imm = 0x2C0
popq %rbp
retq
movq -0xe0(%rbp), %rdi
callq 0x4570
nopw %cs:(%rax,%rax)