/**---------------------------------------------------------------------------
 ** 
 ** io.c -- Navigation I/O utilities
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/15 15:07:57
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/09/04 17:07:36
 ** Update Count    : 13
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/libs/nav/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    This file contains functions for reading navigation files.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 ** 
 ** 1999/09/03 Pierre Jaccard
 **            Adding support for RMC messages.
 ** 1999/09/04 Pierre Jaccard
 **            Adding support for GLL messages.
 **------------------------------------------------------------------------**/

#include "io.h"
#include "io_misc.c"
#include "io_read.c"

/* ------------------------------------------------------------------
   The next functions are local
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 This function reads the next non-empty navigation line in a list of
	 navigation files. On input, if [[fchg]] is [[TRUE]], then reading next ping
	 data in next data file is allowed.

   RETURNS: non-zero on error
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int next_nav_line(/* Pointer to list of files */
                  FILE *fp, 
                  /* Information structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Pointer to navigation line */
                  char *line, 
                  /* Flagg for reading from next data files */
                  char fchg) 
#else
int next_nav_line(fp, fi, line, fchg)
FILE *fp;
DATA_FILE_INFO_TYPE *fi;
char *line;
char fchg;
#endif
{

	char func[]="next_nav_line";

	DATA_FILE_INFO_TYPE backup; 

	int error=0, done, i, len;

	/* Copy current state */
	memcpy((void *) &backup, (void *) fi, sizeof(DATA_FILE_INFO_TYPE));

	/* Read until a non empty line is found */
	done = 0;
	while(!done){
		/* Read next line from file */
		if(!(fgets(line, NAV_LINE_MAX_LENGTH-1, fi->fp))){
			/* No line has been read */
			if(feof(fi->fp)){
				if(fchg){
					/* Get next navigation file */
					error = next_data_file(fp, fi);
					if(error)
						done = 1;
					else
						/* Force an empty line to ensure reading the new file */
						strcpy(line, "");
				}
				else
					error = EOF;
			}
			else
				error = READ_ERROR;
		}
		if(error)
			done = 1;
		else{
			/* Check if current line is not empty */
			len = (int) strlen(line);
			i = 0;
			while((i < len) && isspace(line[i]))
				i++;
			done = (i < len);
		}
	}

	/* Update data file structure */
	if(!error)
		fi->data_pos = (ULONG) ftell(fi->fp);
	else{		
		if(error != EOF){
			/* Restore old values in file structure */
			memcpy((void *) fi, (void *) &backup, sizeof(DATA_FILE_INFO_TYPE));
			/* Position back to previous position */
			fseek(fp, (long) fi->list_pos, SEEK_SET);
			fseek(fi->fp, (long) fi->data_pos, SEEK_SET);
			/* Message */
			error_msg(func, "While reading next navigation line");
		}
		return(error);
	}

	return(0);

}

/* ------------------------------------------------------------------
   The next functions are available for other utilities
   ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 This function reads the next navigation line and fills the navigation
	 structure. 

	 RETURN: the code of the line read if successful an error code if failed 
					 EOF if there is no more navigation line

	 NOTE: error codes are negative, so that this does not conflict with the
	       navigation line codes.
	 ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int next_nav_ping(/* pointer to list of files */
                  FILE *fp, 
                  /* pointer to data files information structure */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* pointer to navigation structure */
                  NAV_TYPE *nav, 
									/* must contain previous time */
                  double last, 
                  /* year base used to calculate decimal day */
                  int year_base, 
                  /* if positive, the time is incremented from the value of
                     [[last]], unless the current navigation line contains
                     time information. */
                  double inc, 
                  /* bits containing navigation lines to read */
                  ULONG bits)
#else
int next_nav_ping(fp, fi, nav, last, year_base, inc, bits)
FILE *fp;
DATA_FILE_INFO_TYPE *fi;
NAV_TYPE *nav;
double last;
int year_base;
double inc;
#endif
{

	char func[]="next_nav_ping";

	int error, code, flag;
	NAV_LINES_TYPE lines;
	char line[NAV_LINE_MAX_LENGTH], *ptr;


	/* Initializations */
	flag = BAD_LINE_CODE;
	code = 0;
	ptr  = (char *) NULL;

	/* Read the next non-empty navigation line */
	error = next_nav_line(fp, fi, line, 1); 
	if(error){
		if(error != EOF)
			error_msg(func, "While reading next navigation line");
		return(error);
	}

	/* Process the navigation line */
	while(code <= MAX_NAV_LINE_CODES){
		/* Check if the line is of the specific type */
		ptr = is_nav_line(line, code);
		if(ptr){
			/* Try to process the line */
			switch(code){
			case ZDA_LINE_CODE:
				if(read_zda_line(ptr, &(lines.zda), year_base)){
					flag = ZDA_LINE_CODE;
					goto got_nav;
				}
				break;
			case GGA_LINE_CODE:
				if(read_gga_line(ptr, &(lines.gga), last, year_base)){
					flag = GGA_LINE_CODE;
					goto got_nav;
				}
				break;
			case VTG_LINE_CODE:
				if(read_vtg_line(ptr, &(lines.vtg))){
					flag = VTG_LINE_CODE;
					goto got_nav;
				}
				break;
			case HDT_LINE_CODE:
				if(read_hdt_line(ptr, &(lines.hdt))){
					flag = HDT_LINE_CODE;
					goto got_nav;
				}
				break;
			case PRDID_LINE_CODE:
				if(read_prdid_line(ptr, &(lines.prdid))){
					flag = PRDID_LINE_CODE;
					goto got_nav;
				}
				break;
			case TRANSECT_LINE_CODE:
				if(read_transect_line(ptr, &(lines.transect))){
					flag = TRANSECT_LINE_CODE;
					goto got_nav;
				}
        break;
		case RMC_LINE_CODE:
				if(read_rmc_line(ptr, &(lines.rmc), year_base)){
					flag = RMC_LINE_CODE;
					goto got_nav;
				}
				break;
		case GLL_LINE_CODE:
				if(read_gll_line(ptr, &(lines.gll))){
					flag = GLL_LINE_CODE;
					goto got_nav;
				}
				break;
			default:
				/* Reset ptr's value */
				ptr = (char *) NULL;
			}
		}
		/* Update code's value */
		code++;
	}

got_nav:
	
	/* Check if this line should be ignored */
	if((flag != BAD_LINE_CODE) && !((ULONG) to_bit(flag) & bits))
		flag = IGNORED_LINE_CODE;
		
	/* Fill the navigation structure */
	if((flag != BAD_LINE_CODE) && (flag != IGNORED_LINE_CODE))
		fill_navigation(nav, &lines, flag, last, inc);

	/* It is important to force a time into the navigation structure, because
		 next calls to this function will most probably use this value as the
		 [[last]] parameter */
	if(!(nav->yd < ADJ_BADFLOAT))
		nav->yd = last;

	return(flag);
	
}
