#include "../network.h"
#include <stdlib.h>
#include <stdio.h>

SOCKET listener;
SOCKET cl_sockets[MAX_SOCKETS];

void cleanup() {
  if (listener != -1)
    closesocket(listener);
#ifdef WIN32
  WSACleanup();
#endif
}

int init_listener() {
  struct sockaddr_in addr;
  struct hostent *host;
  int result;

  // create listener socket
  listener = socket(PF_INET, SOCK_STREAM, 0);
  if (listener == -1) {
    perror("socket");
    cleanup();
    return -1;
  }

  // get information about the host
  memset(&addr, 0, sizeof(addr));
  host = gethostbyname("localhost");
  if (host == NULL) {
    perror("gethostbyname");
    cleanup();
    return (1);
  }

  //  bind the socket to an address and port
  memcpy(&addr.sin_addr, host->h_addr_list[0], sizeof(host->h_addr_list[0]));
  addr.sin_family = AF_INET;
  addr.sin_port   = htons(DEFAULT_PORT);

  result = bind(listener, (struct sockaddr *)&addr, sizeof(addr));
  if (result == -1) {
    perror("bind");
    cleanup();
    return -1;
  }

  //  listen for connections
  result = listen(listener, D_QUEUE);
  if (result == -1) {
    perror("listen");
    cleanup();
    return -1;
  }
  return 0;
}

int main() {
  struct timeval tv;
  int result;
  int index;
  int cycle = 0;
  int delay = 5;
  int sockets_index = 0;
  unsigned int maximun;
  char buffer[D_INFO];
  fd_set input;

  wsock_init();

  // cleans the client sockets
  memset(cl_sockets, 0, sizeof(cl_sockets));
  maximun = listener;

  // listen for connections
  init_listener();

  result = 0;
  while (result != -1) {
    FD_ZERO(&input);
    FD_SET(listener, &input);
    for (result = 0; result < sockets_index; result++)
      FD_SET(cl_sockets[result], &input);

    tv.tv_sec  = delay;
    tv.tv_usec = 0;
    result = select(maximun + 1, &input, NULL, NULL, &tv);
    switch (result) {
      // error in select
      case -1:
        perror("select"); break;
      // nothing to process
      case 0: break;
      // a number of sockets are ready for reading
      default:

      //  accept connection
      if (FD_ISSET(listener, &input)) {
        cl_sockets[sockets_index] = accept(listener, NULL, NULL);
        printf("accepted connection on %i\n", listener);
        if (cl_sockets[sockets_index] == -1) {
          perror("accept");
        }
        else {
          if (cl_sockets[sockets_index] > maximun) {
            maximun = cl_sockets[sockets_index];
          }
          sockets_index++;
        }
      }

      // one of the sockets is sending data. find it
      else {
        for (index = 0; index < sockets_index; index++) {
          if (FD_ISSET(cl_sockets[index], &input)) {
            memset(buffer, 0, sizeof(buffer));
            // read information from socket
            result = recv(cl_sockets[index], buffer, sizeof(buffer), 0);
            if (result == -1)
              perror("recv");
            else {
              int offset = 0;
              int type;
              int len;
              read_short(buffer, offset, len);
              read_short(buffer, offset, type);
              printf("Received %d bytes from descriptor %d: %s (%d)\n", result, cl_sockets[index], buffer+offset, len);
            }
          }
        }
      }
    }
    printf("cycle: %d\r", cycle++);
  }

  // close all clients
  for (result = 0; result < sockets_index; result++) {
    closesocket(cl_sockets[sockets_index]);
  }
  cleanup();
  return (0);
}
