/*
 * 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: legacyio.c 12352 2010-01-11 03:42:23Z wilson.zhu $
 *
 * Read legacy 64 byte records.
 */

/* dagconvert headers. */
#include "inputs.h"
#include "outputs.h"
#include "utils.h"


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

/*
 * array to hold the input files' pointers
 */
extern FILE *gInputFiles[MAXCNT];

/*
 * pointer to hold first legacy uRecord from each file
 */
extern void *gInpRecord;

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

/*
 * Input stream 
 */
static FILE * uInfile = NULL;

/*
 * Reusable memory for records 
 */

static legacy_record_t *uHead;
static dag_record_t uRecord;

static int uInputType;

/*
 * Next payload 
 */
#if !defined(_WIN32)
static void * uPayload = NULL;
#else /* _WIN32 */
static uint8_t * uPayload = NULL;
#endif /* WIN32 */

/*
 * Set the stream from which input is obtained. If "in" is
 * null, then input is set to stdin.
 */
void
set_legacy_input(char *in, int in_type)
{
	int fd;

	uInputType = in_type;

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

/*
 * Close the current input stream.
 */
void
close_legacy_input(void)
{
	if (uInfile && uInfile != stdin)
		fclose(uInfile);
	
	uInfile = NULL;
	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_legacy_header(void)
{
	static int get[MAXCNT];
	static int earliest = -1;
	
	int i;
	legacy_record_t * rec = NULL;

	uHead = NULL;
	
	if (earliest == -1)
	    memset(get, 1, sizeof(int)*MAXCNT);
	
	for (i = 0; i < gFileCount; i++)
	{
		rec = (legacy_record_t*)gInpRecord+i;
		if (get[i])
		{
			if (gInputFiles[i] != NULL)
			{
				/* read the record into reusuable memory */
				if (fread(rec, sizeof(legacy_record_t), 1, gInputFiles[i]) != 1) 
				{
					if (feof(gInputFiles[i]))
					{
						get[i] = 0;
						fclose(gInputFiles[i]);
						gInputFiles[i] = NULL;
					}
					else if (ferror(gInputFiles[i]))
					{
						dagutil_panic("error reading the file %s\n", gInpArray[i]);
					}
				}
				else 
				{
					get[i] = 0;
				}
			}
		} 
	}

	uHead = (legacy_record_t*)gInpRecord;
	earliest = 0;

	for (i = 0; i < gFileCount; i++)
	{
		rec = (legacy_record_t*)gInpRecord + i;
		if (gInputFiles[earliest] != NULL)
		{
			if (gInputFiles[i] != NULL)
			{
				if (uHead->ts > rec->ts)
				{
					uHead = rec;
					earliest = i;
				}
			}
		}
		else
		{
			uHead = rec;
			earliest = i;
		}
	}

	get[earliest] = 1;

	if (gInputFiles[earliest] == NULL)
		return NULL;

	uRecord.ts = uHead->ts;
	uRecord.type = uInputType;
	switch (uInputType) 
	{
		case ERF_TYPE_ETH:
		{
			uint8_t *wlp = (uint8_t *)&uHead->ether.wlen;
			uRecord.rlen = htons(72);
			uRecord.wlen = htons((wlp[1] << 8) + wlp[0]);
			/*
			* The ERF payload which we are trying to emulate starts
			* with two dummy bytes to force long alignment. So nuke
			* the legacy wlen (which happens to be two bytes before
			* the real payload) and point to it to achieve the same
			* net payload
			*/ 
			uHead->ether.wlen = 0;
			uPayload = (uint8_t*)&uHead->ether.wlen;
			break;
		}
		
		case ERF_TYPE_HDLC_POS:
			uRecord.rlen = htons(64);
			uRecord.wlen = htons((uint16_t)ntohl(uHead->pos.wlen));
			uPayload = &uHead->pos.pload;
			break;
		
		default:
			uRecord.rlen = htons(68);
			uRecord.wlen = htons(52);
			uPayload = (uint8_t*)&uHead->cell.header;
			break;
	}
	
	return &uRecord;
}

/*
 * Returns a pointer to the payload of the most recent
 * packet. Returns null if there is no current packet.
 */
void*
get_legacy_payload(void)
{
	return uPayload;
}
