#include "main.h"
#include "network.h"

int wsock_init(void) {
#ifdef WIN32
   WSADATA w;
   int error = WSAStartup(0x0202, &w);
   if (error) {
      printf("WS: could not initialize winsock2!\n");
      return FALSE;
   }
   if (w.wVersion != 0x0202){
      printf("WS: wrong version of winsock!\n");
      WSACleanup();
      return FALSE;
   }
#endif
  return TRUE;
}

u_long resolve_host(const char *hostname) {
  u_long ip;
  ip = inet_addr(hostname);

  // if it's not an IP resolve name
  if (ip == INADDR_NONE) {
    struct hostent *he = gethostbyname(hostname);
    if (he == NULL) {
      printf("cannot resolve %s\n", hostname);
    }
    else {
      struct in_addr addr = *(struct in_addr *)he->h_addr_list[0];
      printf("resolved %s to %s\n", hostname, inet_ntoa(addr));
      ip = addr.s_addr;
    }
  }
	return ip;
}

int client_connect(clientState **cl, const char *hostname, u_short port) {
  SOCKET sockfd;
  struct sockaddr_in addr;
  clientState *cs = *cl;

	// tries to create socket
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if ((int)sockfd == SOCKET_ERROR) {
    perror("socket");
    return -1;
  }

  // fills addr
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = resolve_host(hostname);
  addr.sin_port = htons(port);
  memset((&addr.sin_zero), 0, 8);

  printf("trying to connect server... ");
	if (connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr)) < 0) {
		perror("connect");
		return -1;
	}
  else printf("connected!\n");

	// initializes the client socket
	cs->socket = sockfd;
	cs->quited = FALSE;
	cs->queue = NULL;
	cs->connected = TRUE;
	return 0;
}

// sends TCP/IP message
void client_addPacket(clientState **cl, int type, char *data) {
  clientState *cs = *cl;
  int offset = 0;
  int numbytes = 0;

  // client not connected
  if (!cs->connected) return;

	// allocates new packet
	packet *p;
	numbytes = strlen(data);
	p = (packet*)malloc(sizeof(struct packet));
	p->buffer = (char*)malloc(numbytes+MSG_HEADLEN+1);
  p->next = cs->queue;
  cs->queue = p;

  // write header
	write_short(p->buffer, offset, strlen(data));
	write_short(p->buffer, offset, type);

  // copy data
  strcpy((p->buffer+MSG_HEADLEN), data);
  printf("end add packet\n");
}

void client_sendall(clientState *cs) {
  packet *p;
  int count;

  // client not connected
  if (!cs->connected) return;

  // send packet queue
  p = cs->queue;
  while(p) {
    count = send(cs->socket, p->buffer, strlen(p->buffer+MSG_HEADLEN)+MSG_HEADLEN, 0);
    printf("sent: %s (%i bytes)\n", p->buffer+4, count);
    p = p->next;
    // i was disconnected!
    if (count <= 0) cs->connected = FALSE;
  }
  client_cleanqueue(cs);
}

void client_cleanqueue(clientState *cs) {
  packet *p;
  p = cs->queue;
  while(p) {
    p = p->next;
    free(cs->queue->buffer);
    free(cs->queue);
    cs->queue = p;
  }
}

/* reads a packet and returns it */
packet *packet_read(clientState *cs) {
  int offset = 0;
  int result;
  int type = -1;
  size_t length;
  char buffer[MSG_LEN];
  packet *p;

  p = (packet*)malloc(sizeof(struct packet));
  memset(buffer, 0, MSG_LEN);

  // read information from socket
  printf("receiving..\n");
  result = recv(cs->socket, buffer, sizeof(buffer), 0);
  printf("done.. %d\n", result);

  if (result == -1) {
    printf("invalid packet!!\n");
    cs->connected = FALSE;
    closesocket(cs->socket);
    p->type = PACKET_INVALID;
    client_cleanqueue(cs);
    printf("client %d exited\n", cs->socket);
  }
  else {
    read_short(buffer, offset, length);
    read_short(buffer, offset, type);
    p->type = type;

    // zero length packet (disconnect)
    if (length == 0) {
      printf("zero length packet!!\n");
      cs->connected = FALSE;
      closesocket(cs->socket);
      p->type = PACKET_INVALID;
      client_cleanqueue(cs);
      printf("client %d exited\n", cs->socket);
    }
    // good packet
    else if (strlen(buffer+offset) == length) {
      printf("offset: %d || ", offset);
      printf("length: %d || ", length);
      printf("strlen: %d\n", strlen(buffer+offset));
      p->buffer = (char*)malloc(length+1);
      printf("pbuffer allocated\n");
      strcpy(p->buffer, (buffer+offset));
      printf("ok\n");
    }
    else {
      printf("packet NOT OK!\n");
      printf("buffer: %s\n", buffer);
    }
  }
  return p;
}
