/**---------------------------------------------------------------------------
 ** 
 ** scantnav.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/30 15:57:23
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/07/30 17:13:36
 ** Update Count    : 10
 ** Directory       : /pcdata1/jaccard/codas3c/gfi/src/apps/nav/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    Must be compiled with -DSCAN_NAV to generate a multiple choice
 **    scan_nav file.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

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

	-Introduction:

	Programme [[scan_nav]] parses through navigation files and generates the
	following files:

	   +log       : information about scanning state, and output of data being
		              averaged for each ensemble

		 +statistics: final statistics of averaged data

		 +output    : navigation information required for further scanning and
		              fixing of ADCP raw data

   ##################################################################

	 -Header Files:
	 */

#ifndef scantnav_C_code_already_included
#define scantnav_C_code_already_included

#include "nav_.h"
#include "scantnav.h"

/*
  Module with higher level functions parsing navigation files
*/
#include "nav_.c"

#define DEBUG 0

/* ##################################################################
	 -Initialize Loop:

	 This function is called each time the loop inside time ranges is entered.
	 Since it very much depending on how the data are used by the main
	 programme, it must be defined together in the main file.
	 ################################################################## */

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

	/*
	BYTE tmp;
	*/
	/* Keep current value of GET_TIME_INC_FLAG */
	/*
	tmp = get_flag(curr->flag_list, GET_TIME_INC_FLAG, 0);
	*/

	/* Put all flags to zero */
	zero_flag_list(prev->flag_list, BADINT);
	zero_flag_list(curr->flag_list, BADINT);

	/* Put back value of GET_TIME_INC_FLAG in order to avoid searching for the
		 time increment each time one eneters the loop */
	/*
	set_flag(prev->flag_list, GET_TIME_INC_FLAG, 0, tmp); 
	*/

	/* The next lines are to force GPS and DGPS log when reading first GPS or
		 DGPS navigation lines */
	set_flag(prev->flag_list, GPS_CODE, 0, -1); 
	set_flag(prev->flag_list, DGPS_CODE, 0, -1);
	set_flag(curr->flag_list, GPS_CODE, 0, -1); 
	set_flag(curr->flag_list, DGPS_CODE, 0, -1);

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

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

	/* Initialize unistat lists */
	zero_unistat_list(curr->data_stat_list, BADINT);
	zero_unistat_list(prev->data_stat_list, BADINT);
	zero_unistat_list(curr->scan_stat_list, BADINT);
	zero_unistat_list(prev->scan_stat_list, BADINT);
	zero_unistat_list(curr->data_stat_list0, BADINT);
	zero_unistat_list(prev->data_stat_list0, BADINT);
	zero_unistat_list(curr->scan_stat_list0, BADINT);
	zero_unistat_list(prev->scan_stat_list0, BADINT);
	
	
	return(0);
}

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

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

	UNISTAT_LIST_TYPE *uni;

	curr->scan.number = curr->nav.number;

	/* Correct transect time */
	if((curr->nav0.yd < ADJ_BADFLOAT) && (curr->nav.yd < ADJ_BADFLOAT))
		curr->scan.time.stop =
			(curr->nav0.yd + curr->nav.yd)/2.0;
	else
		curr->scan.time.stop = BADDOUBLE;

	/* Correct transect position */
	if((curr->nav0.pos.lat < ADJ_BADFLOAT) && (curr->nav.pos.lat < ADJ_BADFLOAT))
		curr->scan.pos.stop.lat =
			(curr->nav0.pos.lat + curr->nav.pos.lat)/2.0;
	else
		curr->scan.pos.stop.lat = BADDOUBLE;
	if((curr->nav0.pos.lon < ADJ_BADFLOAT) && (curr->nav.pos.lon < ADJ_BADFLOAT))
		curr->scan.pos.stop.lon = 
			(curr->nav0.pos.lon + curr->nav.pos.lon)/2.0;
	else
		curr->scan.pos.stop.lon = BADDOUBLE;
	
	/* Update rest of ensemble structure */
	curr->scan.time.start    = prev->scan.time.stop;
	curr->scan.pos.start.lat = prev->scan.pos.stop.lat;
	curr->scan.pos.start.lon = prev->scan.pos.stop.lon;

	uni = curr->scan_stat_list0;
	while(uni->name != NULL){
		switch(uni->code){
		case NAV_HEADING_CODE:
			curr->scan.prh.heading.mean = *(uni->stat->sum);
			curr->scan.prh.heading.sdev = sqrt(*(uni->stat->sumsq));
			curr->scan.prh.heading.npts = *(uni->stat->npts);
			break;
		case NAV_PITCH_CODE:
			curr->scan.prh.pitch.mean = *(uni->stat->sum);
			curr->scan.prh.pitch.sdev = sqrt(*(uni->stat->sumsq));
			curr->scan.prh.pitch.npts = *(uni->stat->npts);
			break;
		case NAV_ROLL_CODE:
			curr->scan.prh.roll.mean = *(uni->stat->sum);
			curr->scan.prh.roll.sdev = sqrt(*(uni->stat->sumsq));
			curr->scan.prh.roll.npts = *(uni->stat->npts);
			break;
		case NAV_SHIP_COURSE_CODE:
			curr->scan.spd.course.mean = *(uni->stat->sum);
			curr->scan.spd.course.sdev = sqrt(*(uni->stat->sumsq));
			curr->scan.spd.course.npts = *(uni->stat->npts);
			break;
		case NAV_SHIP_SPEED_CODE:
			curr->scan.spd.speed.mean = *(uni->stat->sum);
			curr->scan.spd.speed.sdev = sqrt(*(uni->stat->sumsq));
			curr->scan.spd.speed.npts = *(uni->stat->npts);
			break;
		default:
			/* Nothing to do */
			break;
		}
		uni++;
	}

	return(0);
}

