/*
 * Copyright (c) 2002-2006 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: erfio.c 13173 2010-09-08 01:03:53Z karthik.sharma $
 *
 * Write ERF records in ERF format.
 */

/* dagconvert headers. */
#include "dagsort.h"
/* Endace headers. */
#include "dagapi.h"
#include "dagutil.h"
#include "dag_platform.h"

/*
 * array to hold the input file names.
 */
extern char gInpArray[100];

/*
 * array to hold the input files' pointers.
 */
extern FILE *gInputFile;

extern IteratorPtr position_p;
/*
 * pointer to hold the list of first dag record from each file.
 */
extern void *gInpRecord;

/*
 * counter variable to hold number of input files.
 */
extern int gFileCount;

/*
 * Output stream.
 */
static FILE * uOutfile = NULL;

/*
 * Input stream.
 */
static FILE * uInfile = NULL;
static char * uInfileName = NULL;

/*
 * Reusable memory for dag records.
 */
static dag_record_t * uHead;

/*
 * Next payload.
 */
static uint8_t * uPayload = NULL;

/*
 * Save output file name for later use.
 */
static char *uOutfileName = NULL;

/*
 * Used for padding.
 */
static const char ZERO[64] = {0};
/*
 * Set the stream on which output is to be produced.
 */
void
set_erf_output(char *out)
{
#if defined(__linux__) || defined(__FreeBSD__) || (defined(__SVR4) && defined(__sun)) || defined(__APPLE__)
	int outfd;
#endif
	uOutfileName = out;

	dagutil_verbose_level(2, "DEBUG: set_erf_output %s\n", out);

	if (out == NULL)
		uOutfile = stdout;
	else 
	{
		outfd = open(out, O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE, 0664);
		if (outfd == -1)
		{
			dagutil_panic("Could not open %s for writing.\n", out);
		}
		uOutfile = fdopen(outfd, "w");
	}
	if (uOutfile == NULL)
	{
		dagutil_panic("Could not open %s for writing.\n", out);
	}
}

/*
 * Close the currently open input (if any).
 */
void
close_erf_output(void)
{
	if (uOutfile && uOutfile != stdout)
    	{
        	fclose(uOutfile);
    	}
	uOutfile = NULL;
}

/*
 * Write given ERF header and payload in ERF format.
 * Returns 1 if record successfully written and 0
 * otherwise.
 */
int
write_erf_record(void *packet_data,uint32_t size)
{
	if (uOutfile== NULL)
	{
		printf("function %s line %d \n",__FUNCTION__,__LINE__);
		set_erf_output(uOutfileName);
	}
	/* write header, return 0 if write fails */
	if (fwrite(packet_data,size,1, uOutfile) != 1)
	{
		printf("function %s line %d \n",__FUNCTION__,__LINE__);
		return 0;
	}
	return 1;
}
void
set_erf_input(char *in)
{
	uInfileName = in;

	if (in == NULL)
	{
		uInfile = stdin;
	}
	else
	{

#if defined(__linux__) || defined(__FreeBSD__) || (defined(__SVR4) && defined(__sun)) || defined(__APPLE__)

		int fd = open(in, O_RDONLY|O_LARGEFILE);
		if (fd == -1)
		{
			dagutil_panic("Could not open %s for reading.\n", in);
		}
		uInfile = fdopen(fd, "r");

#elif defined(_WIN32)

		uInfile = fopen(in, "rb");

#endif /* Platform-specific code. */

		if (uInfile == NULL)
		{
			dagutil_panic("Could not open %s for reading.\n", in);
		}
	}
}

/*
 * Close the current input stream.
 */
void
close_erf_input(void)
{
	if (uInfile && uInfile != stdin)
		fclose(uInfile);
	uInfile = NULL;

	if (uPayload)
		dagutil_free(uPayload);
	uPayload = NULL;
}
/*
 * Get pointer to the ERF header for the next packet
 * in the input stream. Returns null if no further
 * packets are available.
 */

dag_record_t *
get_next_erf_header()
{
	dag_record_t *rec = NULL;
	int rlen = 0;	
	rec = (dag_record_t*)gInpRecord;
	if (gInputFile != NULL)
	{
		if (fread(rec, dag_record_size, 1, gInputFile) != 1)
		{
			if (feof(gInputFile))
			{
				dagutil_verbose_level(2,"EOF offset 0x%"PRIx64" \n",ftello(gInputFile));
				return NULL;
			}
			else if (ferror(gInputFile))
			{
				dagutil_panic("error reading the file %s\n", gInpArray);
			}
						
		}
	}else
	{
		printf("Returning NULL file offset 0x%"PRIu64" \n",ftello(gInputFile));
		return NULL;
	}
	uHead = rec;	 
	rlen = ntohs(uHead->rlen);
	if (rlen == 20)
	{
		/* DS error truncates the packet, but the packet has effectively been padded to 28 bytes by the card. */
		rlen = 28;
	}
	rlen -= dag_record_size;
	/* allocate memory for and read the payload */
	if (rlen == 0)
	{
		/*
		* In this case there is no payload, but we still want
		* to return a non-null pointer. Therefore, if payload
		* is not yet allocated, get a single byte of memory.
		*/
		if (uPayload == NULL)
		{
			uPayload = dagutil_malloc(1);
		}
	} 
	else
	{
		/*
		* In the usual case, simply resize the payload buffer
		* to be large enough for the data
		*/
		uPayload = realloc(uPayload, rlen);
		
		if (uPayload == NULL)
		{
			dagutil_panic("Could not get memory for payload.file offset %"PRIx64"\n",ftello(gInputFile));
		}

		if (fread(uPayload, 1, rlen, gInputFile) != rlen)
		{
			if (feof(gInputFile))
			{
				printf("Not able to read the payload returning NULL \n");
				return NULL;
			}
			else if (ferror(gInputFile))
			{
				dagutil_warning("Problem with payload.\n");
				dagutil_panic("error reading the file %s\n", gInpArray);
			}
		}
		
	}
	return uHead;
}


