// File: /workspace/github_c_makefile_star2_O3/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2198, %rsp           # imm = 0x2198
leaq 0x78d(%rip), %rdi       # 0x21bf
callq 0x1578
movl %eax, %r15d
leaq 0x6af(%rip), %rdi       # 0x20f0
callq 0x16d1
movl %eax, -0x40(%rbp)
leaq 0xa5e(%rip), %rdi       # 0x24ae
callq 0x1070
leaq 0xa6d(%rip), %rdi       # 0x24c9
callq 0x1070
leaq -0x240(%rbp), %rbx
leaq -0x44(%rbp), %r13
leaq -0x270(%rbp), %r14
movl $0x80, -0x44(%rbp)
movl %r15d, %edi
movq %rbx, %rsi
movq %r13, %rdx
callq 0x11b0
cmpl $-0x1, %eax
je 0x1adb
movl %eax, %r12d
movzwl -0x240(%rbp), %edi
xorl %eax, %eax
cmpl $0xa, %edi
sete %al
leaq -0x23c(,%rax,4), %rsi
addq %rbp, %rsi
movq %r14, %rdx
movl $0x2e, %ecx
callq 0x1030
leaq 0x70e(%rip), %rdi       # 0x21cc
movq %r14, %rsi
xorl %eax, %eax
callq 0x10c0
callq 0x1200
testl %eax, %eax
je 0x1ae9
movl %r12d, %edi
callq 0x1100
jmp 0x1a73
leaq 0x6e3(%rip), %rdi       # 0x21c5
callq 0x1190
jmp 0x1a73
movl %r15d, %edi
callq 0x1100
leaq -0x190(%rbp), %rsi
movl $0x64, %edx
movl %r12d, %edi
xorl %ecx, %ecx
callq 0x1040
cmpl $-0x1, %eax
jne 0x1b22
leaq 0x6d9(%rip), %rdi       # 0x21ec
callq 0x1190
movl $0x1, %edi
callq 0x11d0
cltq
movb $0x0, -0x190(%rbp,%rax)
movq 0x24a5(%rip), %rax      # 0x3fd8
movq (%rax), %rdi
callq 0x1140
leaq -0x120(%rbp), %rbx
leaq -0x190(%rbp), %rsi
movq %rbx, %rdi
callq 0x14f2
movq (%rbx), %r13
movq 0x8(%rbx), %r14
movq 0x10(%rbx), %r15
movq 0x18(%rbx), %r8
leaq 0x68a(%rip), %rdi       # 0x21f1
leaq 0x582(%rip), %r9        # 0x20f0
movq %r13, %rsi
movq %r14, %rdx
movq %r15, %rcx
movq %r8, -0x50(%rbp)
xorl %eax, %eax
callq 0x10c0
leaq 0x6e8(%rip), %rsi       # 0x2271
leaq -0x100(%rbp), %rbx
movq %rbx, %rdi
movq %r13, -0x58(%rbp)
movq %r13, %rdx
movq %r14, -0x38(%rbp)
movq %r14, %rcx
movq %r15, -0x30(%rbp)
movq %r15, %r8
xorl %eax, %eax
callq 0x11c0
leaq 0x4f8(%rip), %rdx       # 0x20ae
leaq -0x1210(%rbp), %r14
movl -0x40(%rbp), %r15d
movl %r15d, %edi
movq %rbx, %rsi
movq %r14, %rcx
callq 0x17a4
movq (%r14), %rax
movabsq $0x20746f6e2070614d, %rcx # imm = 0x20746F6E2070614D
xorq %rcx, %rax
movq 0x6(%r14), %rcx
movabsq $0x646e756f662074, %r14 # imm = 0x646E756F662074
xorq %r14, %rcx
orq %rax, %rcx
jne 0x1c9f
leaq -0x1210(%rbp), %rbx
movl $0xfa0, %edx            # imm = 0xFA0
movq %rbx, %rdi
xorl %esi, %esi
callq 0x10e0
leaq 0x4e0(%rip), %rdx       # 0x20f6
leaq -0x100(%rbp), %rsi
movl %r15d, %edi
movq %rbx, %rcx
callq 0x17a4
movabsq $0x20746f6e2070614d, %rax # imm = 0x20746F6E2070614D
xorq (%rbx), %rax
xorq 0x6(%rbx), %r14
orq %rax, %r14
jne 0x1ca8
leaq 0x8a7(%rip), %rdi       # 0x24ec
callq 0x1070
leaq 0x84d(%rip), %rsi       # 0x249e
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
movq -0x58(%rbp), %rdx
xorl %eax, %eax
callq 0x11c0
movq %rbx, %rdi
callq 0x10a0
movl %r12d, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10b0
cmpq $-0x1, %rax
jne 0x1c90
leaq 0x61f(%rip), %rdi       # 0x22aa
callq 0x1190
movl %r12d, %edi
callq 0x1100
xorl %edi, %edi
callq 0x11d0
leaq 0x89c(%rip), %rdi       # 0x2542
jmp 0x1caf
leaq 0x860(%rip), %rdi       # 0x250f
callq 0x1070
leaq 0x5cd(%rip), %rsi       # 0x2288
leaq -0x21b0(%rbp), %rdi
leaq -0x1210(%rbp), %rbx
movq -0x38(%rbp), %r14
movq %r14, %rdx
movq -0x30(%rbp), %r15
movq %r15, %rcx
movq -0x50(%rbp), %r8
movq %rbx, %r9
xorl %eax, %eax
callq 0x11c0
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x190c
testl %eax, %eax
je 0x1d66
cmpl $0x1, %eax
je 0x1dd2
cmpl $0xa, %eax
jne 0x1e36
leaq 0x584(%rip), %rsi       # 0x2294
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
movq -0x38(%rbp), %rdx
xorl %eax, %eax
callq 0x11c0
movq %rbx, %rdi
callq 0x10a0
movl %r12d, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10b0
cmpq $-0x1, %rax
jne 0x1d4f
leaq 0x560(%rip), %rdi       # 0x22aa
callq 0x1190
leaq 0x559(%rip), %rdi       # 0x22af
leaq 0x462(%rip), %rdx       # 0x21bf
movq -0x38(%rbp), %rsi
jmp 0x1e2a
leaq 0x5f8(%rip), %rsi       # 0x2365
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
movq -0x38(%rbp), %rdx
movq -0x30(%rbp), %rcx
xorl %eax, %eax
callq 0x11c0
movq %rbx, %rdi
callq 0x10a0
movl %r12d, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10b0
cmpq $-0x1, %rax
jne 0x1db0
leaq 0x4ff(%rip), %rdi       # 0x22aa
callq 0x1190
leaq 0x5ca(%rip), %rdi       # 0x2381
leaq 0x401(%rip), %rcx       # 0x21bf
movq -0x38(%rbp), %rsi
movq -0x30(%rbp), %rdx
xorl %eax, %eax
callq 0x10c0
jmp 0x1c90
leaq 0x4bb(%rip), %rsi       # 0x2294
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
movq -0x30(%rbp), %rdx
xorl %eax, %eax
callq 0x11c0
movq %rbx, %rdi
callq 0x10a0
movl %r12d, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10b0
cmpq $-0x1, %rax
jne 0x1e18
leaq 0x497(%rip), %rdi       # 0x22aa
callq 0x1190
leaq 0x4eb(%rip), %rdi       # 0x230a
leaq 0x399(%rip), %rdx       # 0x21bf
movq -0x30(%rbp), %rsi
xorl %eax, %eax
callq 0x10c0
jmp 0x1c90
leaq 0x5ad(%rip), %rdx       # 0x23ea
leaq -0x21b0(%rbp), %rsi
leaq -0xc0(%rbp), %r14
movl -0x40(%rbp), %edi
movq %r14, %rcx
callq 0x17a4
leaq 0x718(%rip), %rdi       # 0x2575
callq 0x1070
leaq 0x587(%rip), %rdi       # 0x23f0
leaq 0x34f(%rip), %rsi       # 0x21bf
xorl %eax, %eax
callq 0x10c0
leaq -0x1c0(%rbp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x1535
leaq 0x718(%rip), %rdi       # 0x25a8
callq 0x1070
movq 0x20(%rbx), %rsi
movq %rsi, -0x40(%rbp)
leaq 0x592(%rip), %rdi       # 0x2436
xorl %eax, %eax
callq 0x10c0
movq (%rbx), %r14
leaq 0x594(%rip), %rdi       # 0x2449
movq %r14, %rsi
xorl %eax, %eax
callq 0x10c0
movq 0x8(%rbx), %r13
leaq 0x596(%rip), %rdi       # 0x2460
movq %r13, %rsi
xorl %eax, %eax
callq 0x10c0
movq 0x10(%rbx), %r15
leaq 0x599(%rip), %rdi       # 0x2478
movq %r15, %rsi
xorl %eax, %eax
callq 0x10c0
movq 0x18(%rbx), %r9
movq -0x40(%rbp), %rax
movq %rax, (%rsp)
leaq 0x593(%rip), %rsi       # 0x248f
leaq -0xc0(%rbp), %rbx
movq %rbx, %rdi
movq %r14, %rdx
movq %r13, %rcx
movq %r15, %r8
xorl %eax, %eax
callq 0x11c0
movq %rbx, %rdi
callq 0x10a0
movl %r12d, %edi
movq %rbx, %rsi
movq %rax, %rdx
xorl %ecx, %ecx
callq 0x10b0
cmpq $-0x1, %rax
jne 0x1f40
leaq 0x36f(%rip), %rdi       # 0x22aa
callq 0x1190
leaq 0x4a9(%rip), %rdi       # 0x23f0
leaq 0x271(%rip), %rsi       # 0x21bf
xorl %eax, %eax
callq 0x10c0
jmp 0x1c90