/**---------------------------------------------------------------------------
 ** 
 ** nav_.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/30 16:12:59
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/09/04 17:15:40
 ** Update Count    : 18
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/apps/nav/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 ** 
 ** 1999/09/03 Pierre Jaccard
 **            Adding support for RMC messages.
 ** 1999/09/04 Pierre Jaccard
 **            Adding support for GLL messages.
 **------------------------------------------------------------------------**/

/* ##################################################################

	-Introduction:

	High level functions for scanning through the navigation files, using the
	lower level functions defined in [[misc_nav.c]].

	This file should be included in the main file.

	##################################################################
*/

#ifndef nav__C_code_already_included
#define nav__C_code_already_included

#include "nav_.h"

#if PROTOTYPE_ALLOWED

int data_stat_header(FILE *fp, SCAN_NAV_TYPE *scan);
int ens_info(SCAN_NAV_TYPE *scan);

#else

int ens_info();
int data_stat_header();

#endif

/* ##################################################################
	 -Initializations:
	 ################################################################## */

#define DEBUG 0

/* ------------------------------------------------------------------
	 --Initializations of Options:

	 This function should be called at startup, before reading parameters and
	 options from the control file.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_options()
#else
int init_options()
#endif
{

	strcpy(nav_file, "");
	data_stat_bits = 0x0;
	nav_lines_bits = 0x0;

	return(0);

}

/* ------------------------------------------------------------------
	 --Initialization of Files:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_files(NAV_FILES_TYPE *fps)
#else
int init_files(fps)
#endif
{

	FILE_NAME_TYPE file;
	DOUBLE blog;

	fps->lst = check_fopen((char *) file_list, "r");
	new_extension(file, out_file, ".log");
	fps->log = check_fopen((char *) file, "w");
	new_extension(file, out_file, ".bin");
	fps->bin = check_fopen((char *) file, "wb");
	new_extension(file, out_file, ".sta");
	fps->sta = check_fopen((char *) file, "w");
	new_extension(file, out_file, ".out");
	fps->out = check_fopen((char *) file, "w");

	if(strlen(nav_file))
		fps->nav = check_fopen((char *) file, "r");
	else
		fps->nav = NULL;
	
	set_msg_file(fps->log);

	/* Write a control float in the binary file for automatic selection
		 of opening parameters in Matlab */
	blog = 1.0;
	fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);

	return(0);

}

/* ------------------------------------------------------------------
	 --Closing Files:

	 This function should be called before leaving the programme
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int close_files(NAV_FILES_TYPE *fps, DATA_FILE_INFO_TYPE *fi)
#else
int close_files(fps, fi)
#endif
{

	fclose(fps->lst);
	if(fps->nav)
		fclose(fps->nav);
	fclose(fps->sta);
	fclose(fps->log);
	fclose(fps->bin);
	fclose(fps->out);
	if(fi->fp)
		fclose(fi->fp);

	return(0);

}

/* ------------------------------------------------------------------
	 --Releasing Memory:

	 This function should be called before leaving the programme
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int free_memory(SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr)
#else
int free_memory(prev, curr)
#endif
{

	free_unistat_list(prev->data_stat_list);
	free_unistat_list(prev->scan_stat_list);
	free_unistat_list(prev->data_stat_list0);
	free_unistat_list(prev->scan_stat_list0);
	free_flag_list(prev->flag_list);
	/* --------------------------------- */
	free(prev->data_stat_list);
	free(prev->scan_stat_list);
	free(prev->data_stat_list0);
	free(prev->scan_stat_list0);
	free(prev->flag_list);
	
	free_unistat_list(curr->data_stat_list);
	free_unistat_list(curr->scan_stat_list);
	free_unistat_list(curr->data_stat_list0);
	free_unistat_list(curr->scan_stat_list0);
	free_flag_list(curr->flag_list);
	/* --------------------------------- */
	free(curr->data_stat_list);
	free(curr->scan_stat_list);
	free(curr->data_stat_list0);
	free(curr->scan_stat_list0);
	free(curr->flag_list);

	return(0);

}

/* ------------------------------------------------------------------
	 --Before Exit:

	 This function closes files and release memory. It should be called before
	 leaving the [[do_it]] function in the main programme. The value of
	 [[error]] should contain the error code value on exit.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int before_exit(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr,
								int error)
#else
int before_exit(fps, prev, curr, error)
#endif
{

	/* Close the files */
	close_files(fps, &(curr->fi));
	/* Free all variables */
	free_memory(prev, curr);

	/* Check for errors */
	if(error){
		if(error != EOF)
			printf("\n\n\t !!! Function `do_it' ended with error !!!\n\n");
		else
			printf("\n\n\t Function `do_it' ended at EOF \n\n");
	}
	else
		printf("\n\n\t Function `do_it' ended normally \n\n");

	return(0);

}

/* ------------------------------------------------------------------
	 --Initialize Scanning:

	 This function does a complete initialization after all parameters and
	 options have been read from the control file. It groups the initializations
	 defined above.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_scan(NAV_FILES_TYPE *fps,
							SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr)
#else
int init_scan(fps, prev, curr)
#endif
{

	char func[]="init_scan";

	/* Initialize files */
	init_files(fps);

	/* Initialize options bits, by default ALL is selected */
	if(!data_stat_bits)
		data_stat_bits |= (ALL_DATA_STAT_BIT | ALL_FLAGS_BIT);
	if(!nav_lines_bits)
		nav_lines_bits |= ALL_NAV_MESSAGES_BIT;

	/* Initialize required unistat variables */
	prev->data_stat_list = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(data_stat_list, (char *) &data_stat_bits, 0);
	if(prev->data_stat_list == NULL){
		error_msg(func, "while initializing data stat list [prev]");
		return(INSUFFICIENT_MEMORY);
	}
	prev->scan_stat_list = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(scan_stat_list, (char *) &data_stat_bits, 0);
	if(prev->scan_stat_list == NULL){
		error_msg(func, "while initializing scan stat list [prev]");
		return(INSUFFICIENT_MEMORY);
	}
	/* --------------------------------- */
	curr->data_stat_list = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(data_stat_list, (char *) &data_stat_bits, 0);
	if(curr->data_stat_list == NULL){
		error_msg(func, "while initializing data stat list [curr]");
		return(INSUFFICIENT_MEMORY);
	}
	curr->scan_stat_list = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(scan_stat_list, (char *) &data_stat_bits, 0);
	if(curr->scan_stat_list == NULL){
		error_msg(func, "while initializing ensemble stat list [curr]");
		return(INSUFFICIENT_MEMORY);
	}
	/* --------------------------------- */
	prev->data_stat_list0 = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(data_stat_list, (char *) &data_stat_bits, 0);
	if(prev->data_stat_list0 == NULL){
		error_msg(func, "while initializing data stat list [prev]");
		return(INSUFFICIENT_MEMORY);
	}
	prev->scan_stat_list0 = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(scan_stat_list, (char *) &data_stat_bits, 0);
	if(prev->scan_stat_list0 == NULL){
		error_msg(func, "while initializing scan stat list [prev]");
		return(INSUFFICIENT_MEMORY);
	}
	/* --------------------------------- */
	curr->data_stat_list0 = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(data_stat_list, (char *) &data_stat_bits, 0);
	if(curr->data_stat_list0 == NULL){
		error_msg(func, "while initializing data stat list [curr]");
		return(INSUFFICIENT_MEMORY);
	}
	curr->scan_stat_list0 = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(scan_stat_list, (char *) &data_stat_bits, 0);
	if(curr->scan_stat_list0 == NULL){
		error_msg(func, "while initializing ensemble stat list [curr]");
		return(INSUFFICIENT_MEMORY);
	}

	/* Initialize required flag variables */
	curr->flag_list = (FLAG_LIST_TYPE *) 
		init_flag_list(flag_list, (char *) &data_stat_bits, 0);
	if(curr->flag_list == NULL){
		error_msg(func, "while initializing flag list [curr]");
		return(INSUFFICIENT_MEMORY);
	}
	prev->flag_list = (FLAG_LIST_TYPE *) 
		init_flag_list(flag_list, (char *) &data_stat_bits, 0);
	if(prev->flag_list == NULL){
		error_msg(func, "while initializing flag list [prev]");
		return(INSUFFICIENT_MEMORY);
	}

	/* Initialize file information structures */
	init_file_info(NULL, &(prev->fi), "r");
	init_file_info(fps->lst, &(curr->fi), "r");

	/* Write data stat header in the log file
	   NOTE: the header for output data is written by the function writting data
		       to the output file */
	data_stat_header(fps->log, curr);

	init_navigation(&(prev->nav), -1);
	init_navigation(&(prev->nav0), -1);
	init_navigation(&(curr->nav), -1);
	init_navigation(&(curr->nav0), -1);

	init_scan_nav_line(&(prev->scan), -1);
	init_scan_nav_line(&(curr->scan), -1);

	return(0);

}