/*
 * Get pointer to the ERF header for the next packet
 * in the input stream. Returns null if no further
 * packets are available.
 */
read_rec_t*
read_next_erf_header(ListPtr readlist_p)
{
	dag_record_t *rec = NULL;
	int rlen = 0;	
	read_rec_t *read_rec = NULL;
	read_rec_t *temp = NULL;
	rec = (dag_record_t*)gInpRecord;
	uint8_t going_forwards = 0;
	uint8_t going_backwards = 0;
	uint8_t front_end = 0;
	
	if (gInputFile != NULL)
	{
		if (fread(rec, dag_record_size, 1, gInputFile) != 1)
		{
			if (feof(gInputFile))
			{
				dagutil_verbose_level(2,"EOF offset 0x%"PRIx64" \n",ftello(gInputFile));
				return NULL;
			}
			else if (ferror(gInputFile))
			{
				dagutil_panic("error reading the file %s\n", gInpArray);
			}
						
		}
		else
		{
			read_rec = (read_rec_t*)dagutil_malloc(sizeof(read_rec_t));
			read_rec->header = dagutil_malloc(dag_record_size);
			read_rec->file_offset = (ftello(gInputFile) - dag_record_size);
			memcpy(read_rec->header,rec,dag_record_size);
		}
	}else
	{
		printf("Returning NULL file offset 0x%"PRIu64" \n",ftello(gInputFile));
		return NULL;
	}
	uHead = rec;	 
	rlen = ntohs(uHead->rlen);
	if (rlen == 20)
	{
		/* DS error truncates the packet, but the packet has effectively been padded to 28 bytes by the card. */
		rlen = 28;
	}
	rlen -= dag_record_size;
	/* allocate memory for and read the payload */
	if (rlen == 0)
	{
		/*
		* In this case there is no payload, but we still want
		* to return a non-null pointer. Therefore, if payload
		* is not yet allocated, get a single byte of memory.
		*/
		if (uPayload == NULL)
		{
			uPayload = dagutil_malloc(1);
		}
	} 
	else
	{
		/*
		* In the usual case, simply resize the payload buffer
		* to be large enough for the data
		*/
		uPayload = realloc(uPayload, rlen);
		
		if (uPayload == NULL)
		{
			dagutil_panic("Could not get memory for payload.file offset %"PRIx64"\n",ftello(gInputFile));
		}

		if (fread(uPayload, 1, rlen, gInputFile) != rlen)
		{
			if (feof(gInputFile))
			{
				printf("Not able to read the payload returning NULL \n");
				return NULL;
			}
			else if (ferror(gInputFile))
			{
				dagutil_warning("Problem with payload.\n");
				dagutil_panic("error reading the file %s\n", gInpArray);
			}
		}else
		{
			read_rec->payload = (char*)dagutil_malloc((ntohs(rec->rlen) - dag_record_size));
			memcpy(read_rec->payload,uPayload,(ntohs(rec->rlen) - dag_record_size));	
		}
	}
	if(adt_iterator_is_in_list(position_p))
	{
		temp = adt_iterator_retrieve(position_p);
		while(1)
		{
			if(read_rec->header->ts >= temp->header->ts)
			{
				if(going_backwards == 1)
				{
					break;
				}
				going_forwards = 1;
				adt_iterator_advance(position_p);
				if(adt_iterator_is_in_list(position_p))
				{
					temp = adt_iterator_retrieve(position_p);
				}
				else
				{
					front_end = 1;
					break;
				}
			}
			else
			{
				if(going_forwards == 1)	
				{
					adt_iterator_retreat(position_p);
					break;
				}
				going_backwards = 1;
				adt_iterator_retreat(position_p);
				if(adt_iterator_is_in_list(position_p))
				{
					temp = adt_iterator_retrieve(position_p);
				}
				else
				{
					break;
				}
			}	
		}	
	}
	if(front_end == 1)
	{
		adt_iterator_last(position_p);
	}
	
	adt_iterator_add(position_p,(AdtPtr)(read_rec));
	return adt_iterator_retrieve(position_p);
}	
/*
 * Returns a pointer to the payload of the most recent
 * packet. Returns null if there is no current packet.
 */
void *get_erf_payload(void)
{
	/**/return NULL;
}