/* ##################################################################
	 -Get Next Valid Navigation Line:
	 ################################################################## */

#if PROTOTYPE_ALLOWED
int next_valid_nav_ping(NAV_FILES_TYPE *fps, SCAN_NAV_TYPE *prev, 
												SCAN_NAV_TYPE *curr, ULONG *nping, double yd)
#else
int next_valid_nav_ping()
#endif
{

	char func[]="next_valid_nav_ping";
	
	int flag, error;
	
	/* Initializations */
	error = 0;
	flag = BAD_LINE_CODE;

	/* Read until a valid navigation line is met */
	while((flag > 0) && ((flag == BAD_LINE_CODE) 
											 || (flag == EMPTY_LINE_CODE)
											 || (flag == IGNORED_LINE_CODE)))
		flag = next_nav_ping(fps->lst, &(curr->fi), &(curr->nav),	yd, 
															 year_base, -1, nav_lines_bits); 
	if(flag < 0){
		error = flag;
		if(error != EOF)
			error_msg(func, "While reading next navigation ping [inside]");
		return(error);
	}
		
	if(!error){
		*nping += 1;
		short_info(nping, -ULONG_VALUE_CODE);
			
		report_file_change(prev->fi.name, curr->fi.name);
	}

	return(flag);

}

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

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

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

	int error;

	/* Keep a copy of pre-transect navigation and stat data */
	if(flag == TRANSECT_LINE_CODE){
		memcpy((void *) &(curr->nav0), (void *) &(curr->nav), sizeof(NAV_TYPE));
		full_copy_unistat_list(curr->data_stat_list0, prev->data_stat_list, 
													 BADINT);
	}

	/* Update and check flags */
	update_flags(prev, curr, flag);
	error = check_flags(prev, curr);
	if(error)
		return(error);

	/* Update statistics */
	update_data_stat(prev->data_stat_list, prev, curr, 0);
	update_data_stat(curr->data_stat_list, prev, curr, 0);
	update_scan_nav_stat(curr->scan_stat_list, curr);
	
	/* Things to do when a transect line is read */
	if(flag == TRANSECT_LINE_CODE){
		/* Copy of scan statistics */
		full_copy_unistat_list(curr->scan_stat_list0, curr->scan_stat_list,
													 BADINT);
		full_copy_unistat_list(prev->scan_stat_list, curr->scan_stat_list,
													 BADINT);
		/* Reset scan statistics for next ensemble */
		zero_unistat_list(curr->scan_stat_list, BADINT);
		/* Copy of data statistics */
		full_copy_unistat_list(prev->data_stat_list0, prev->data_stat_list,
													 BADINT);
		/* Reset data statistics for next ensemble */
		zero_unistat_list(prev->data_stat_list, BADINT);
	}

	/* Things to do for TRANSECT corrections */
	if(get_flag(curr->flag_list, APPLY_TRANSECT_CORRECTIONS_FLAG, 0)){
#if (DEBUG == 1)
    report_msg("\nDEBUG: Applying TRANSECT corrections\n");
#endif
		/* Write scan data */
		calculate_stat(curr->scan_stat_list0);
		fill_scan_nav_transect(prev, curr);
		write_scan_nav_line(fps->out, &(curr->scan), year_base);
		/* Update special flags */
		set_flag(curr->flag_list, ENSEMBLE_DONE_FLAG, 0, 1);
		/* Write data stat */
		update_data_stat(prev->data_stat_list0, prev, curr, -1);
		calculate_stat(prev->data_stat_list0);
		write_data_stat(fps, &(curr->scan), prev->data_stat_list0, 
										curr->flag_list, year_base);
		/* Backup scan data */
		memcpy((void *) &(prev->scan), (void *) &(curr->scan),
					 sizeof(SCAN_NAV_LINE_TYPE));
		/* Reset scan data structure */
		init_scan_nav_line(&(curr->scan), -1);
		/* Reset statistics */
		zero_unistat_list(curr->scan_stat_list0, BADINT);
		zero_unistat_list(prev->data_stat_list0, BADINT);
	}
		
	return(0);

}