/* ##################################################################
	 -Statistics Functions:
	 ################################################################## */

/* ------------------------------------------------------------------
	 --Calculate Statistics:

	 Given a pointer to an UNISTAT_LIST_TYPE list, this function calculates the
	 statistics of each element in the list. Additionnal transformation are done
	 after the statistics has been performed, according to the value of the
	 [[code]] value of the elements.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int calculate_stat(UNISTAT_LIST_TYPE *list)
#else
int calculate_stat(list)
#endif
{

	UNISTAT_LIST_TYPE *uni;

	/* Begin statistics calculation */
	uni = list;
	while(uni->name != NULL){

		/* Calculate statistics */
		calculate_unistat(uni->stat);

		/* Special transformations */
		switch(uni->code){
		case NAV_HEADING_CODE:
			*(uni->stat->sum) = to360(*(uni->stat->sum));
			*(uni->stat->max) = to360(*(uni->stat->max));
			*(uni->stat->min) = to360(*(uni->stat->min));
			break;
		case NAV_COURSE_FROM_POS_CODE:
			*(uni->stat->sum) = to360(*(uni->stat->sum));
			*(uni->stat->max) = to360(*(uni->stat->max));
			*(uni->stat->min) = to360(*(uni->stat->min));
			break;
		case NAV_SHIP_COURSE_CODE:
			*(uni->stat->sum) = to360(*(uni->stat->sum));
			*(uni->stat->max) = to360(*(uni->stat->max));
			*(uni->stat->min) = to360(*(uni->stat->min));
			break;
		default:
			/* Skipp other variables */
			break;
		}
		/* Update list pointer */
		uni++;
	}
	
	return(0);
}

/* ------------------------------------------------------------------
	 Since ensemble and data UNISTAT_LIST_TYPE lists are used for different
	 purposes, it is best to have a separate function for updating them and
	 writting them to a file.
	 ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 --Update Ensemble Statistics:

	 This function updates the statistics for scan_nav data.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int update_scan_nav_stat(UNISTAT_LIST_TYPE *list, SCAN_NAV_TYPE *scan)
#else
int update_scan_nav_stat(list, scan)
#endif
{

	char func[]="update_scan_nav_stat";

	UNISTAT_LIST_TYPE *uni;
	static double ref_heading=0.0;
	static double ref_course=0.0;
	ULONG bits=0;

	/* Build the update bits */
	if(get_flag(scan->flag_list, NAV_HEADING_FLAG, 0))
		bits |= NAV_HEADING_BIT;
	if(get_flag(scan->flag_list, NAV_ROLL_FLAG, 0))
		bits |= NAV_ROLL_BIT;
	if(get_flag(scan->flag_list, NAV_PITCH_FLAG, 0))
		bits |= NAV_PITCH_BIT;
	if(get_flag(scan->flag_list, NAV_COURSE_FLAG, 0))
		bits |= NAV_SHIP_COURSE_BIT;
	if(get_flag(scan->flag_list, NAV_SPEED_FLAG, 0))
		bits |= NAV_SHIP_SPEED_BIT;

	/* Begin statistics update */
	uni = list;
	while(uni->name != NULL){
		/* Check if update is required */
		if((ULONG) to_bit(uni->code) & bits){
			switch(uni->code){
			case NAV_HEADING_CODE:
				if(scan->nav.heading < ADJ_BADFLOAT){
					*(uni->data) = nearest_angle(ref_heading, scan->nav.heading);
					ref_heading = *(uni->data);
				}
				else{
					ref_heading = 0.0;
					*(uni->data) = BADDOUBLE;
				}
				break;
			case NAV_PITCH_CODE:
				*(uni->data) = scan->nav.pitch;
				break;
			case NAV_ROLL_CODE:
				*(uni->data) = scan->nav.roll;
				break;
			case NAV_SHIP_COURSE_CODE:
				if(scan->nav.course < ADJ_BADFLOAT){
					*(uni->data) = nearest_angle(ref_course, scan->nav.course);
					ref_course = *(uni->data);
				}
				else{
					ref_course = 0.0;
					*(uni->data) = BADDOUBLE;
				}
				break;	
			case NAV_SHIP_SPEED_CODE:
				*(uni->data) = scan->nav.speed;
				break;
			default:
				warning_msg(func, "No ens_stat defined for this code");
				break;
			}
			/* Update statistics */
			update_unistat_d(uni->stat, uni->data, uni->size);
		}
		/* Update pointer */
		uni++;
	}

	return(0);
}
				
