/*
 * input.c
 *
 *	Gets data to be plotted
 */
#include <stdio.h>
#include <errno.h>
extern int errno;
#include <assert.h>
#include <ctype.h>
#include "datatypes.h"


FLOAT	**
GetData(Fp, m, n)
FILE	*Fp;
int	*m, *n;
{
#ifdef	ANSI_C
	FLOAT	**GetDataMem(FILE *fp, int *M, int *N);
#else
	FLOAT	**GetDataMem();
#endif

	return(GetDataMem(Fp, m, n));
}


bool
Append(L, Ptr)
register LIST	*L;
generic	*Ptr;
{
	register LATOM	*A;

	assert(L != (LIST *)NULL);
	assert(L->list_n >= 0);

	if ((A = (LATOM *)calloc(1, sizeof(LATOM))) == (LATOM *)NULL) {
		perror("(AppendDbl) ");
		ErrorExit();
	}
	A->la_p = Ptr;
	A->la_next = (LATOM *)NULL;

	if (L->list_n == 0) {
		/* empty list */
		assert(L->list_head == (LATOM *)NULL);
		assert(L->list_tail == (LATOM *)NULL);
		L->list_head = A;
		L->list_tail = A;
		L->list_n = 1;
	} else {
		assert(L->list_head != (LATOM *)NULL);
		assert(L->list_tail != (LATOM *)NULL);
		L->list_tail->la_next = A;
		L->list_tail = A;
		L->list_n++;
	}
	return(TRUE);
}


FLOAT	**
GetDataMem(Fp, m, n)
FILE	*Fp;
int	*m, *n;
{
	int	i;
	int	C;
	int	NTuples, TupleSize;
	double	D;
	FLOAT	*F;
	FLOAT	*Tuple;
	FLOAT	**Data;
	LIST	TupleL1;
	LIST	TupleList;
	LATOM	*A;
#ifdef	ANSI_C
	bool GetNextDbl(FILE *, double *, int *);
#else
	bool GetNextDbl();
#endif
	
	TupleL1.list_n = 0;
	TupleL1.list_head = (LATOM *)NULL;
	TupleL1.list_tail = (LATOM *)NULL;

	/* read first line to determine tuple size	*/
	NTuples = 0;
	i = 0;
	do {
		if (GetNextDbl(Fp, &D, &C) == TRUE) {
			if ((F = (FLOAT *)calloc(1, sizeof(FLOAT))) == (FLOAT *)NULL) {
				perror("(GetDataMem) ");
				ErrorExit();
			}
			*F = D;
			Append(&TupleL1, (generic *)F);
			++i;
		} else {
			break;
		}
	} while(C != '\n' && C != EOF);

	TupleSize = i;
	if ((Tuple=(FLOAT *)calloc(TupleSize, sizeof(FLOAT))) == (FLOAT *)NULL) {
		perror("(GetDataMem) ");
		ErrorExit();
	}
	for (A=TupleL1.list_head,i=0; i<TupleSize; i++,A=A->la_next) {
		Tuple[i] = *((FLOAT *)(A->la_p));
	}

	/* initialize list of tuples	*/
	TupleList.list_n = 0;
	TupleList.list_head = (LATOM *)NULL;
	TupleList.list_tail = (LATOM *)NULL;
	Append(&TupleList, (generic *)Tuple);

	/* get remaining tuples	*/
	i = 1;
	do {
		if ((Tuple=(FLOAT *)calloc(TupleSize, sizeof(FLOAT))) == (FLOAT *)NULL) {
			perror("(GetDataMem) ");
			ErrorExit();
		}
		if (GetNextTuple(Fp, Tuple, TupleSize, &C) == TRUE) {
			Append(&TupleList, (generic *)Tuple);
			++i;
		}
	} while(!feof(Fp));

	if ( C != EOF ) {
		fprintf(stderr,"Error encountered while trying to read data stream...\n");
		ErrorExit();
	} else {
		NTuples = i;
	}


	/* convert to list of tuples to vectorized array */
	if ((Data = (FLOAT **)calloc(NTuples, sizeof(FLOAT *))) == (FLOAT **)NULL) {
		perror("(GetDataMem) ");
		ErrorExit();
	}

	for (A=TupleList.list_head,i=0; i<NTuples; i++,A=A->la_next) {
		Data[i] = (FLOAT *)A->la_p;
	}

	*m = NTuples;
	*n = TupleSize;
	return(Data);
}


bool
GetNextTuple(Fp, Tuple, n, C)
FILE	*Fp;
FLOAT	*Tuple;
int	n;
register int	*C;
{
	register int	j;
	double		D;
#ifdef	ANSI_C
	bool GetNextDbl(FILE *, double *, int *);
#else
	bool GetNextDbl();
#endif

	for (*C=' ',j=0; j<n && isspace((char)(*C)) && *C != EOF && *C != '\n'; ) {
		if (GetNextDbl(Fp, &D, C) == TRUE) {
			Tuple[j++] = D;
		}
	}
	/* strip trailing any trailing characters */
	for (; *C != '\n' && *C != EOF; )
		*C = fgetc(Fp);
	
	if ( j>0 && j<(n-1) ) {
		/* error */
		if (*C == EOF) {
			fprintf(stderr,"Unexpected EOF while reading data!\n");
		} else if (*C == '\n') {
			fprintf(stderr, "Unexpected EOL while reading tuple...\n");
		} else {
			fprintf(stderr, "Unable to interpret data stream...\n");
		}
		ErrorExit();
	}
	return(j==n? TRUE : FALSE);
}

bool
GetNextDbl(Fp, D, C)
FILE	*Fp;
double 	*D;
register int	*C;
/* returns next uninterpreted character in C and
 *	TRUE if found double else FALSE.
 */
{
	register int	i;
	register char	*cp;
	char		s[64];
	int		flag;

	for (flag=0,i=0,cp=s; i<sizeof(s)-1; ) {
		if ((*C = fgetc(Fp))  == EOF) {
			if (flag) {
				*cp = (char)NULL;
				if (sscanf(s, "%lf", D) == 1) {
					return(TRUE);
				} else {
					/* error */
					fprintf(stderr,"Encountered nonnumeric item in data stream...\n");
					ErrorExit();
				}
			} else {
				return(FALSE);
			}
		} else if (*C == '\n') {
			if (flag) {
				*cp = (char)NULL;
				if (sscanf(s, "%lf", D) == 1) {
					return(TRUE);
				} else {
					/* error */
					fprintf(stderr,"Encountered nonnumeric item in data stream...\n");
					ErrorExit();
				}
			} else {
				return(FALSE);
			}
		} else if (isspace(*C)) {
			if (flag) {
				*cp = (char)NULL;
				if (sscanf(s, "%lf", D) == 1) {
					return(TRUE);
				} else {
					/* error */
					fprintf(stderr,"Encountered nonnumeric item in data stream...\n");
					ErrorExit();
				}
			} else {
				continue;
			}
		} else {
			flag = 1;
			*cp++ = (char)(*C);
			++i;
		}
	}
	fprintf(stderr,"Possible internal error...\nEncountered data item greater than %d characters!\n", sizeof(s)-1);
	
	ErrorExit();
}
