#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "debug.h"
#include "sockethelper.h"
#include "selecthelper.h"

typedef struct _buf { int fd; int length; char *text; } buffer;

buffer *init_buf(int n){
	buffer *b = malloc(sizeof(buffer)*n);
	memset(b,0,sizeof(buffer)*n);
	return b;
}

enum { CLOSE, QUIT, CONTINUE };

int server (buffer *buf, int N, int client_socket) {
  int i;
	int res = 0;

	for(i=0; i<N; i++) {
		if (buf[i].fd==client_socket) {
    	/* Allocate a buffer to hold the text.  */
			buf[i].text=malloc(sizeof(char)*buf[i].length);
    	/* Read the text itself, and print it.  */
			res=read (client_socket, buf[i].text, buf[i].length);
			if eagain(res) {
			 	perror("read()");
				return -1;
			} 
		  errlog(res);

			if (res) {
			  printf ("%s\n", buf[i].text);
  		
				/* If the client sent the message "quit", we're all done.  */
	    	res = (!strcmp (buf[i].text, "quit") ? 	QUIT : CONTINUE);
			} else 
				res=CONTINUE;
				  
			/* Free the buffer.  */
  		free (buf[i].text);
			buf[i].length=0;
			buf[i].fd = 0;
			return res;
		}
	}
	/* client_socket not in buffer, must read size */

	for(i=0; i<N; i++) {
		if (buf[i].fd==0) {
			buf[i].fd=client_socket;
		  /* First, read the length of the text message from the socket.  If
	       read returns zero, the client closed the connection.  */
			fprintf(stderr,"reading from %d\n",client_socket);
			res = read (client_socket, &(buf[i].length), sizeof (int));
			errlog(res);
    	if (res == 0) return CLOSE;
			return CONTINUE;
		}
	}
	
	fprintf(stderr,"No more space in buffer, terminating\n");
	exit(1);
}

void printfdarray(int *fd_array, int len){
	int i;
	fprintf(stderr, "fd_array = { ");
	for (i=0; i<len; i++)
		fprintf(stderr, "%d ", fd_array[i]);
	fprintf(stderr, "}\n");
}

void removefd(int *fd_array, int *len, int fd){
	int i;
	for(i=0; i<*len && fd_array[i]!=fd; i++);	
	for(i=i; i<*len-1; i++)
		fd_array[i]=fd_array[i+1];
	fd_array[*len]=0;
	*len=*len-1;
}

int main (int argc, char* const argv[])
{
  int socket_fd;
  struct sockaddr_in peer;
	int client_len = sizeof (struct sockaddr_in);
	int end = 0;
	int len = 0;
	int i = 0;
	int N = atol(argv[1]);
	int *fdarray = malloc(sizeof(int)*(N+1));

	socket_fd = inet_passive_socket("127.0.0.1",9999,NONBLOCKING|REBIND);
	fprintf(stderr,"listening socket is %d\n", socket_fd);
	fdarray[0]=socket_fd;
	len++;
	
	buffer *buf = init_buf(N);
	
	while (1) {
		int *to_read;
		printfdarray(fdarray,len);
		to_read = wait_fd(fdarray, len, 20);
		errorlog(to_read,NULL);
		/* check for new connections */
		if (in(to_read,socket_fd)) {
			/* Accept a connection */
		  int connection = accept(socket_fd, &peer, &client_len);
		  errlog(connection);
			setnonblocking(connection);
			if (len<N) {
				fdarray[len]=connection;
				len++;
			} else {
				write(connection,"cannot be served\n",18);
				close(connection);
			}
		} 
	
		/* handle existing connections */
		i=0;
		while(to_read[i]!=0) {
			fprintf(stderr,"to_read[%d]==%d\n", i, to_read[i]);
			if (to_read[i]!=socket_fd) {
			  end = server(buf, N, to_read[i]);	
				if (end==QUIT) {
					fprintf(stderr,"quit received\n");
					exit(0);
				}	else if (end==CLOSE) { 
					removefd(fdarray, &len, to_read[i]); 
					close(to_read[i]);
					fprintf(stderr,"fd %d closed\n", to_read[i]);
		printfdarray(fdarray,len);
				} else if (end==-1) { 
					fprintf(stderr,"more stuff to read from this connection");
				}
			}
			i++;
		}
		free(to_read);
	}
	fprintf(stderr,"Abnormal termination\n");
  return -1;
}