/* ------------------------------------------------------------------
	 --Update Data Statistics:

	 This function updates data statistics in the specified list. If [[code]] is
	 negative, then only statistics for end_of_ensemble are updated.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int update_data_stat(UNISTAT_LIST_TYPE *list, SCAN_NAV_TYPE *prev, 
										 SCAN_NAV_TYPE *curr, int code)
#else
int update_data_stat(list, prev, curr, code)
#endif
{

	char func[]="update_data_stat";

	ULONG bits=0;
	
	static double ref_hdg=0.0;
	static double ref_crs_from_pos=0.0;
	double tmp_heading;
	double *data;
	UNISTAT_LIST_TYPE *u;

	/* Build the check bit */
	if(get_flag(curr->flag_list, ENSEMBLE_DONE_FLAG, 0))
		bits |= TIME_BETWEEN_ENSEMBLE_BIT;
	/*
	if(get_flag(curr->flag_list, GET_TIME_INC_FLAG, 0) < 0)
 		bits |= TIME_INCREMENT_BIT;
		*/
	if(code >= 0){
		if(get_flag(curr->flag_list, NAV_TIME_FLAG, 0))
			bits |= TIME_BETWEEN_NAV_PING_BIT;
		if(get_flag(curr->flag_list, NAV_POSITION_FLAG, 0)){
			bits |= NAV_TRAVELLED_DISTANCE_BIT;
			bits |= NAV_COURSE_FROM_POS_BIT;
		}
		if((bits & NAV_TRAVELLED_DISTANCE_BIT) 
			 && (bits & TIME_BETWEEN_NAV_PING_BIT)) 
			bits |= NAV_SPEED_FROM_POS_BIT;
		if(get_flag(curr->flag_list, NAV_HEADING_FLAG, 0))
			bits |= NAV_HEADING_BIT;
		if(get_flag(curr->flag_list, NAV_PITCH_FLAG, 0))
			bits |= NAV_PITCH_BIT;
		if(get_flag(curr->flag_list, NAV_ROLL_FLAG, 0))
			bits |= NAV_ROLL_BIT;
		if(get_flag(curr->flag_list, NAV_SATELLITE_FLAG, 0))
			bits |= SATELLITE_NUMBER_BIT | SATELLITE_HDOP_BIT | SATELLITE_HEIGHT_BIT;
		if(get_flag(curr->flag_list, NAV_COURSE_FLAG, 0))
			bits |= NAV_SHIP_COURSE_BIT;
		if(get_flag(curr->flag_list, NAV_SPEED_FLAG, 0))
			bits |= NAV_SHIP_SPEED_BIT;
	}

	/* Begin statistics update */
	u = list;
	while(u->name != NULL){
		/* Check if update is required */
		if(((ULONG) to_bit(u->code) & data_stat_bits)
			 && ((ULONG) to_bit(u->code) & bits)){
			/* Allocate space for data values */
			data = calloc(u->size, sizeof(double));
			if(!data){
				error_msg(func, "Could not allocate space for data");
				return(INSUFFICIENT_MEMORY);
			}
			switch(u->code){
			case TIME_BETWEEN_ENSEMBLE_CODE:
				if((curr->scan.time.start < ADJ_BADFLOAT) 
					 && (curr->scan.time.stop < ADJ_BADFLOAT))
					*(data) = 
						(curr->scan.time.stop - curr->scan.time.start) * 86400.0;
				else
					*(data) = BADDOUBLE;
				break;
			case TIME_BETWEEN_NAV_PING_CODE:
				if((prev->nav.yd < ADJ_BADFLOAT) 
					 && (curr->nav.yd < ADJ_BADFLOAT)
					 && (prev->nav.yd != curr->nav.yd))
					*(data) = (curr->nav.yd - prev->nav.yd) * 86400.0;
				else
					*(data) = BADDOUBLE;
				break;
				case TIME_INCREMENT_CODE:
					if(curr->nav.inc < ADJ_BADFLOAT)
						*(data) = curr->nav.inc;
					else
						*(data) = BADDOUBLE;
					break;
			case NAV_TRAVELLED_DISTANCE_CODE:
				if((prev->nav.pos.lat < ADJ_BADFLOAT) 
					 && (prev->nav.pos.lon < ADJ_BADFLOAT)
					 && (curr->nav.pos.lat < ADJ_BADFLOAT)
					 && (curr->nav.pos.lon < ADJ_BADFLOAT))
					*(data) = 
						posdiff_meter_d(prev->nav.pos.lon, prev->nav.pos.lat,
														curr->nav.pos.lon, curr->nav.pos.lat);
				else
					*(data) = BADDOUBLE;
				break;
			case NAV_SPEED_FROM_POS_CODE:
				if((prev->nav.pos.lat < ADJ_BADFLOAT) 
					 && (prev->nav.pos.lon < ADJ_BADFLOAT)
					 && (curr->nav.pos.lat < ADJ_BADFLOAT)
					 && (curr->nav.pos.lon < ADJ_BADFLOAT)
					 && (prev->nav.yd < ADJ_BADFLOAT) 
					 && (curr->nav.yd < ADJ_BADFLOAT)
					 && (curr->nav.yd != prev->nav.yd))
					*(data) = 
						posdiff_meter_d(prev->nav.pos.lon, prev->nav.pos.lat,
														curr->nav.pos.lon, curr->nav.pos.lat) / 
						((curr->nav.yd - prev->nav.yd)*86400.0) * 3.6 * 0.51479;
				else
					*(data) = BADDOUBLE;
				break;
			case NAV_COURSE_FROM_POS_CODE:
				if((prev->nav.pos.lat < ADJ_BADFLOAT) 
					 && (prev->nav.pos.lon < ADJ_BADFLOAT)
					 && (curr->nav.pos.lat < ADJ_BADFLOAT)
					 && (curr->nav.pos.lon < ADJ_BADFLOAT))
					tmp_heading = 
						posdiff_direction_d(prev->nav.pos.lon, prev->nav.pos.lat,
																curr->nav.pos.lon, curr->nav.pos.lat);
				else
					tmp_heading = BADDOUBLE;
				if(tmp_heading < ADJ_BADFLOAT){
					*(data) = nearest_angle(ref_crs_from_pos, tmp_heading);
					ref_crs_from_pos = tmp_heading;
				}
				else{
					ref_crs_from_pos = 0.0;
					*(data) = BADDOUBLE;
				}				
				break;
			case NAV_HEADING_CODE:
				if(curr->nav.heading < ADJ_BADFLOAT){
					*(data) = nearest_angle(ref_hdg, curr->nav.heading);
					ref_hdg = curr->nav.heading;
				}
				else{
					ref_hdg = 0.0;
					*(data) = BADDOUBLE;
				}
				break;
			case NAV_PITCH_CODE:
				*(data) = curr->nav.pitch;
				break;
			case NAV_ROLL_CODE:
				*(data) = curr->nav.roll;
				break;
			case SATELLITE_NUMBER_CODE:
				if(curr->nav.nsat != BADUSHORT)
					*(data) = (double) curr->nav.nsat;
				else
					*(data) = BADDOUBLE;
				break;
			case SATELLITE_HDOP_CODE:
				if(curr->nav.hdop != ADJ_BADFLOAT)
					*(data) = curr->nav.hdop;
				else
					*(data) = BADDOUBLE;
				break;
			case SATELLITE_HEIGHT_CODE:
				if(curr->nav.height != ADJ_BADFLOAT)
					*(data) = (double) curr->nav.height;
				else
					*(data) = BADDOUBLE;
				break;
			case NAV_SHIP_COURSE_CODE:
				if(curr->nav.course < ADJ_BADFLOAT)
					*(data) = curr->nav.course;
				else
					*(data) = BADDOUBLE;
				break;
			case NAV_SHIP_SPEED_CODE:
				if(curr->nav.speed < ADJ_BADFLOAT)
					*(data) = curr->nav.speed;
				else
					*(data) = BADDOUBLE;
				break;
			default:
				warning_msg(func, "No data_stat defined for this code");
				break;
			}
			/* Copy data into specific unistat lists and update statistics */
			*(u->data) = *(data);
			update_unistat_d(u->stat, u->data, 1);
			/* Free data pointer */
			free(data);

		}
		/* Update pointer */
		u++;
	}


	return(0);
}

/* ------------------------------------------------------------------
	 --Final Statistics:

	 This function calculates statistics for all elements in an
	 UNISTAT_LIST_TYPE list and write it into a file. If [[fp]] si NULL, then
	 output is skipped. A message for identifying the statistics is logged. Its
	 content is current time given by [[yd]] and [[year_base]], and a number for
	 the statistics that is incremented each time this function is called.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int final_stat(FILE *fp, UNISTAT_LIST_TYPE *list, double yd, int year_base)
#else
int final_stat(fp, curr, yd, year_base)
#endif
{

	static int stat_count = 0;

	UNISTAT_LIST_TYPE *uni;
	char label[5], str[100], msg[200];
	int i;

	/* Calculate statistics */
	calculate_stat(list);

	/* Check for writting statistics */
	if(fp){
		/* Message */
		yd_to_ymdhms_str(str, yd, year_base);
		sprintf(msg, "\n\n%%%% TIME: %s  Calculating Statistics", str);
		report_msg(msg);
		sprintf(label, "%03d", stat_count);
		sprintf(msg, "\n%%%% Statistics number %s\n", label);
		report_msg(msg);
		
		/* Header for statistics */
		for(i=0; i<96; i++)
			fprintf(fp, "%c", '-');
		fprintf(fp, "\n\t SCAN_LOG Statistics %03d\n", stat_count);
		for(i=0; i<96; i++)
			fprintf(fp, "%c", '-');
		fprintf(fp, "\n");
		
		/* Write statistics */
		uni = list;
		while(uni->name != NULL){
			write_unistat(fp, uni->stat, 1.0, NULL, label, 0); 
			uni++;
		}
		
		fprintf(fp, "\n");
	}
	
	/* Update statistics number */
	stat_count++;

	return(0);
}

