#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>
#include <time.h>
#include <sys/utsname.h>

#define K	1024
#define min(a,b)	((a) < (b)? (a) : (b))

/*
 * LOOK %d,%d
 */
int parse(char *s, int *x, int *y)
{
  char *w;
  
  w = strtok(s, " \r\n");
  if (w == NULL) return 0;
  if (strcasecmp("LOOK", w) != 0) return 0;
  w = strtok(NULL, " ,\r\n");
  if (w == NULL) return 0;
  *x = atoi(w);
  w = strtok(NULL, " ,\r\n");
  if (w == NULL) return 0;
  *y = atoi(w);
  return 1;
}

int main(int argc, char *argv[])
{
  FILE *eggs;
  struct epoll_event epv;
  struct sockaddr_in server, client;
  socklen_t clientlen;
  int sock, so = 1, port, epfd, r, i, j;
  char buf[K], board[K][K];

  if (argc < 2) {
    fprintf(stderr,"Usage: egg <port>\n");
    exit(0);
  }

  daemon(1,0);
  srand(time(0));

  port = atoi(argv[1]);
  if (port < 47300 || port > 47350) {
    fprintf(stderr,"Invalid port %d\n", port);
    exit(1);
  }

  for(i=0; i < K; i++) {
    for(j=0;j < K; j++) {
      board[i][j] = 0;
    }
  }

  sprintf(buf, "eggs.%d", port);
  if ((eggs = fopen(buf, "w")) == NULL) {
    fprintf(stderr,"Unable to open egg logfile for writing.\n");
    exit(1);
  }
  for(r=0; r < 10; r++) {
    do {
      i = rand() % K;
      j = rand() % K;
    } while (board[i][j] == 1);
    board[i][j] = 1;
    fprintf(eggs,"%d,%d\n", i, j);
  }
  fclose(eggs);

  // Create a SOCK_STREAM internet socket here:
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  if (sock < 0) {
    perror("socket");
    exit(1);
  }

  // Set the socket option SO_REUSEADDR here:
  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so, sizeof(so));

  // Setup server address, bind to any address on port defined by the PORT
  // #define above:
  server.sin_family = AF_INET;
  server.sin_addr.s_addr = INADDR_ANY;
  server.sin_port = htons(port);
  if (bind(sock, (struct sockaddr *)&server, sizeof(server))) {
    perror("bind");
    exit(1);
  }

  if ((epfd = epoll_create(25)) < 0) {
    perror("epoll_create");
    exit(1);
  }
  epv.events = EPOLLIN | EPOLLERR | EPOLLHUP;
  epv.data.fd = -1;
  epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &epv);

  for(;;) {
    r = epoll_wait(epfd, &epv, 1, -1);
    if (r <= 0) continue;

    if (epv.events & (EPOLLERR | EPOLLHUP)) break;

    r = recvfrom(sock, buf, K, 0, (struct sockaddr *)&client,
		 &clientlen);
    buf[min(r,K-1)] = '\0';
    if (parse(buf, &i, &j)) {
      r = rand() % 4;
      if (r == 0) {
	if (board[i][j]) sprintf(buf,"%d,%d: Found one!", i, j);
	else sprintf(buf, "%d,%d: No egg.", i, j);
	sendto(sock, buf, strlen(buf)+1, 0, (struct sockaddr *)&client,
	       sizeof(struct sockaddr_in));
      }
    }
  }
  // Not reached:
  return 0;
}
