// from: http://beej.us/guide/bgnet/html/#a-simple-stream-client

/*
** client.c -- a stream socket client demo
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <arpa/inet.h>

#define PORT "3490" // the port client will be connecting to 

#define MAXDATASIZE 100 // max number of bytes we can get at once 

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int do_connection(int argc, char * argv[]) {
  int sockfd;
  
    struct addrinfo hints, *servinfo;
    int rv;

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_INET; // AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }

    // note: better to loop through servinfo...

    if ((sockfd = socket(servinfo->ai_family, servinfo->ai_socktype,
			 servinfo->ai_protocol)) == -1) {
      perror("client: socket");
      exit(1);
    }

    printf("sockfd: %d\n", sockfd);

    if (connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen) == -1) {
      close(sockfd);
      perror("client: connect");
      exit(1);
    }

    freeaddrinfo(servinfo); // all done with this structure

    return sockfd;
}

int main(int argc, char *argv[])
{
    int sockfd, numbytes;  
    char buf[MAXDATASIZE];

    if (argc != 2) {
        fprintf(stderr,"usage: client hostname\n");
        exit(1);
    }

    sockfd = do_connection(argc, argv);
    
    char *line = NULL;
    size_t len = 0;
    ssize_t nread;

    // file descriptors we will poll
    struct pollfd pfds[2];
    pfds[0].fd = 0; // stdin
    pfds[0].events = POLLIN;
    
    pfds[1].fd = sockfd; // our socket
    pfds[1].events = POLLIN; // bit field: 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, ...

    // only getline if there is something there.
    while (1) {
      // check if the user has typed something
      
      // check if there is something from the server

      // poll: give an array of fd's, is there new information on any of them
      //       to read?
      // fd 0 : keyboard (stdin)
      // sockfd : our socket
      int num_events = poll(pfds, 2, 1);
      if (num_events > 0) {

	if (pfds[0].revents & POLLIN) {
	  nread = getline(&line, &len, stdin);
	  if (nread > 0) {
	    if ((numbytes = send(sockfd, line, nread, 0)) != nread) {
	      printf("error, numbytes sent was %d, was supposed to be %ld\n",
		     numbytes, nread);
	    }
	    if (strcmp(line, "quit\n") == 0) break;
	  }
	}

	if (pfds[1].revents & POLLIN) {
	  //bzero(buf, MAXDATASIZE);
	  if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
	    perror("recv");
	    exit(1);
	  }
	  //printf("%d bytes received, last byte %d.\n", numbytes,
	  //	 buf[numbytes-1]);
	  if (numbytes > 0) {
	    buf[numbytes] = '\0';
	    printf(">> %s", buf);
	  }
	}
      }
    }
    
    close(sockfd);

    return 0;
}