/* ##################################################################
	 -Processing Functions:
	 ################################################################## */

/* ------------------------------------------------------------------
	 --Update Flags:

	 This function set the flags after a new navigation line has been read. If
	 [[prev]] is [[NULL]] a minimal update is performed.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int update_flags(SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr, int flag)
#else
int update_flags(prev, curr, flag)
#endif
{

	/*
	FLAG_LIST_TYPE *f;
	int i;
	*/
#if (DEBUG == 1)
  char str[200];
#endif

	/* Set the navigation line flag */
	set_flag(curr->flag_list, NAV_LINE_FLAG, 0, flag);

	/* Set the specific navigation line flags according to the flag */
	set_flag(curr->flag_list, NAV_TIME_FLAG,      0, 0);
	set_flag(curr->flag_list, NAV_POSITION_FLAG,  0, 0);
	set_flag(curr->flag_list, NAV_HEADING_FLAG,   0, 0);
	set_flag(curr->flag_list, NAV_PITCH_FLAG,     0, 0);
	set_flag(curr->flag_list, NAV_ROLL_FLAG,      0, 0);
	set_flag(curr->flag_list, NAV_COURSE_FLAG,    0, 0);
	set_flag(curr->flag_list, NAV_SPEED_FLAG,     0, 0);
	set_flag(curr->flag_list, NAV_SATELLITE_FLAG, 0, 0);
	set_flag(curr->flag_list, NAV_PRECISION_FLAG, 0, 0);
	switch(flag){
	case GGA_LINE_CODE:
		set_flag(curr->flag_list, NAV_TIME_FLAG,      0, 1);
		set_flag(curr->flag_list, NAV_POSITION_FLAG,  0, 1);
		set_flag(curr->flag_list, NAV_SATELLITE_FLAG, 0, 1);
		set_flag(curr->flag_list, NAV_PRECISION_FLAG, 0, 1);
		if(curr->nav.qual > 0)
			set_flag(curr->flag_list, GPS_CODE, 0, 1);
		else
			set_flag(curr->flag_list, GPS_CODE, 0, 0);
		if(curr->nav.qual > 1)
			set_flag(curr->flag_list, DGPS_CODE, 0, 1);
		else
			set_flag(curr->flag_list, DGPS_CODE, 0, 0);
		break;
	case ZDA_LINE_CODE:
		set_flag(curr->flag_list, NAV_TIME_FLAG,      0, 1);
		break;
	case HDT_LINE_CODE:
		set_flag(curr->flag_list, NAV_HEADING_FLAG,   0, 1);
		break;
	case PRDID_LINE_CODE:
		set_flag(curr->flag_list, NAV_HEADING_FLAG,   0, 1);
		set_flag(curr->flag_list, NAV_PITCH_FLAG,     0, 1);
		set_flag(curr->flag_list, NAV_ROLL_FLAG,      0, 1);
		break;
	case VTG_LINE_CODE:
		set_flag(curr->flag_list, NAV_COURSE_FLAG,    0, 1);
		set_flag(curr->flag_list, NAV_SPEED_FLAG,     0, 1);
		break;
	case RMC_LINE_CODE:
		set_flag(curr->flag_list, NAV_TIME_FLAG,      0, 1);
		set_flag(curr->flag_list, NAV_POSITION_FLAG,  0, 1);
		set_flag(curr->flag_list, NAV_COURSE_FLAG,    0, 1);
		set_flag(curr->flag_list, NAV_SPEED_FLAG,     0, 1);
		break;
	case GLL_LINE_CODE:
		set_flag(curr->flag_list, NAV_POSITION_FLAG,  0, 1);
		break;
	}
	
	if(prev == NULL)
		return(0);
	
	/* Reset things when ensemble done */
	if(get_flag(prev->flag_list, ENSEMBLE_DONE_FLAG, 0)){
		set_flag(curr->flag_list, ENSEMBLE_DONE_FLAG, 0, 0);
		set_flag(curr->flag_list, CORRECT_TRANSECT_FLAG, 0, 0);
		set_flag(curr->flag_list, APPLY_TRANSECT_CORRECTIONS_FLAG, 0, 0);
		/* Initialize time info for next transect */
		set_flag(curr->flag_list, TIME_AFTER_TRANSECT_FLAG, 0, 0);
		if(get_flag(prev->flag_list, TIME_AFTER_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0, 1);
		else
			set_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0, 0);
		/* Initialize position info for next transect */
		set_flag(curr->flag_list, POS_AFTER_TRANSECT_FLAG, 0, 0);
		if(get_flag(prev->flag_list, POS_AFTER_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0, 1);
		else
			set_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0, 0);
	}
	
	/* Control of TRANSECT corrections */
	if(flag == TRANSECT_LINE_CODE){
		/* Set the correction flag */
		set_flag(curr->flag_list, CORRECT_TRANSECT_FLAG, 0, 1);
		/* Initialize time info for new ensemble */
		set_flag(curr->flag_list, TIME_AFTER_TRANSECT_FLAG, 0, 0);
		if(get_flag(prev->flag_list, TIME_AFTER_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0, 1);
		/*
		else
			set_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0, 0);
			*/
		/* Initialize position info for new ensemble */
		set_flag(curr->flag_list, POS_AFTER_TRANSECT_FLAG, 0, 0);
		if(get_flag(prev->flag_list, POS_AFTER_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0, 1);
		/*
		else
			set_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0, 0);
			*/
	}
	
	/* Update time info */
	if(get_flag(curr->flag_list, NAV_TIME_FLAG, 0)){
		/* Update time info before transect */
		if(get_flag(curr->flag_list, CORRECT_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, TIME_AFTER_TRANSECT_FLAG, 0, 1);
		else
			set_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0, 1);
	}	

	/* Update position info */
	if(get_flag(curr->flag_list, NAV_POSITION_FLAG, 0)){
		/* Update time info before transect */
		if(get_flag(curr->flag_list, CORRECT_TRANSECT_FLAG, 0))
			set_flag(curr->flag_list, POS_AFTER_TRANSECT_FLAG, 0, 1);
		else
			set_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0, 1);
	}
		 
	/* Set the flag to launch time increment calculations */
	if(get_flag(curr->flag_list, CORRECT_TRANSECT_FLAG, 0)
     && get_flag(curr->flag_list, TIME_BEFORE_TRANSECT_FLAG, 0)
     && get_flag(curr->flag_list, TIME_AFTER_TRANSECT_FLAG, 0)
     && get_flag(curr->flag_list, POS_BEFORE_TRANSECT_FLAG, 0)
     && get_flag(curr->flag_list, POS_AFTER_TRANSECT_FLAG, 0)){
		set_flag(curr->flag_list, APPLY_TRANSECT_CORRECTIONS_FLAG, 0, 1);
#if (DEBUG == 1)
    sprintf(str, "\nDEBUG: [%-d] Should apply TRANSECT corrections\n",
            curr->nav.number);
    report_msg(str);
#endif
  }
	else
		set_flag(curr->flag_list, APPLY_TRANSECT_CORRECTIONS_FLAG, 0, 0);
		
  
	/*
	if(!(get_flag(curr->flag_list, GET_TIME_INC_FLAG, 0))
		 && is_nav_time(flag)) 
		set_flag(curr->flag_list, GET_TIME_INC_FLAG, 0, 1);
	else
		set_flag(curr->flag_list, GET_TIME_INC_FLAG, 0, 0);
		*/

	/*
	printf("\n");
	f = curr->flag_list;
	while(f->name != NULL){
		for(i=0; i<(f->size); i++)
			printf("[%-d%c%-d]=%-d -- ", f->code, '.', i, *(f->flag + i));
		f++;
	}
	printf("\n");
	fflush(stdout);
	*/

	return(0);

}


