#include <sys/syscall.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/un.h>

#include <gtk_stuff.h>

/**
 * All the labels and strings in this code do not have anything to do with GTK stuff,
 * it is simply obfuscated to make sure the participants don't waste time trying to 
 * reverse this.
 */

#define SOCK_PATH   "/tmp/" "gtk_buffer"

#define PKT_TYPE_CALLSIGN       1
#define PKT_TYPE_ACCEPT_STROKE  2
#define PKT_TYPE_DRAW           3

struct packet
{
    int type;
    int x_start;
    int y_start;
    int x_end;
    int y_end;
};

gtk_update_cb_t gtk_update_cb;
pthread_t g_pid;
int g_socket_fd;


/* DO NOT DELETE: poll function for draw commands */
void* gtk_buffer_flip(void* x)
{
    int fd = g_socket_fd;
    struct packet pckt;

    while (read(fd, &pckt, sizeof(struct packet)))
    {
        if (pckt.type == PKT_TYPE_DRAW)
            gtk_update_cb(pckt.x_start, pckt.y_start, pckt.x_end, pckt.y_end);
    }
    return NULL;
}


/* DO NOT DELETE: this will tell the grandme program we are operational and can receive commands */
void gtk_buffer_ready_for_refresh(gtk_update_cb_t cb)
{
    struct sockaddr_un address;
    struct packet pkt;

    g_socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if (g_socket_fd < 0)
        return;
    
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, SOCK_PATH);

    if (connect(g_socket_fd, (struct sockaddr*) &address, sizeof(struct sockaddr_un)) != 0)
    {
        return;
    }

    pkt.type = PKT_TYPE_ACCEPT_STROKE;
    write(g_socket_fd, &pkt, sizeof(struct packet));

    gtk_update_cb = cb;

    pthread_create(&g_pid, NULL, gtk_buffer_flip, NULL);
}
