// File: /workspace/github_c_makefile_star2_O0/MAGI003769[P]EE450-Socket-Project/aws.c
// Function: main
int main(void) {
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
	int udp_sock;
	struct sockaddr_storage their_addr; // connector's address information
	socklen_t sin_size; // used for accept()
	char s[INET6_ADDRSTRLEN];
	int numbytes; //using in receive or send

    char message_buf[100];  // temp saving place for receiving from client though TCP
    char result_buf[100]; // temp saving place for sending results to client though TCP
    char udp_send[50];
    char udp_received[MAXBUFLEN];  // buffer to receive map data from backend server
    char queryC[MAXBUFLEN];      // buffer to merge args from client and data from server A or B
    char *splited_args[4];
    char *parsed_results[5];    // {shortest_dist, trans_delay, prop_delay, total_delay, ans_path}

    int has_map_id = 0;
    int vtx_valid = 0;

	sockfd = setupTCP(PORTCLIENT);
    udp_sock = setupUDP2(UDPPORT);
	//printf("debug: sockfd is %d\n", sockfd);
	//printf("debug: sockfd_monitor is %d\n", sockfd_monitor);
	printf("The AWS is up and running.\n");
    
    printf("server: waiting for connections...\n");

    while(1) {
        has_map_id = 0;
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if(new_fd == -1) {
            perror("accept");
            continue;
        }

        inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
        printf("server: got connection from %s\n", s);

        if(!fork()) {
            close(sockfd);

            // receive arguments as single string
            if((numbytes = recv(new_fd, message_buf, sizeof message_buf, 0)) == -1) {
                perror("recv");
                exit(1);
            }
            message_buf[numbytes] = '\0';
            fflush(stdout);
            //printf("The received message is: %s\n", message_buf);

            // split received string of args into multiple string
            split_args2(splited_args, message_buf);
            printf("The AWS has received map ID %s, start vertex %s, destination vertex %s and file size %s from the client using TCP over port %s\n", splited_args[0], splited_args[1], splited_args[2], splited_args[3], UDPPORT);
            

            // merge map_id, source_vtx and target_vtx server
            sprintf(udp_send, "%s %s %s", splited_args[0], splited_args[1], splited_args[2]);

            // make a udp query from AWS to backend server A
            //udpQuery(udp_send, SERVERPORTA, udp_received);
            //printf("debug: udp sending %s\n", udp_send);
            udpQuery2(udp_sock, udp_send, SERVERPORTA, udp_received);
            //strcpy(udp_received, recvTmp);
            //printf("debug: udp received %lu\n", strlen(udp_received));

            // printf("debug: %s\n", udp_received);
            if(strcmp(udp_received, MAPNOTFOUND) != 0) {
                printf("The AWS has received map information from server A\n");
                has_map_id = 1;
            } else {
                //printf("debug: Try server B\n");

                // if map id cannot be found in server A, try server B
                memset(&udp_received, 0, sizeof udp_received);
                //udpQuery(udp_send, SERVERPORTB, udp_received);
                udpQuery2(udp_sock, udp_send, SERVERPORTB, udp_received);

                if(strcmp(udp_received, MAPNOTFOUND) != 0) {
                    printf("The AWS has received map information from server B\n");
                    has_map_id = 1;
                } else {
                    printf("debug: Ummm, no map id anywhere...\n");
                    has_map_id = 0;
                }
            }

            if(has_map_id == 1) {
                // As map has been found, check source (splited_args[1]) and target (splited_target[2]) are valid or not
                sprintf(queryC, "%s %s %s\n%s", splited_args[1], splited_args[2], splited_args[3], udp_received);
                vtx_valid = check_vtx(splited_args[1], splited_args[2], udp_received);
                switch (vtx_valid) {
                    // Source not found, target found
                    case 10:
                        sprintf(result_buf, "No vertex id %s found", splited_args[1]);
                        if (send(new_fd, result_buf, strlen(result_buf), 0) == -1) {
                            perror("send");
                        }
                        printf("Source vertex (%s) not found in the graph, sending error to client using TCP over port %s\n", splited_args[1], PORTCLIENT);
                        break;
                    
                    // Source found, target not found
                    case 1:
                        sprintf(result_buf, "No vertex id %s found", splited_args[2]);
                        if (send(new_fd, result_buf, strlen(result_buf), 0) == -1) {
                            perror("send");
                        }
                        printf("Target vertex (%s) not found in the graph, sending error to client using TCP over port %s\n", splited_args[2], PORTCLIENT);
                        break;
                    
                    // Source not found, target not found
                    case 0:
                        sprintf(result_buf, "No vetex id %s and %s found", splited_args[1], splited_args[2]);
                        if (send(new_fd, result_buf, strlen(result_buf), 0) == -1) {
                            perror("send");
                        }
                        printf("Both source (%s) and target (%s) not found in the graph, sending error to client using TCP over port %s\n", splited_args[1], splited_args[2], PORTCLIENT);
                        break;
                    
                    // Both found
                    default:
                        //printf("debug: Yeah! All found!\n");
                        //printf("debug: AWS send %s to server-C\n", queryC);
                        //udpQuery(queryC, SERVERPORTC, result_buf);
                        udpQuery2(udp_sock, queryC, SERVERPORTC, result_buf);
                        printf("The source and destination vertex are in the graph\n");
                        printf("The AWS has sent calculated results to client using TCP over port %s\n", PORTCLIENT);
                        parse_result(parsed_results, result_buf);
                        printf("The AWS has received the result from server C: \n");
                        printf("Shortest path: %s\n", parsed_results[4]);
                        printf("Shortest distance: %s\n", parsed_results[0]);
                        printf("Transmission delay: %s\n", parsed_results[1]);
                        printf("Propagation delay: %s\n", parsed_results[2]);
                        // rewrite the result buffer
                        //memset(&result_buf, 0, sizeof result_buf);
                        sprintf(result_buf, "%s\n%s\n%s\n%s\n%s", parsed_results[0], parsed_results[1], parsed_results[2], parsed_results[3], parsed_results[4]);
                        //printf("debug: sent %s back to client\n", result_buf);
                        if (send(new_fd, result_buf, strlen(result_buf), 0) == -1) {
                            perror("send");
                        }
                        printf("The AWS has sent calculated results to client using TCP over port %s\n", PORTCLIENT);
                        break;
                }
            } else {
                // Send error of no map to client
                sprintf(result_buf, "No map %s found", splited_args[0]);
                if (send(new_fd, result_buf, strlen(result_buf), 0) == -1) {
                    perror("send");
                }
            }
            
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x21f0, %rsp           # imm = 0x21F0
movl $0x0, -0x4(%rbp)
movl $0x0, -0x2184(%rbp)
movl $0x0, -0x2188(%rbp)
leaq 0x1644(%rip), %rdi      # 0x31c1
callq 0x1480
movl %eax, -0x8(%rbp)
leaq 0x1566(%rip), %rdi      # 0x30f2
callq 0x1690
movl %eax, -0x10(%rbp)
leaq 0x162c(%rip), %rdi      # 0x31c7
movb $0x0, %al
callq 0x10b0
leaq 0x163a(%rip), %rdi      # 0x31e3
movb $0x0, %al
callq 0x10b0
movl $0x0, -0x2184(%rbp)
movl $0x80, -0x94(%rbp)
movl -0x8(%rbp), %edi
leaq -0x90(%rbp), %rsi
leaq -0x94(%rbp), %rdx
callq 0x11a0
movl %eax, -0xc(%rbp)
cmpl $-0x1, -0xc(%rbp)
jne 0x1bf1
leaq 0x161d(%rip), %rdi      # 0x3207
callq 0x1180
jmp 0x1bb0
movzwl -0x90(%rbp), %eax
movl %eax, -0x218c(%rbp)
leaq -0x90(%rbp), %rdi
callq 0x1360
movl -0x218c(%rbp), %edi
movq %rax, %rsi
leaq -0xd0(%rbp), %rdx
movl $0x2e, %ecx
callq 0x1030
leaq -0xd0(%rbp), %rsi
leaq 0x15dc(%rip), %rdi      # 0x320e
movb $0x0, %al
callq 0x10b0
callq 0x11e0
cmpl $0x0, %eax
jne 0x21f0
movl -0x8(%rbp), %edi
callq 0x10f0
movl -0xc(%rbp), %edi
leaq -0x140(%rbp), %rsi
movl $0x64, %edx
xorl %ecx, %ecx
callq 0x1040
movl %eax, -0xd4(%rbp)
cmpl $-0x1, %eax
jne 0x1c86
leaq 0x15b7(%rip), %rdi      # 0x322e
callq 0x1180
movl $0x1, %edi
callq 0x11c0
movslq -0xd4(%rbp), %rax
movb $0x0, -0x140(%rbp,%rax)
movq 0x333c(%rip), %rax      # 0x4fd8
movq (%rax), %rdi
callq 0x1130
leaq -0x2150(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x13a0
movq -0x2150(%rbp), %rsi
movq -0x2148(%rbp), %rdx
movq -0x2140(%rbp), %rcx
movq -0x2138(%rbp), %r8
leaq 0x1559(%rip), %rdi      # 0x3233
leaq 0x1411(%rip), %r9       # 0x30f2
movb $0x0, %al
callq 0x10b0
leaq -0x1f0(%rbp), %rdi
movq -0x2150(%rbp), %rdx
movq -0x2148(%rbp), %rcx
movq -0x2140(%rbp), %r8
leaq 0x15a8(%rip), %rsi      # 0x32b3
movb $0x0, %al
callq 0x11b0
movl -0x10(%rbp), %edi
leaq -0x1f0(%rbp), %rsi
leaq -0x1190(%rbp), %rcx
leaq 0x1386(%rip), %rdx      # 0x30b0
callq 0x17e0
leaq -0x1190(%rbp), %rdi
leaq 0x157f(%rip), %rsi      # 0x32bc
callq 0x1110
cmpl $0x0, %eax
je 0x1d61
leaq 0x157c(%rip), %rdi      # 0x32ca
movb $0x0, %al
callq 0x10b0
movl $0x1, -0x2184(%rbp)
jmp 0x1ddd
leaq -0x1190(%rbp), %rdi
xorl %esi, %esi
movl $0xfa0, %edx            # imm = 0xFA0
callq 0x10d0
movl -0x10(%rbp), %edi
leaq -0x1f0(%rbp), %rsi
leaq -0x1190(%rbp), %rcx
leaq 0x136c(%rip), %rdx      # 0x30f8
callq 0x17e0
leaq -0x1190(%rbp), %rdi
leaq 0x151d(%rip), %rsi      # 0x32bc
callq 0x1110
cmpl $0x0, %eax
je 0x1dc3
leaq 0x154e(%rip), %rdi      # 0x32fe
movb $0x0, %al
callq 0x10b0
movl $0x1, -0x2184(%rbp)
jmp 0x1ddb
leaq 0x1568(%rip), %rdi      # 0x3332
movb $0x0, %al
callq 0x10b0
movl $0x0, -0x2184(%rbp)
jmp 0x1ddd
cmpl $0x1, -0x2184(%rbp)
jne 0x2177
movq -0x2148(%rbp), %rdx
movq -0x2140(%rbp), %rcx
movq -0x2138(%rbp), %r8
leaq 0x1550(%rip), %rsi      # 0x3356
xorl %eax, %eax
leaq -0x2130(%rbp), %rdi
leaq -0x1190(%rbp), %r9
movq %r9, -0x2198(%rbp)
callq 0x11b0
movq -0x2198(%rbp), %rdx
movq -0x2148(%rbp), %rdi
movq -0x2140(%rbp), %rsi
callq 0x1a10
movl %eax, -0x2188(%rbp)
movl -0x2188(%rbp), %eax
movl %eax, -0x2190(%rbp)
testl %eax, %eax
je 0x1f8c
jmp 0x1e58
movl -0x2190(%rbp), %eax
subl $0x1, %eax
je 0x1f03
jmp 0x1e69
movl -0x2190(%rbp), %eax
subl $0xa, %eax
jne 0x2023
jmp 0x1e7a
leaq -0x1b0(%rbp), %rdi
movq -0x2148(%rbp), %rdx
leaq 0x14d3(%rip), %rsi      # 0x3362
movb $0x0, %al
callq 0x11b0
movl -0xc(%rbp), %eax
movl %eax, -0x21a4(%rbp)
leaq -0x1b0(%rbp), %rax
movq %rax, -0x21a0(%rbp)
leaq -0x1b0(%rbp), %rdi
callq 0x1090
movl -0x21a4(%rbp), %edi
movq -0x21a0(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10a0
cmpq $-0x1, %rax
jne 0x1ee2
leaq 0x149b(%rip), %rdi      # 0x3378
callq 0x1180
movq -0x2148(%rbp), %rsi
leaq 0x148d(%rip), %rdi      # 0x337d
leaq 0x12ca(%rip), %rdx      # 0x31c1
movb $0x0, %al
callq 0x10b0
jmp 0x2175
leaq -0x1b0(%rbp), %rdi
movq -0x2140(%rbp), %rdx
leaq 0x144a(%rip), %rsi      # 0x3362
movb $0x0, %al
callq 0x11b0
movl -0xc(%rbp), %eax
movl %eax, -0x21b4(%rbp)
leaq -0x1b0(%rbp), %rax
movq %rax, -0x21b0(%rbp)
leaq -0x1b0(%rbp), %rdi
callq 0x1090
movl -0x21b4(%rbp), %edi
movq -0x21b0(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10a0
cmpq $-0x1, %rax
jne 0x1f6b
leaq 0x1412(%rip), %rdi      # 0x3378
callq 0x1180
movq -0x2140(%rbp), %rsi
leaq 0x145f(%rip), %rdi      # 0x33d8
leaq 0x1241(%rip), %rdx      # 0x31c1
movb $0x0, %al
callq 0x10b0
jmp 0x2175
leaq -0x1b0(%rbp), %rdi
movq -0x2148(%rbp), %rdx
movq -0x2140(%rbp), %rcx
leaq 0x148b(%rip), %rsi      # 0x3433
movb $0x0, %al
callq 0x11b0
movl -0xc(%rbp), %eax
movl %eax, -0x21c4(%rbp)
leaq -0x1b0(%rbp), %rax
movq %rax, -0x21c0(%rbp)
leaq -0x1b0(%rbp), %rdi
callq 0x1090
movl -0x21c4(%rbp), %edi
movq -0x21c0(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10a0
cmpq $-0x1, %rax
jne 0x1ffb
leaq 0x1382(%rip), %rdi      # 0x3378
callq 0x1180
movq -0x2148(%rbp), %rsi
movq -0x2140(%rbp), %rdx
leaq 0x143f(%rip), %rdi      # 0x344f
leaq 0x11aa(%rip), %rcx      # 0x31c1
movb $0x0, %al
callq 0x10b0
jmp 0x2175
movl -0x10(%rbp), %edi
leaq -0x2130(%rbp), %rsi
leaq -0x1b0(%rbp), %rcx
leaq 0x147d(%rip), %rdx      # 0x34b8
callq 0x17e0
leaq 0x1477(%rip), %rdi      # 0x34be
movb $0x0, %al
callq 0x10b0
leaq 0x149d(%rip), %rdi      # 0x34f2
leaq 0x1165(%rip), %rsi      # 0x31c1
movb $0x0, %al
callq 0x10b0
leaq -0x2180(%rbp), %rdi
leaq -0x1b0(%rbp), %rsi
callq 0x1410
leaq 0x14bb(%rip), %rdi      # 0x3538
movb $0x0, %al
callq 0x10b0
movq -0x2160(%rbp), %rsi
leaq 0x14d7(%rip), %rdi      # 0x3569
movb $0x0, %al
callq 0x10b0
movq -0x2180(%rbp), %rsi
leaq 0x14d5(%rip), %rdi      # 0x357c
movb $0x0, %al
callq 0x10b0
movq -0x2178(%rbp), %rsi
leaq 0x14d7(%rip), %rdi      # 0x3593
movb $0x0, %al
callq 0x10b0
movq -0x2170(%rbp), %rsi
leaq 0x14da(%rip), %rdi      # 0x35ab
movb $0x0, %al
callq 0x10b0
leaq -0x1b0(%rbp), %rdi
movq -0x2180(%rbp), %rdx
movq -0x2178(%rbp), %rcx
movq -0x2170(%rbp), %r8
movq -0x2168(%rbp), %r9
movq -0x2160(%rbp), %rax
leaq 0x14b9(%rip), %rsi      # 0x35c2
movq %rax, (%rsp)
movb $0x0, %al
callq 0x11b0
movl -0xc(%rbp), %eax
movl %eax, -0x21d4(%rbp)
leaq -0x1b0(%rbp), %rax
movq %rax, -0x21d0(%rbp)
leaq -0x1b0(%rbp), %rdi
callq 0x1090
movl -0x21d4(%rbp), %edi
movq -0x21d0(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10a0
cmpq $-0x1, %rax
jne 0x2160
leaq 0x121d(%rip), %rdi      # 0x3378
callq 0x1180
leaq 0x138b(%rip), %rdi      # 0x34f2
leaq 0x1053(%rip), %rsi      # 0x31c1
movb $0x0, %al
callq 0x10b0
jmp 0x21e1
leaq -0x1b0(%rbp), %rdi
movq -0x2150(%rbp), %rdx
leaq 0x1445(%rip), %rsi      # 0x35d1
movb $0x0, %al
callq 0x11b0
movl -0xc(%rbp), %eax
movl %eax, -0x21e4(%rbp)
leaq -0x1b0(%rbp), %rax
movq %rax, -0x21e0(%rbp)
leaq -0x1b0(%rbp), %rdi
callq 0x1090
movl -0x21e4(%rbp), %edi
movq -0x21e0(%rbp), %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10a0
cmpq $-0x1, %rax
jne 0x21df
leaq 0x119e(%rip), %rdi      # 0x3378
callq 0x1180
jmp 0x21e1
movl -0xc(%rbp), %edi
callq 0x10f0
xorl %edi, %edi
callq 0x11c0
movl -0xc(%rbp), %edi
callq 0x10f0
jmp 0x1bb0