/* ------------------------------------------------------------------
	 --Check Flags values:

	 This function check the value of the various flags and report messages if
	 necessary. 
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int check_flags(SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr)
#else
int check_flags(prev, curr)
#endif
{

	int flag, gps, dgps, last_gps, last_dgps, info=1;
	ULONG bits=0;
	FLAG_LIST_TYPE *f;

#if DEBUG
  char str[200], msg[200]; 
#endif

	/* Get the flags */
	flag = get_flag(curr->flag_list, NAV_LINE_FLAG, 0);
	gps  = get_flag(curr->flag_list, GPS_CODE, 0);
	dgps = get_flag(curr->flag_list, DGPS_CODE, 0);
	last_gps  = get_flag(prev->flag_list, GPS_CODE, 0);
	last_dgps = get_flag(prev->flag_list, DGPS_CODE, 0);

	if(flag == BAD_LINE_CODE){
		info = ens_info(curr);
		report_msg("%% BAD NAVIGATION LINE\n");
	}

#if DEBUG
	strcpy(msg, "");
	yd_to_ymdhms_str(str, prev->nav.yd, year_base);
	sprintf(msg, "\nDEBUG: PREV: %s flag=%-d ens=%-d  ", str, 
					get_flag(prev->flag_list, NAV_LINE_FLAG, 0), prev->nav.number);
	report_msg(msg);
	degree_to_str(str, prev->nav.pos.lat, 1, DM_FORMAT_CODE);
  strcat(str, "  ");
	report_msg(str);
	degree_to_str(str, prev->nav.pos.lon, -1, DM_FORMAT_CODE);
	report_msg(str);
	strcpy(msg, "\n");
	f = prev->flag_list;
	while(f->name != NULL){
		sprintf(str, "[%-d=%-d]", f->code, 
						get_flag(prev->flag_list, f->code, 0));
		strcat(msg, str);
		f++;
	}
	strcat(msg,"\n");
	report_msg(msg);
	yd_to_ymdhms_str(str, curr->nav.yd, year_base);	
	sprintf(msg, "DEBUG: CURR: %s flag=%-d ens=%-d  ", str,
					get_flag(curr->flag_list, NAV_LINE_FLAG, 0), curr->nav.number);
	report_msg(msg);
	degree_to_str(str, curr->nav.pos.lat, 1, DM_FORMAT_CODE);
  strcat(str, "  ");
	report_msg(str);
	degree_to_str(str, curr->nav.pos.lon, -1, DM_FORMAT_CODE);
	report_msg(str);
	strcpy(msg, "\n");
	f = curr->flag_list;
	while(f->name != NULL){
		sprintf(str, "[%-d=%-d]", f->code, 
						get_flag(curr->flag_list, f->code, 0));
		strcat(msg, str);
		f++;
	}
	strcat(msg,"\n");
	report_msg(msg);
	strcpy(msg, "");
#endif	

  /*
   * 2000/11/30 PJ
   *            Had to add test for ENSEMBLE_DONE_FLAG also, or corrections
   *            will not work if there is only one GGA line bewteen TRANSECT
   *            lines 
   */
	if((flag == TRANSECT_LINE_CODE)
		 && (get_flag(prev->flag_list, CORRECT_TRANSECT_FLAG, 0))
     && !(get_flag(prev->flag_list, ENSEMBLE_DONE_FLAG, 0))){
		info = ens_info(prev);
		report_msg("%% NO CORRECTIONS FOR TRANSECT DATA\n");
		return(SKIP_NEXT_LINES);
	}
  

	/* Build the check bit */
	if(data_stat_bits & GPS_BIT)   bits |= GPS_BIT;
	if(data_stat_bits & DGPS_BIT)  bits |= DGPS_BIT;

	f = curr->flag_list;
	while(f->name != NULL){
		if((ULONG) to_bit(f->code) & bits){
			switch(f->code){
			case GPS_CODE:
				if(last_gps != gps){
					if(info) info = ens_info(curr);
					if(gps > 0)      report_msg("%% GPS is ON\n");
					else if(gps < 0) report_msg("%% NO GPS INFORMATION\n");
					else             report_msg("%% GPS is OFF\n");
				}
				set_flag(prev->flag_list, GPS_CODE, 0, gps);
				break;
			case DGPS_CODE:
				if(last_dgps != dgps){
					if(info) info = ens_info(curr);
					if(dgps > 0)      report_msg("%% DGPS is ON\n");
					else if(dgps < 0) report_msg("%% NO DGPS INFORMATION\n");
					else              report_msg("%% DGPS is OFF\n");
				}
				set_flag(prev->flag_list, DGPS_CODE, 0, dgps); 
				break;
			default:
				/* Nothing to do */
				break;
			}
		}
		f++;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 -Next Navigation Time:

	 Reads in the data file until a line containing navigation time information
	 is met. A navigation time line is defined by the [[update_flags]] function.
	 On output, the data file pointer is located just after the next navigation
	 time line, and the navigation structure has been updated with the data from
	 this line.

	 INPUT : NAV_FILES_TYPE *fps;       pointer to file pointers
	         SCAN_NAV_TYPE *scan;       pointer to scan_nav structure
           double last;               must contain previous time
					 int year_base;             year base used to calculate decimal day
					 ULONG *nping;              pointer to current ping number
					 int verbose;               if non-zero, print search evolution
					                            output. 
	 
	 RETURN: negative on error
           navigation line flag on success
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int next_nav_time(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *scan, double last, 
									int year_base, ULONG *nping, int verbose, ULONG bits)  
#else
int next_nav_time()
#endif
{

	char func[]="next_nav_time";

	double inc;
	int flag, error, done;
	ULONG n;
	char msg[200], str[100];
	FILE_NAME_TYPE path, name;
	
	/* Initializations */
	inc = -1.0;

	/* Message */
	if(verbose){
		if(last < ADJ_BADFLOAT)
			yd_to_ymdhms_str(str, last, year_base);
		else
			sprintf(str, "BAD TIME");
		split_file_path((char *) scan->fi.name, (char *) path, (char *) name);
		sprintf(msg, "\n%%%%%% FILE: %s  TIME: %s", name, str);
		report_msg(msg);
		report_msg("\n%%% Reading until next navigation time line\n");
	}

	/* Loop through the lines */
	n = *nping;
	done = 0;
	while(!done){
		
		/* Read next navigation ping */
		flag = next_nav_ping(fps->lst, &(scan->fi), &(scan->nav), last, 
												 year_base, inc, bits); 
		if(flag < 0){
			error = flag;
			if(error != EOF)
				error_msg(func, "While reading until first time data");
			return(error);
		}
		n++;
		
		/* Message */
		if(verbose)
			short_info(&n, -ULONG_VALUE_CODE);

		/* Update the flags */
		update_flags((SCAN_NAV_TYPE *) NULL, scan, flag);
		
		/* Update time */
		if(get_flag(scan->flag_list, NAV_TIME_FLAG, 0))
			done = 1;
		else
			last = scan->nav.yd;
		
	}

	/* Set current current ping number */
	*nping = n;

	return(flag);

}
	
/* ------------------------------------------------------------------
	 -Next Not Time:

	 This function reads navigation lines until a line not containing navigation
	 time is met. On output, the data file is positionned just before the first
	 non time navigation line, and the navigation structure has been updated
	 with the last navigation time line.

	 INPUT : NAV_FILES_TYPE *fps;       pointer to file pointers
	         SCAN_NAV_TYPE  *scan;      pointer to scan_nav structure
           double last;               must contain previous time
					 int year_base;             year base used to calculate decimal day
					 ULONG *nping;              pointer to current ping number
					 int verbose;               if non-zero, print search evolution
	 
	 RETURN: negative on error
           last navigation line flag on success
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int next_not_time(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *scan, double last, 
									int year_base, ULONG *nping, int verbose, ULONG bits)
#else
int next_not_time()
#endif
{

	char func[]="next_not_time";

	DATA_FILE_INFO_TYPE fi_tmp;
	NAV_TYPE nav_tmp;
	int flag_tmp;
	int flag, error, done;
  ULONG n;
	char msg[200], str[100];
	FILE_NAME_TYPE path, name;
	double inc;

	/* Initializations: */
	inc = -1.0;

	/* Message */
	if(verbose){
		if(last < ADJ_BADFLOAT)
			yd_to_ymdhms_str(str, last, year_base);
		else
			sprintf(str, "BAD TIME");
		split_file_path((char *) scan->fi.name, (char *) path, (char *) name);
		sprintf(msg, "\n%%%%%% FILE: %s  TIME: %s", name, str);
		report_msg(msg);
		report_msg("\n%%% Reading until end of navigation time lines\n");
	}
		
	/* Initializations */
	memcpy((void *) &fi_tmp, (void *) &(scan->fi), sizeof(DATA_FILE_INFO_TYPE));
	
	/* Loop through the lines */
	n = *nping;
	done = 0;
	while(!done){
		
		/* Read next valid navigation ping */
		flag_tmp = next_nav_ping(fps->lst, &fi_tmp, &nav_tmp, last, year_base,
														 inc, bits); 
		if(flag_tmp < 0){
			error = flag_tmp;
			if(error != EOF)
				error_msg(func, "While reading until first non time data");
			return(error);
		}

		/* Update the flags */
		update_flags((SCAN_NAV_TYPE *) NULL, scan, flag_tmp);

		/* Check if line contains time information */
		if(get_flag(scan->flag_list, NAV_TIME_FLAG, 0)){
			/* Backup current state */
			memcpy((void *) &(scan->fi), (void *) &fi_tmp,
						 sizeof(DATA_FILE_INFO_TYPE)); 
			memcpy((void *) &(scan->nav), (void *) &nav_tmp, sizeof(NAV_LINES_TYPE));
			flag = flag_tmp;
			last = scan->nav.yd;
			/* Update number of pings */
			n++;
			/* Message */
			if(verbose)
				short_info(&n, -ULONG_VALUE_CODE);
		}
		else if((flag_tmp != BAD_LINE_CODE) && (flag_tmp != EMPTY_LINE_CODE))
			done = 1;

	}

	/* Restore file pointer to beginning of current line */
	if(strcmp((char *) scan->fi.name, (char *) fi_tmp.name)){
		/* File has changed */
		fclose(fi_tmp.fp);
		scan->fi.fp = fopen((char *) scan->fi.name, scan->fi.mode);
		if(scan->fi.fp == NULL){
			error_msg(func, "Could not reopen data file");
			return(READ_ERROR);
		}
	}
	fseek(fps->lst, (long) scan->fi.list_pos, SEEK_SET);
	fseek(scan->fi.fp, (long) scan->fi.data_pos, SEEK_SET);

	/* Update current time */
	*nping = n;
	
	return(flag);

}

