#include <arpa/inet.h> // for htons/ntohs/etc
#include <hashmap.h>
#include <net.h>
#include <netdb.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <vector.h>

#define BUFSIZE 4096

typedef struct client
{
    struct sockaddr_storage remote_addr;
    socklen_t addrlen;

    short last_acked;
} uc_client;

struct client_list
{
    struct client *list;
    int size;
    int index;
};

void send_ack(int sock, struct sockaddr_storage *client, int addrlen,
              short sequence, short flags)
{
    struct uc_header t;
    t.sequence_nr = sequence;
    t.flags       = 2 | flags;
    t.size        = 8;
    sendto(sock, &t, sizeof t, 0, (struct sockaddr *)client, addrlen);
}

uc_client *get_or_create_client(struct client_list *clients,
                                struct sockaddr_storage remote_addr,
                                socklen_t addrlen)
{
    uc_client *c;
    for (int i = 0; i < clients->index; ++i)
    {
        c = clients->list + i;
        if (memcmp(&c->remote_addr, &remote_addr, sizeof remote_addr) == 0)
        {
            return c;
        }
    }

    // In this case, we're creating a new client.
    uc_client cl;
    cl.remote_addr = remote_addr;
    cl.addrlen     = addrlen;
    cl.last_acked  = 0;

    VEC_PUSH(clients, cl);
    return clients->list + (clients->index - 1);
}

int main()
{
    struct client_list clients;
    VEC_INIT(&clients, 16);

    uint8_t buf[BUFSIZE];
    int sock = uc_server_socket(NULL, "16064");

    uc_header header;
    while (1)
    {
        struct sockaddr_storage remaddr;
        socklen_t addrlen = sizeof remaddr;
        int len = recvfrom(sock, (uint8_t*)&header, 8, 0, (struct sockaddr *)&remaddr,
                           &addrlen);

        len = recvfrom(sock, buf, header.size, 0, (struct sockaddr *)&remaddr,
                       &addrlen);

#ifdef DEBUG
        printf("Header: size %d, flags %d, seq.nr. %d\n", header.size, header.flags, header.sequence_nr);
        printf("Data: %s", buf);
#endif

        uc_client *client = get_or_create_client(&clients, remaddr, addrlen);

#ifdef DEBUG
        printf("Got client %p\n", client);
#endif

        if (header.sequence_nr <= client->last_acked)
        {
            continue;
        }

        client->last_acked = header.sequence_nr;
        send_ack(sock, &remaddr, addrlen, header.sequence_nr, 0);
        buf[len] = '\0';
        printf("%s", buf);
        fflush(stdout);
    }
}
