#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <stdbool.h>
#include <sys/time.h>

#define SERVER1_PORT 15281
#define SERVER2_PORT 18510

typedef struct {
    struct sockaddr_in address;
    int fails;
    bool connected;
} ServerInfo;

ServerInfo server_infos[2];

int main() {
    int sockfd1;
    int sockfd2;
    struct sockaddr_in client_addr1;
    struct sockaddr_in client_addr2;
    char buf[256];
    socklen_t len = sizeof(client_addr1);
    struct timeval start_time, current_time;

    sockfd1 = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd2 < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    sockfd2 = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd2 < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    memset(&client_addr1, 0, sizeof(client_addr1));
    client_addr1.sin_family = AF_INET;
    client_addr1.sin_port = htons(SERVER1_PORT);
    client_addr1.sin_addr.s_addr = INADDR_ANY;

    memset(&client_addr2, 0, sizeof(client_addr2));
    client_addr2.sin_family = AF_INET;
    client_addr2.sin_port = htons(SERVER2_PORT);
    client_addr2.sin_addr.s_addr = INADDR_ANY;

    if (bind(sockfd1, (const struct sockaddr *)&client_addr1, sizeof(client_addr1)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (bind(sockfd2, (const struct sockaddr *)&client_addr2, sizeof(client_addr2)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    while(!(server_infos[0].connected && server_infos[1].connected)) {
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(sockfd1, &read_fds);
        FD_SET(sockfd2, &read_fds);
        struct timeval timeout;
        timeout.tv_sec = 100 / 1000;
        timeout.tv_usec = (100 % 1000) * 1000;
        if(select(sockfd2 + 1, &read_fds, NULL, NULL, &timeout) > 0) {
            if FD_ISSET(sockfd1, &read_fds) {
                int n = recvfrom(sockfd1, buf, 256, 0, (struct sockaddr*)&client_addr1, &len);
		if(n == 1 && buf[0] == 'A') {
		    memcpy(&server_infos[0].address, &client_addr1, sizeof(struct sockaddr_in));
		    server_infos[0].connected = true;
		    printf("Server 1 connected\n");
		}
	    }
            if FD_ISSET(sockfd2, &read_fds) {
                int n = recvfrom(sockfd2, buf, 256, 0, (struct sockaddr*)&client_addr2, &len);
		if(n == 1 && buf[0] == 'B') {
		    memcpy(&server_infos[1].address, &client_addr2, sizeof(struct sockaddr_in));
		    server_infos[1].connected = true;
		    printf("Server 2 connected\n");
		}
	    }
        }
    }

    int fails = 0;

    while(fails < 10) {
	buf[0] = 'R';
        sendto(sockfd1, buf, 1, 0, (struct sockaddr*)&server_infos[0].address, len);
        fd_set read_fds;
        FD_ZERO(&read_fds);
        FD_SET(sockfd1, &read_fds);
        struct timeval timeout;
        timeout.tv_sec = 100 / 1000;
        timeout.tv_usec = (100 % 1000) * 1000;
        if(select(sockfd2 + 1, &read_fds, NULL, NULL, &timeout) > 0) {
            if FD_ISSET(sockfd1, &read_fds) {
                fails = 0;
                int n = recvfrom(sockfd1, buf, 256, 0, (struct sockaddr*)&client_addr1, &len);
		if(n == 1 && buf[0] == '1') {
		    sendto(sockfd2, buf, 1, 0, (struct sockaddr*)&server_infos[1].address, len);
		}
	    }
        }
        ++fails;
        usleep(1700000);
    }
    printf("Server timed out\n");

    return 0;
}