/* ------------------------------------------------------------------
	 -Get Time Increment:

	 This function reads navigation lines to determine a time increment between
	 time navigation information. On output, the data file is positionned at
	 the beginning of the first non-time navigation line, and [[nav]] contains
	 data from the last navigation time line. [[yd]] is updated to the time of
	 this line.

	 NOTE: This function should be called when a line containing time
	       information has been read.

	 INPUT : FILE *fp;                  pointer to list of files
	         DATA_FILE_INFO_TYPE *fi;   pointer to data files information 
					                            structure
					 SCAN_NAV_TYPE *scan;       pointer to navigation scan_nav structure
					 double last;               must contain previous time
					 int year_base;             year base used to calculate decimal day
					 ULONG *nping;              pointer to current ping number
					 int verbose;               if non-zero, print search evolution
					 double *yd                 navigation time of previous line on
					                            output. 
					 double *inc;               time increment in seconds
	 
	 RETURN: negative on error
           last navigation line flag on success
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int get_time_inc(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *scan, double last, 
								 int year_base, ULONG *nping, int verbose, double *inc,
								 ULONG bits) 
#else
int get_time_inc()
#endif
{

	char func[]="get_time_inc";

	SCAN_NAV_TYPE scan_tmp;

	int flag, flag_tmp, error, done;
	ULONG n;
	double last_tmp;
	char msg[200], str[100];

	/* Message */
	if(verbose)
		report_msg("\n%%% Updating time increment\n");
	
	done = 0;
	while(!done){

		/* Read until end of time information lines */
		flag = next_not_time(fps, scan, last, year_base, nping, verbose, bits);
		if(flag < 0){
			error = flag;
			if(error != EOF)
				error_msg(func, "While searching for end of time data");
			return(error);
		}

		/* Backup current state */
		memcpy((void *) &scan_tmp, (void *) scan, sizeof(SCAN_NAV_TYPE));
		last_tmp = scan->nav.yd;
		n = *nping;

		/* Search for next navigation time line from current position */
		flag_tmp = next_nav_time(fps, &scan_tmp, last_tmp, year_base, &n, 
														 verbose, bits);
 
		/* Calculate time increment */
		if((last_tmp < ADJ_BADFLOAT) && (scan_tmp.nav.yd < ADJ_BADFLOAT)
			 && (n - *nping) > 0)
			*inc = ((scan_tmp.nav.yd - last_tmp)*86400.0) / ((double) (n - *nping));
		else
			error_msg(func, "Undefined time increment");
		
		/* Loop exit */
		if(*inc > 0)
			done = 1;
		else if(verbose){
			sprintf(msg, "\n%%%%%% TIME INCREMENT: %8.4f", *inc);
			report_msg(msg);
			if(last_tmp < ADJ_BADFLOAT)
				yd_to_ymdhms_str(str, last_tmp, year_base);
			else
				sprintf(str, "BAD TIME");
			sprintf(msg, "\n%%%%%% From : %s", str);
			report_msg(msg);
			if(scan_tmp.nav.yd < ADJ_BADFLOAT)
				yd_to_ymdhms_str(str, scan_tmp.nav.yd, year_base);
			else
				sprintf(str, "BAD TIME");
			sprintf(msg, "\n%%%%%% To   : %s", str);
			report_msg(msg);
			if((n - *nping) > 0)
				sprintf(str, "%lu", (n - *nping));
			else
				sprintf(str, "BAD NUMBER");
			sprintf(msg, "\n%%%%%% lines: %s\n", str);
			report_msg(msg);
			report_msg("\n%%% Bad increment time. Skipping ... \n");
		}
	}

	/* Restore file position to beginning of non-time lines */
	if(strcmp((char *) scan->fi.name, (char *) scan_tmp.fi.name)){
		/* File has changed */
		fclose(scan_tmp.fi.fp);
		scan->fi.fp = fopen((char *) scan->fi.name, scan->fi.mode);
		if(scan->fi.fp == NULL){
			error_msg(func, "Could not reopen data file");
			return(READ_ERROR);
		}
	}
	fseek(fps->lst, (long) scan->fi.list_pos, SEEK_SET);
	fseek(scan->fi.fp, (long) scan->fi.data_pos, SEEK_SET);
	
	/* Message */
	if(verbose){
		sprintf(msg, "\n%%%%%% TIME INCREMENT: %8.4f", *inc);
		report_msg(msg);
		if(last_tmp < ADJ_BADFLOAT)
			yd_to_ymdhms_str(str, last_tmp, year_base);
		else
			sprintf(str, "BAD TIME");
		sprintf(msg, "\n%%%%%% From : %s", str);
		report_msg(msg);
		if(scan_tmp.nav.yd < ADJ_BADFLOAT)
			yd_to_ymdhms_str(str, scan_tmp.nav.yd, year_base);
		else
			sprintf(str, "BAD TIME");
		sprintf(msg, "\n%%%%%% To   : %s", str);
		report_msg(msg);
		if((n - *nping) > 0)
			sprintf(str, "%lu", (n - *nping));
		else
			sprintf(str, "BAD NUMBER");
		sprintf(msg, "\n%%%%%% lines: %s\n", str);
		report_msg(msg);
	}

	return(flag);

}

