#include "h9.h"

int setup_socket(void)
{
  struct sockaddr_in server;
  int sock, r=1;
  
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    perror("socket");
    exit(1);
  }
  memset(&server, 0, sizeof(server));
  server.sin_family = AF_INET;
  server.sin_port = htons(PORT);
  server.sin_addr.s_addr = htonl(INADDR_ANY);

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &r, sizeof(r));

  if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
    perror("bind()");
    exit(1);
  }
  if (listen(sock, 20) < 0) {
    perror("listen()");
    exit(1);
  }
  return sock;
}

void terminfo(struct termios *tio, struct winsize *ws)
{
  if (tcgetattr(0, tio) < 0) {
    perror("tcgetattr");
    exit(1);
  }
  if (ioctl(0, TIOCGWINSZ, ws) < 0) {
    fprintf(stderr,"getting winsize\n");
    exit(1);
  }
}

int main(int argc, char *argv[])
{
  struct epoll_event epv[100];
  struct termios tio;
  struct winsize ws;
  SSL_CTX *context;
  int epfd, sock, game, conn, r, clients=0;
  ssl_conn *c;
  char buf[K];

  terminfo(&tio, &ws);

  SSL_load_error_strings();
  SSL_library_init();

  context = setup_ssl_context();

  sock = setup_socket();
  game = launch_game(&tio, &ws);

  epfd = epoll_create(5);
  
  epv[0].events = EPOLLIN;
  epv[0].data.fd = sock;
  epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &(epv[0]));
  epv[1].events = EPOLLIN | EPOLLET;
  epv[1].data.fd = game;
  epoll_ctl(epfd, EPOLL_CTL_ADD, game, &(epv[1]));

  while(1) {
    r = epoll_wait(epfd, epv, 2+clients, -1);
    if (r <= 0) continue;
    
    for(i=0; i < r; i++) {
      if (epv[i].events & (EPOLLERR | EPOLLHUP)) {
	if (epv[i].data.fd == sock) shutdown();
	if (epv[i].data.fd == game) shutdown();
	else disconnect(epv[i].data.fd);
	continue;
      }
      if (epv[i].events & EPOLLIN) {
	if (epv[i].data.fd == sock) {
	  if ((c = ssl_accept(sock, context)) == NULL) {
	    fprintf(stderr,"Error accepting connection.\n");
	    continue;
	  }
	  newclient(c);
	  continue;
	}
	if (epv[i].data.fd == game && clients) {
	  broadcast(game);
	  continue;
	}
	input(epv[i].data.fd);
      }
    }
  }
}

