#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <unistd.h>

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "yconnection.h"


int ConnectionIsAllocated(int n);
int ConnectionIsConnected(int n);
YConnection *ConnectionGetPtr(int n);
int ConnectionAllocate(void);
void ConnectionReset(int n);
void ConnectionDelete(int n);
void ConnectionDeleteAll();
void ConnectionReclaim(void);


#define MIN(a,b)        ((a) < (b) ? (a) : (b))
#define MAX(a,b)        ((a) > (b) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define ABSOLUTE(x)     (((x) < 0) ? ((x) * -1) : (x))


/*
 *	Checks if connection n is valid.
 */
int ConnectionIsAllocated(int n)
{
	if((n < 0) ||
	   (n >= total_yconnections) ||
	   (yconnection == NULL)
	)
	    return(0);
	else if(yconnection[n] == NULL)
	    return(0);
	else
	    return(1);
}

/*
 *	Checks if connection n is valid and connected.
 */
int ConnectionIsConnected(int n)
{
	if(!ConnectionIsAllocated(n))
	    return(0);
	else if(yconnection[n]->socket < 0)
	    return(0);
	else
	    return(1);
}

/*
 *	Returns pointer to connection n if it is allocated and valid or
 *	NULL if it is not.
 */
YConnection *ConnectionGetPtr(int n)
{
	if(ConnectionIsAllocated(n))
	    return(yconnection[n]);
	else
	    return(NULL);
}

/*
 *	Allocate a new connection structure.
 */
int ConnectionAllocate(void)
{
	int i, n;
	YConnection *con_ptr;


	/* Sanitize total. */
	if(total_yconnections < 0)
	    total_yconnections = 0;

	/* Check for available pointer. */
	for(i = 0; i < total_yconnections; i++)
	{
	    if(yconnection[i] == NULL)
		break;
	}
	if(i < total_yconnections)
	{
	    n = i;
	}
	else
	{
	    n = total_yconnections;
	    total_yconnections++;

	    yconnection = (YConnection **)realloc(
		yconnection,
		total_yconnections * sizeof(YConnection *)
	    );
	    if(yconnection == NULL)
	    {
		total_yconnections = 0;
	        return(-1);
	    }
	}

	yconnection[n] = (YConnection *)calloc(
	    1,
	    sizeof(YConnection)
	);
	if(yconnection[n] == NULL)
	{
	    return(-1);
	}

	/* Reset values. */
	con_ptr = yconnection[n];

	con_ptr->socket = -1;

	/* Allocate recieve buffer. */
	con_ptr->buf_cont = 0;
	con_ptr->buf_len = YNetRecvBufLen;

	con_ptr->buf = (u_int8_t *)calloc(
	    con_ptr->buf_len,
	    sizeof(u_int8_t)
	);
	if(con_ptr->buf == NULL)
	{
	    con_ptr->buf_len = 0;
	}

	return(n);
}

/*
 *	Resets connection values to default, freeing any allocated
 *	substructures.
 */
void ConnectionReset(int n)
{
	YConnection *con_ptr;

	con_ptr = ConnectionGetPtr(n);
	if(con_ptr == NULL)
	    return;


	if(con_ptr->socket > -1)
	{
	    /* This is not the formal place to close the socket,
	     * the calling function should close() it before calling
	     * this function. But we close it just in case since this
	     * function is often called with the connection socket
	     * still connected.
	     */
	    close(con_ptr->socket);
	    con_ptr->socket = -1;
	}


	free(con_ptr->name);
	con_ptr->name = NULL;

	free(con_ptr->password);
	con_ptr->password = NULL;

	free(con_ptr->buf);
	con_ptr->buf = NULL;
	con_ptr->buf_cont = 0;
	con_ptr->buf_len = 0;

	con_ptr->user_id = 0;
	con_ptr->group_id = 0;

	con_ptr->access_level = 0;


	return;
}

/*
 *	Deletes connection n and close()s it if it is not closed
 *	already. Note that the calling function should close it
 *	first and set the socket to -1.
 */
void ConnectionDelete(int n)
{
	if(ConnectionIsAllocated(n))
	{
	    /* Free allocated resourses. */
	    ConnectionReset(n);

	    free(yconnection[n]);
	    yconnection[n] = NULL;
	}

	return;
}

/*
 *	Deletes all connections.
 */
void ConnectionDeleteAll()
{
	int i;

	for(i = 0; i < total_yconnections; i++)
	    ConnectionDelete(i);

	free(yconnection);
	yconnection = NULL;
	total_yconnections = 0;

	return;
}

/*
 *	Deletes any NULL pointers in the connection array.
 */
void ConnectionReclaim(void)
{




	return;
}