/* ------------------------------------------------------------------
	 --Fill Ensemble Structure:

	 This function depends very much on the scan programme. It should therefore
	 be defined separately.
	 ------------------------------------------------------------------ */

/* ------------------------------------------------------------------
	 --Skip Over Navigation Lines:

	 This function reads navigation data until a line containing valid time
	 information is read. It then skip all next lines until [[SKIP_NEXT_LINES]]
	 navigation time lines have been read.

	 This is usefull when navigation goes down for a couple of seconds. At
	 stratup, it usually need some time for the instrument to output correct
	 data. 
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int skip_lines(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *scan, ULONG *nping, 
							 int year_base, ULONG bits)
#else
int skip_lines()
#endif
{

	char func[]="skip_lines";

	FILE_NAME_TYPE path, name;
	char str[100], msg[200];
	int i, error, flag;
	double last;

	if(skip_next_lines < 0)
		return(get_flag(scan->flag_list, NAV_LINE_FLAG, 0));

	/* Calculate current statistics */
	final_stat(fps->sta, scan->data_stat_list, scan->nav.yd, year_base);

	/* Skip over next lines */
	report_msg("\n%%% Skipping over next navigation lines...\n");
	last = scan->nav.yd;
	for(i=0; i<skip_next_lines; i++){
		flag = next_nav_time(fps, scan, scan->nav.yd, year_base, nping, 0, 
												 bits);
		if(flag < 0){
			error = flag;
			if(error != EOF)
				error_msg(func, "While skipping over navigation lines");
			return(error);
		}
	}
	/* Restore old value of navigation time */
	scan->nav.yd = last;

	/* Read until next navigation time */
	report_msg("\n%%% Getting next valid time information... \n");
	flag = next_nav_time(fps, scan, scan->nav.yd, year_base, nping, 0, bits);
	if(flag < 0){
		error = flag;
		if(error != EOF)
			error_msg(func, "While reading until next time line");
		return(error);
	}
	
	/* Message */
	yd_to_ymdhms_str(str, scan->nav.yd, year_base);
	split_file_path((char *) scan->fi.name, (char *) path, (char *) name);
	sprintf(msg, "\n%%%%%% FILE: %s  NEW TIME: %s \n", name, str);
	report_msg(msg);
	
	return(flag);

}

/* ------------------------------------------------------------------
	 --Process Data:

	 This function controls the whole processing actions, according to the flag
	 values. 

	 Because this function depends very much on the scan programme. It should be
	 defined separately, together with the main programme.
	 ------------------------------------------------------------------ */

/* ##################################################################
	 -Output Functions:
	 ################################################################## */

/* ------------------------------------------------------------------
	 --Header for Data Stat Log Information: 

	 This function is called from the initialization function.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int data_stat_header(FILE *fp, SCAN_NAV_TYPE *scan)
#else
int data_stat_header(fp, scan)
ULONG bits;
SCAN_NBR_PING_TYPE *scan;
#endif
{

	int n = 0;

	/* Beginning of header */
	fprintf(fp, "%% *** SCAN_NAV: Data Description ****\n");
	
	/* Header for ensemble location */
	fprintf(fp, "%% %3d : ensemble number\n", 1);
	fprintf(fp, "%% %3d : stop time (decimal day in %4d)\n", 
					2, year_base);
	fprintf(fp, "%% %3d : stop latitude\n", 3);
	fprintf(fp, "%% %3d : stop longitude\n", 4);

	/* Unistat variables information */
	n = fprintf_stat_header(fp, scan->data_stat_list, 5);
	n = fprintf_flag_header(fp, scan->flag_list, n);

	/* End of header */
	fprintf(fp, "%% ***********************************\n");

	return(0);

}

/* ------------------------------------------------------------------
	 --Write Data Stat:

	 This function reports data statistics in the log file. It uses data from
	 the NAV_TYPE structure and the UNISTAT_LIST_TYPE list. Since data
	 statistics is written for each ensemble, it is assumed that ensemble out
	 data has already been calculated. This is important because data statistics
	 is most probably wrong when an ensemble is uncomplete.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int write_data_stat(NAV_FILES_TYPE *fps, SCAN_NAV_LINE_TYPE *scan, 
										UNISTAT_LIST_TYPE *u_list, FLAG_LIST_TYPE *f_list, 
										int year_base)
#else
int write_data_stat()
#endif
{


	UNISTAT_LIST_TYPE *uni;
	FLAG_LIST_TYPE *f;
	double data;
	DOUBLE blog;
	UBYTE  ascii_log;

	int i, j, len, good_stat;
	char str[500];

	/* Initializations */
	good_stat = 0;
	ascii_log = (scan_bits & ASCII_LOG_BIT) ? 1 : 0;

	/* Print location of ensemble */
	if(ascii_log)
		fprintf(fps->log, "%6hu ", scan->number);
	blog = (DOUBLE) scan->number;
	fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);
	if(scan->time.stop < ADJ_BADFLOAT){
		sprintf(str, "%14.8f ", scan->time.stop);
		blog = (DOUBLE) scan->time.stop;
	}
	else{
		sprintf(str, "%s", "           NaN ");
		blog = BADDOUBLE;
	}
	if(ascii_log)
		fprintf(fps->log, "%s", str);
	fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);	
	if(scan->pos.stop.lat < ADJ_BADFLOAT){
		sprintf(str, "%14.8f ", scan->pos.stop.lat);
		blog = (DOUBLE) scan->pos.stop.lat;
	}
	else{
		sprintf(str, "%s", "           NaN ");
		blog = BADDOUBLE;
	}
	if(ascii_log)
		fprintf(fps->log, "%s", str);
	fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);	
	if(scan->pos.stop.lon < ADJ_BADFLOAT){
		sprintf(str, "%14.8f ", scan->pos.stop.lon);
		blog = (DOUBLE) scan->pos.stop.lon;
	}
	else{
		sprintf(str, "           NaN ");
		blog = BADDOUBLE;
	}
	if(ascii_log)
		fprintf(fps->log, "%s", str);
	fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);	

	/* Determine good statistics */
	good_stat = 
		(scan->time.start < ADJ_BADFLOAT) 
		&& (scan->time.stop < ADJ_BADFLOAT)
		&& (scan->pos.start.lat < ADJ_BADFLOAT)
		&& (scan->pos.start.lon < ADJ_BADFLOAT)
		&& (scan->pos.stop.lat < ADJ_BADFLOAT)
		&& (scan->pos.stop.lon < ADJ_BADFLOAT);
		 
	/* Print data being averaged */
	uni = u_list;
	while(uni->name != NULL){
		/* Special transformations */
		switch(uni->code){
		case NAV_COURSE_FROM_POS_CODE:
			data = to360(*(uni->stat->sum));
			break;
		case NAV_HEADING_CODE:
			data = to360(*(uni->stat->sum));
			break; 
		case NAV_SHIP_COURSE_CODE:
			data = to360(*(uni->stat->sum));
			break;
		default:
			data = *(uni->stat->sum);
			break;
		}
		/* Write data */
		if((data < ADJ_BADFLOAT) && good_stat){
			sprintf(str, uni->format, data);
			blog = (DOUBLE) data;
		}
		else{
			sprintf(str, uni->format, 1.0);
			len = strlen(str);
			strcpy(str, "");
			for(i=0; i<len-3; i++)
				strcat(str, " ");
			strcat(str, "NaN");
			blog = BADDOUBLE;
		}
		/* Column separations */
		strcat(str, "  ");
		/* Write data */
		if(ascii_log)
			fprintf(fps->log, "%s", str);
		fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);	
		/* update pointer */
		uni++;
	}

	/* Print flag status */
	f = f_list;
	while(f->name != NULL){
		/* Print flag status */
		if(f->code >= 0){
			for(j=0; j<(f->size); j++){
				if(*(f->flag + j) < BADBYTE){
					sprintf(str, "%3d", *(f->flag + j));
					blog = (DOUBLE) *(f->flag + j);
				}
				else{
					sprintf(str, "NaN");
					blog = BADDOUBLE;
				}
				/* Column separations */
				strcat(str, "  ");
				/* Write data */
				if(ascii_log)
					fprintf(fps->log, "%s", str);
				fwrite((void *) &blog, sizeof(DOUBLE), 1, fps->bin);	
			}
		}
		/* update pointer */
		f++;
	}
	/* End of line */
	if(ascii_log)
		fprintf(fps->log, "\n");

	return(0);

}