/* ##################################################################
	 -MAIN:

	 There are two variables containing ping information, [[curr]] and [[prev]].
	 For these variables, the unistat lists are not copies of previous ping
	 values: 

	    prev.scan_stat_list:  calculated ensemble statistics for previous
			                      TRANSECT line

	    curr.scan_stat_list:  updated/calculated ensemble statistics for current
			                      TRANSECT line

			prev.data_stat_list: updated and calculated data check statistics
			                     between two TRANSECT lines (approximately)
	 
			curr.data_stat_list: updated data check statistics over a whole time
			                     range 
	 ################################################################## */

#ifndef SCAN_NAV

#if PROTOTYPE_ALLOWED
void do_it(FILE *fp_cnt)
#else
void do_it(fp_cnt)
#endif

#else

#if PROTOTYPE_ALLOWED
void scan_nav_transect(FILE *fp_cnt)
#else
void scan_nav_transect(fp_cnt)
#endif

#endif
{

	char func[]="do_it";

	NAV_FILES_TYPE fps;
	SCAN_NAV_TYPE prev, curr;

	YMDHMS_TIME_TYPE start_time, stop_time;
	double start_day, stop_day, yd;

	char str[200], msg[200];
	FILE_NAME_TYPE path, name;
	int error=0, flag, done;

	ULONG nping;

	/* First Initializations */
	nping = 0;
	init_options();

	/* Get the parameters */
	if (get_parameters(fp_cnt, scan_params, NULL)) exit(-1);
	print_parameters(stdout, scan_params, NULL, "\n");

	/* Read and process all options */
	if (execute_options(fp_cnt, scan_options, ECHO)<=0){
		error_msg(func, "while reading scan options.");
		exit(-1);
	}

	/* Convert first day and set year_base */
	if(str_to_ymdhms(&first_day, first_day_str)){
		error_msg(func, "Invalid time for first day");
		goto on_error;
	}
	year_base = (int) first_day.year;
	yd = year_day(&first_day, year_base);

	/* Memory and variables initialization */
	if(init_scan(&fps, &prev, &curr)){
		error_msg(func, "While initializing scan");
		goto on_error;
	}

	/* Get first time from navigation file */
	report_msg("\n%%% Getting first time information... \n");
	flag = next_nav_time(&fps, &curr, yd, year_base, &nping, 1, 
											 nav_lines_bits);
	if(flag < 0){
		error = flag;
		if(error != EOF)
			error_msg(func, "While reading until first time data");
		goto on_error;
	}

	/* Message */
	yd_to_ymdhms_str(str, curr.nav.yd, year_base);
	split_file_path((char *) curr.fi.name, (char *) path, (char *) name);
	sprintf(msg, "\n%%%%%% FILE: %s  FIRST TIME: %s \n", name, str);
	report_msg(msg);

	/* ------------------------------------------------------------------ 
		 Loop through time ranges 
		 ------------------------------------------------------------------ */
	while(get_time_range(fp_cnt, &start_time, &stop_time)==1){
	
		/* Get decimal days of time range */
		start_day = year_day(&start_time, year_base);
		stop_day  = year_day(&stop_time,  year_base);

		/* Message */
		time_range_to_str(str, &start_time, &stop_time);
		sprintf(msg, "\n%%%%%% TIME RANGE: %s\n", str);
		report_msg(msg);
		yd_to_ymdhms_str(str, curr.nav.yd, year_base);
		split_file_path((char *) curr.fi.name, (char *) path, (char *) name);
		sprintf(msg, "\n%%%%%% FILE: %s  TIME: %s  Outside time range ...\n", 
						name, str);
		report_msg(msg);

		/* Get year day of current navigation line */
		yd = curr.nav.yd;
		
		/* ------------------------------------------------------------------
			 Loop outside range 
			 ------------------------------------------------------------------ */
		while((yd < start_day) && !error){
			
			backup_data(&prev, &curr, -1);

			flag = next_valid_nav_ping(&fps, &prev, &curr, &nping, yd);
			if(flag < 0){
				error = flag;
				if(error != EOF)
					error_msg(func, "While reading next navigation ping [inside]");
				goto on_error;
			}
			yd = curr.nav.yd;

		}
		/* ------------------------------------------------------------------ */
			
		/* Message */
		yd_to_ymdhms_str(str, curr.nav.yd, year_base);
		split_file_path((char *) curr.fi.name, (char *) path, (char *) name);
		sprintf(msg, "\n%%%%%% FILE: %s  TIME: %s  Inside time range ...\n",
						name, str);
		report_msg(msg);
		
		init_loop_inside_range(&prev, &curr);

		/* ------------------------------------------------------------------
			 Loop inside time range 
			 ------------------------------------------------------------------ */
		while((yd <= stop_day) && (!error)){
			
			/* Loop until good processing */
			done = 0;
			while(!done){
				error = process_data_transect(&fps, &prev, &curr, flag);
				/* Loop exit flag */
				done = (!error || (error == EOF)) ? 1 : 0;
				/* Check for skipping lines */
				if(error == SKIP_NEXT_LINES){
					flag = skip_lines(&fps, &curr, &nping, year_base, nav_lines_bits);
					error = (flag < 0) ? flag : 0;
					/* Re-initialize data */
					if(skip_next_lines >= 0)
						init_loop_inside_range(&prev, &curr);
				}
				/* Process error */
				if(error){
					if(error != EOF)
						error_msg(func, "While processing/skipping navigation lines");
					goto on_error;
				}
			}

			backup_data(&prev, &curr, flag);

			/* Get next valid navigation line */
			flag = next_valid_nav_ping(&fps, &prev, &curr, &nping, yd);
			if(flag < 0){
				error = flag;
				if(error != EOF)
					error_msg(func, "While reading next navigation ping [inside]");
				goto on_error;
			}
			yd = curr.nav.yd;
			
		}
		
		/* Calculate statistics */
		final_stat(fps.sta, curr.data_stat_list, yd, year_base);
		
	} 
	/* ------------------------------------------------------------------ */

	if(!error)
		error = 0;

on_error:
	before_exit(&fps, &prev, &curr, error);

	return;

}

#endif /* scantnav_C_code_already_included */
	