/* ------------------------------------------------------------------
	--Ensemble Information:

	Each time a message from checks is reported, a header giving information
	about the current ensemble is output in order to be able to track it back in
	the data file, or to unselect it from the list of ensembles to scan and
	load. This function uses [[report_msg]] so that messages go to screen and to
	the log file.
	------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int ens_info(SCAN_NAV_TYPE *scan)
#else
int ens_info(scan) 
#endif
{

	char str[100], msg[200];
	FILE_NAME_TYPE path, name;
	int flag;

	/* Get the navigation line flag */
	flag = get_flag(scan->flag_list, NAV_LINE_FLAG, 0);

	/* Print header */
	sprintf(msg, "\n%%%% WARNING:\n");
	report_msg(msg);
	split_file_path((char *) scan->fi.name, (char *) path, (char *) name);
	sprintf(msg, "%%%%   data_file_name: %s\n", name);
	report_msg(msg);
	sprintf(msg, "%%%%   address       : %8lXh\n", scan->fi.data_pos);
	report_msg(msg);
	sprintf(msg, "%%%%   ensemble      : %hu\n",   scan->nav.number);
	report_msg(msg);


	/* Build a part of the line */
	switch(flag){
	case GGA_LINE_CODE:
		yd_to_ymdhms_str(str, scan->nav.yd, year_base);
		sprintf(msg, "%%%%   GGA: time: %s\n", str);
		break;
	case ZDA_LINE_CODE:
		yd_to_ymdhms_str(str, scan->nav.yd, year_base);
		sprintf(msg, "%%%%   ZDA: time: %s\n", str);
		break;
	case HDT_LINE_CODE:
		sprintf(msg, "%%%%   HDT: heading: %6.2f\n", scan->nav.heading);
		break;
	case PRDID_LINE_CODE:
		sprintf(msg, 
						"%%%%   PRDID: heading: %6.2f - pitch: %6.2f - roll: %6.2f\n", 
						scan->nav.heading, scan->nav.pitch, scan->nav.roll);
		break;
	case VTG_LINE_CODE:
		sprintf(msg, "%%%%   VTG: course: %6.2f - speed: %6.2f\n", 
						scan->nav.course, scan->nav.speed);
		break;
	case RMC_LINE_CODE:
		yd_to_ymdhms_str(str, scan->nav.yd, year_base);
		sprintf(msg, "%%%%   RMC: time: %s\n", str);
		break;
	case GLL_LINE_CODE:
		sprintf(msg, "%%%%   GLL: lon: %10.4f - lat: %10.4f\n", 
            scan->nav.pos.lon, scan->nav.pos.lon);
		break;
	default:
		strcpy(msg, "");
		break;
	}
	report_msg(msg);

	return(0);
}


/* ##################################################################
	 -Backup Functions:
	 ################################################################## */

/* ------------------------------------------------------------------
	 --Backup Data:
	 
	 If [[flag]] is negative, backup assumes to be called from the loop outside
	 time ranges, and a minimal backup is carried out. Else, it should
	 correspond to the value of the current navigation line flag.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int backup_data(SCAN_NAV_TYPE *prev, SCAN_NAV_TYPE *curr, int flag)
#else
int backup_data(prev, curr, flag)
#endif
{

	/* ---------------------------------
		 Minimal backup 
		 --------------------------------- */
	memcpy((void *) &(prev->fi), (void *) &(curr->fi), 
				 sizeof(DATA_FILE_INFO_TYPE));
	full_copy_flag_list(prev->flag_list, curr->flag_list, BADINT);
	prev->nav.inc = curr->nav.inc;

	if(flag < 0)
		return(0);

	/* ---------------------------------
		 Normal backup
		 --------------------------------- */

	switch(flag){
	case GGA_LINE_CODE:
		prev->nav.yd  = curr->nav.yd;
		prev->nav.pos.lat = curr->nav.pos.lat;
		prev->nav.pos.lon = curr->nav.pos.lon;
		prev->nav.qual = curr->nav.qual;
		prev->nav.nsat = curr->nav.nsat;
		prev->nav.hdop = curr->nav.hdop;
		prev->nav.height = curr->nav.height;
		break;
	case ZDA_LINE_CODE:
		prev->nav.yd = curr->nav.yd;
		break;
	case HDT_LINE_CODE:
		prev->nav.heading = curr->nav.heading;
		break;
	case PRDID_LINE_CODE:
		prev->nav.heading = curr->nav.heading;
		prev->nav.pitch = curr->nav.pitch;
		prev->nav.roll = curr->nav.roll;
		break;
	case TRANSECT_LINE_CODE:
		prev->nav.number = curr->nav.number;
		break;
	case VTG_LINE_CODE:
		prev->nav.course = curr->nav.course;
		prev->nav.speed = curr->nav.speed;
		break;
	case RMC_LINE_CODE:
		prev->nav.yd  = curr->nav.yd;
		prev->nav.pos.lat = curr->nav.pos.lat;
		prev->nav.pos.lon = curr->nav.pos.lon;
		prev->nav.course = curr->nav.course;
		prev->nav.speed = curr->nav.speed;
    break;
	case GLL_LINE_CODE:
		prev->nav.pos.lat = curr->nav.pos.lat;
		prev->nav.pos.lon = curr->nav.pos.lon;
    break;
	default:
		/* Nothing to do */
		break;
	}

	return(0);

}

#endif /* nav__C_code_already_included */



