/**---------------------------------------------------------------------------
 ** 
 ** process.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/31 21:16:06
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/09/21 14:19:53
 ** Update Count    : 9
 ** Directory       : /pcdata1/jaccard/codas3c/gfi/src/apps/nbr/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    Undocumented.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

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

	-Introduction:

	Main programme for processing NB ADCP raw data and loading threm into the
	database.
	
	##################################################################
*/

#include "process.h"

/*
  Separate modules 
*/
#include "avg_.c"
#include "process_.c"
#include "load_.c"

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

/* ------------------------------------------------------------------
	 --Initialize Options:

	 This function sets all optionnal parameters to their default values. It
	 should be called before reading the options from the control file
	 ------------------------------------------------------------------ */

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

	/* Initialization of file names */
	strcpy(scan_nav_file, "");
	strcpy(nav_out_file, "");
	
	/* Time controls are set to a negative value, so that their default
	   value can be calculated later, when the average time is known */
	proc_cnt.max_gap = -1;
	proc_cnt.avg_min = -1;
	
	/* Transducer misalignements are set to zero */
	tr_mis.heading = 0.0;
	tr_mis.pitch   = 0.0;
	tr_mis.roll    = 0.0;
		
	/* Control strings */
	strcpy(pos_time_ref_str, "ensemble_stop");
	
	/* Conversion Controls */
	conv_cnt.echo_scale_temp = 10.0;
	conv_cnt.sound_speed     = DEFAULT_SOUND_SPEED;
	conv_cnt.sound_abs       = 0.039;
	
	/* Processing Controls */
	proc_cnt.bo = 0.0;
	proc_cnt.ba = 30.0;
	proc_cnt.check_meth = DEF_CHECK_BEAMS_METH;
	proc_cnt.check_op   = DEF_CHECK_BEAMS_OP;
  proc_cnt.min_bs     = -1;
	proc_cnt.max_bs     = MAXINT;
	proc_cnt.tr_depth   = 0.0;
	proc_cnt.bt_pings   = 255;
	proc_cnt.tr_freq    = 153600.0;

	return(0);
}

/* ------------------------------------------------------------------
	 --Initialize the Files:
	 ------------------------------------------------------------------ */

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

	fps->lst = check_fopen(file_list, "r");
	fps->log = check_fopen(log_file, "w");
	set_msg_file(fps->log);
  
	if(strlen(scan_nav_file)){
		fps->nav = check_fopen(scan_nav_file, "r");
		option_bits |= USE_SCAN_NAV_BIT;
	}
	else
		fps->nav = NULL;
	if(strlen(nav_out_file)){
		fps->out = check_fopen(nav_out_file, "w");
		option_bits |= NAV_OUTPUT_BIT;
	}
	else
		fps->out = NULL;
		
	return(0);
}		

/* ------------------------------------------------------------------
	 --Close the files:
	 ------------------------------------------------------------------ */

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

	fclose(fps->lst);
	fclose(fps->log);
	if(fi->fp)
		fclose(fi->fp);
	if(fps->nav)
		fclose(fps->nav);
	if(fps->out)
		fclose(fps->out);
	
	/* Close the database */
	close_db();

	return(0);

}

/* ------------------------------------------------------------------
	 --Initialize Memory:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_memory(LOAD_NBR_TYPE *rec)
#else
int init_memory(rec)
#endif
{

	char func[]="init_memory";
	
	/* Initialize the flag list */
	rec->flag_list = (FLAG_LIST_TYPE *)
		init_flag_list(flag_list, (char *) NULL, -1);
	if(rec->flag_list == NULL){
		error_msg(func, "while initializing flag list");
		return(INSUFFICIENT_MEMORY);
	}
	
	/* Initialize unistat list */
	rec->stat_list = (UNISTAT_LIST_TYPE *) 
		init_unistat_list(avg_nbr_stat_list, (char *) NULL, -1);
	if(rec->stat_list == NULL){
		error_msg(func, "while initializing unistat list");
		return(INSUFFICIENT_MEMORY);
	}
	
	zero_flag_list(rec->flag_list, BADINT);

	return(0);

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

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

#if PROTOTYPE_ALLOWED
int free_memory(LOAD_NBR_TYPE *rec)
#else
int free_memory(rec)
#endif
{

	free_unistat_list(rec->stat_list);
	free_flag_list(rec->flag_list);
	/* --------------------------------- */
	free(rec->stat_list);
	free(rec->flag_list);
	
	return(0);

}

/* ------------------------------------------------------------------
	 --Initialize Conversion Control Structure:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_cnv_control(LOAD_NBR_TYPE *rec)
#else
int init_cnv_control(rec)
#endif
{

	char func[]="init_cnv_control";

	DATA_TO_CONVERSION_TYPE *uc;

	/* Fiinish to fill the correspondance list between the data and the
		 conversion code */
	uc = uni_to_cnv_list;
	while(uc->name != NULL){
		if(uc->cnv_code == BADINT){
			switch(uc->var_code){
			case HEADING_CODE:
				uc->cnv_code = (option_bits & CORRECT_HEADING_BIT) ?
					CNV_NAV_HEADING_CODE : CNV_NBR_HEADING_CODE;
				break;
			case HEADING_SDEV_CODE:
				uc->cnv_code = (option_bits & CORRECT_HEADING_BIT) ?
					CNV_NAV_HEADING_SDEV_CODE : CNV_NBR_HEADING_SDEV_CODE;
				break;
			case PITCH_CODE:
				uc->cnv_code = (option_bits & CORRECT_PITCH_BIT) ?
					CNV_NAV_PITCH_CODE : CNV_NBR_PITCH_CODE;
				break;
			case PITCH_SDEV_CODE:
				uc->cnv_code = (option_bits & CORRECT_PITCH_BIT) ?
					CNV_NAV_PITCH_SDEV_CODE : CNV_NBR_PITCH_SDEV_CODE;
				break;
			case ROLL_CODE:
				uc->cnv_code = (option_bits & CORRECT_ROLL_BIT) ?
					CNV_NAV_ROLL_CODE : CNV_NBR_ROLL_CODE;
				break;
			case ROLL_SDEV_CODE:
				uc->cnv_code = (option_bits & CORRECT_ROLL_BIT) ?
					CNV_NAV_ROLL_SDEV_CODE : CNV_NBR_ROLL_SDEV_CODE;
				break;
			default:
				warning_msg(func, "No conversion code defined for this variable code");
				break;
			}
		}
		/* Update pointer */
		uc++;
	}
	
	/* Fill the conversion control structure */
	conv_cnt.buff             = (char *) &ref_rec;
	conv_cnt.buff_size        = sizeof(LOAD_NBR_TYPE);
	conv_cnt.adcp_config      = &(rec->ens.leader.adcp_config);
	conv_cnt.tr_mis           = &(tr_mis);
	conv_cnt.scaling_list     = nbr_scaling_list;
	conv_cnt.conversion_list  = nbr_conversion_list;
	conv_cnt.data_to_cnv_list = uni_to_cnv_list;
									
	/* Update the pointer in the record */
	rec->cnv = &conv_cnt;

	return(0);

}

/* ------------------------------------------------------------------
	 --Initialize Process Control Structure:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_proc_control(LOAD_NBR_TYPE *rec)
#else
int init_proc_control()
#endif
{

	char msg[200];

	/* Setting default values for time controls */
	proc_cnt.avg_time *= 100;
	proc_cnt.max_gap  *= 100;
	proc_cnt.avg_min  *= 100;
	if(proc_cnt.max_gap < 0){
		proc_cnt.max_gap = proc_cnt.avg_time / 5;
		sprintf(msg, "%%%%%% Setting MAX_GAP time to %d s\n",
			proc_cnt.max_gap/100);
		report_msg(msg);
	}
	if(proc_cnt.avg_min < 0){
		proc_cnt.avg_min = proc_cnt.avg_time - proc_cnt.max_gap;
		sprintf(msg, "%%%%%% Setting AVG_MIN time to %d s\n",
			proc_cnt.avg_min/100);
		report_msg(msg);
	}
	
	/* Check bin solutions */
	if(proc_cnt.min_bs < MIN_BEAM_SOLUTION_NUM){
		proc_cnt.min_bs = MIN_BEAM_SOLUTION_NUM;
		sprintf(msg, "%%%%%% Setting MIN beam solution to %d\n",
						proc_cnt.min_bs);
		report_msg(msg);
	}
	if(proc_cnt.max_bs > MAX_BEAM_SOLUTION_NUM){
		proc_cnt.max_bs = MAX_BEAM_SOLUTION_NUM;
		sprintf(msg, "%%%%%% Setting MAX beam solution to %d\n",
						proc_cnt.max_bs);
		report_msg(msg);
	}

	proc_cnt.adcp_config = &(rec->ens.leader.adcp_config);
	proc_cnt.bvsl = beam_vector_signs_list;
	proc_cnt.bml  = bin_map_list;

	/* Update pointer in record */
	rec->cnt = &(proc_cnt);

	return(0);

}

/* ------------------------------------------------------------------
	 --Initialize Process Control Structure:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_load_control(LOAD_NBR_TYPE *rec)
#else
int init_load_control()
#endif
{
	
	/* Set the flag for creating a new block */
	set_flag(rec->flag_list, LOAD_BLOCK_VAR_FLAG, 0, 1);

	return(0);

}

/* ------------------------------------------------------------------
	 --Initializations:
	 
	 This function initializes files, memory, and other parameters according to
	 the options read from the control file. It should be called just after the
	 latter has been read.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init(LOAD_NBR_FILES_TYPE *fps, LOAD_NBR_TYPE *rec)				
#else
int init(fps, rec)
#endif
{

	/* Initialize files */
	init_files(fps);

	/* Set the correct bit for position and time reference */
	if(!(strcmp(pos_time_ref_str, "ensemble_start")))
		option_bits |= POS_TIME_START_BIT;
	else if(!(strcmp(pos_time_ref_str, "ensemble_stop")))
		option_bits |= POS_TIME_STOP_BIT;
	/* Any other entry will generate a reference at the middle of the 
		 ensemble */
	
	/* Initialize data file information structure */
	init_file_info(fps->lst, &(rec->fi), "rb");
	
	if( init_memory(rec) )
		return(INSUFFICIENT_MEMORY);
	
	/* Initialize the control structures */
	init_cnv_control(rec);
	init_proc_control(rec);
	init_load_control(rec);

	/* Calculate the rotation matrix for transformation from instrument to ship
		 coordinate system */
	fill_rotation_matrix((double *) adcp_to_ship, tr_mis.heading + proc_cnt.bo,
											 tr_mis.pitch, tr_mis.roll);
	
	/* Initialize data base */
	init_db(dbname, prdfile);

	return(0);
}		 

/* ------------------------------------------------------------------
	 --Fill Navigation Output Structure:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int fill_nav_output(LOAD_NBR_TYPE *rec, AVG_NPT_TYPE *npt)
#else
int fill_nav_output(rec, npt)
#endif
{

	NAV_OUT_LINE_TYPE *n;
	double dt, dx, dy, dla, dlo, lat;

	/* Assign pointers */
	n = &(rec->out);

	/* Calculate mean ship velocity */
	dt = (npt->stop.time.hun - npt->start.time.hun)/100.0;
	lat= (npt->start.pos.lat + npt->stop.pos.lat)/2.0;
	dla= (npt->stop.pos.lat - npt->start.pos.lat);
	dlo= (npt->stop.pos.lon - npt->start.pos.lon);
	dx = dlon_to_meters(dlo, lat);
	dy = dlat_to_meters(dla, lat);
	
	/* Fill structure */
	n->yd = npt->db.time.yd;
	n->ref.u = BADDOUBLE;
	n->ref.v = BADDOUBLE;
	if(dt > MINFLOAT){
		n->ship.u = dx/dt;
		n->ship.v = dy/dt;
	}
	else{
		n->ship.u = BADDOUBLE;
		n->ship.v = BADDOUBLE;
	}
	n->pos.lat = npt->db.pos.lat;
	n->pos.lon = npt->db.pos.lon;
	n->filter_fraction = BADDOUBLE;

	return(0);
}

/* ##################################################################
	 -Input Functions:
	 ################################################################## */

/* ------------------------------------------------------------------	
   -Read Next Record:
   
	This function reads the next valid record. A record is composed of a valid
	[[scan_nav]] line, and its corresponding ADCP raw ping ensemble. The latter
	is found by reading the ADCP raw files until the ensemble number matches the
	one read from the [[scan_nav]] file. If [[scan_nav]] input is not specified,
	then the record consits of the next ADCP raw ping only.  
	------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int next_record(LOAD_NBR_FILES_TYPE *fps, LOAD_NBR_TYPE *rec)
#else
int next_record(fps, rec)
#endif
{

	char func[]="next_record";
	
	int error;
	USHORT nav_num=0, nbr_num=0, d1, d2;
	FILE_NAME_TYPE prev;
  static int last_nav = -1;
  char str[200];
	
	/* Initializations */
	strcpy(prev, rec->fi.name);

  /* read next nbr ping */
  error = next_nbr_ping(fps->lst, &(rec->fi), &(rec->ens), 1);
  if(error){
    if(error != EOF)
      error_msg(func, "While reading next nbr ping");
    return(error);
  }
  process_status_data(&(rec->ens));
  nbr_num = rec->ens.leader.ensemble_number;
  short_info((&nbr_num), -USHORT_VALUE_CODE);
    
	/* Check for scan_nav input */	      
	if(option_bits & USE_SCAN_NAV_BIT){ 
		
    /* Read next valid scan_nav line */ 
		error = read_scan_nav_line(fps->nav, &(rec->nav), year_base); 
		if(error){ 
			if(error != EOF)
   		  error_msg(func, "While reading next valid scan_nav line"); 
			return(error); 
		}
		nav_num = rec->nav.number;
  
    /* 
       Synchronize nbr and nav pings, taking care of the change from 65535 to
       zero  
    */
    while(nav_num != nbr_num){
      
      sprintf(str, "%%%%%% SYNCHRONIZING PINGS: nbr=%-d  nav=%-d\n",
              nbr_num, nav_num);
      report_msg(str);

      /*
       * Below, d2 will be smaller than d1 if one of nav or nbr has crossed
       * from 65535 to 0, but not the other one. We have also to take into
       * account navigation gaps accross. These happen usually at file
       * changes. Navigation ensemble is then reset before the adcp ensemble. 
       */
      d1 = abs_val(nav_num - nbr_num);  
      d2 = 65536 - d1;
      
      /* 
       * No crossing  AND  nbr > nav  AND  no nav reset : nbr AFTER nav
       * Crossing     AND  nbr < nav : nbr AFTER nav
       * 
       */
      if( ((d2 > d1) && (nbr_num > nav_num) && (last_nav < nav_num))
          || (!(d2 > d1) && !(nbr_num > nav_num)) ){
        
        /* Read next valid scan_nav line */ 
        error = read_scan_nav_line(fps->nav, &(rec->nav), year_base); 
        if(error){ 
          if(error != EOF)
            error_msg(func, "While reading next valid scan_nav line"); 
          return(error); 
        }
        last_nav = nav_num;
        nav_num = rec->nav.number; 
      }
      /*
       * No crossing  AND  nbr < nav : nbr BEFORE NAV
       * Crossing     AND  nbr > nav : nbr BEFORE NAV
       */
      else{
              
        /* read next nbr ping */
        error = next_nbr_ping(fps->lst, &(rec->fi), &(rec->ens), 1);
        if(error){
          if(error != EOF)
            error_msg(func, "While reading next nbr ping");
          return(error);
        }
        process_status_data(&(rec->ens));
        nbr_num = rec->ens.leader.ensemble_number;
        short_info((&nbr_num), -USHORT_VALUE_CODE);
      }
    }
  }
  last_nav = nav_num;
      
	/* Check for raw file changes: */
	report_file_change(prev, rec->fi.name);
  
	return(0);
	
}

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


/* ------------------------------------------------------------------
	 --Write Navigation:

	 This output may be used by [[putnav]] to store raw navigation data from
	 processing. Since [[putnav]] checks the value of [[ref_u]] to flagg bad
	 positions, the reference velocities are set to zero. The same is done for
	 the filter fraction.
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int write_nav(FILE *fp, NAV_OUT_LINE_TYPE *n)
#else
int write_nav(fp, rec)
#endif
{

	/* Write navigation line in [[putnac]] format */
	fprintf(fp, "%15.8f 0.0 0.0 %8.2f %8.2f %15.8f %15.8f 0.0\n",
					n->yd, n->ship.u, n->ship.v, n->pos.lon, n->pos.lat);
	
	return(0);

}

/* ##################################################################
   -MAIN:
   ################################################################## */
   
#if PROTOTYPE_ALLOWED
void do_it(FILE *fp_cnt)
#else
void do_it(fp_cnt)
FILE *fp_cnt
#endif
{

	char func[]="do_it";
	
	LOAD_NBR_FILES_TYPE fps;
	LOAD_NBR_TYPE rec;
	YMDHMS_TIME_TYPE start_time, stop_time;
	AVG_NPT_TYPE npt;
	
	int error=1;
	double start_day, stop_day, yd;
	ULONG hun_stop;
	
	char str[100], msg[200];

	/* Set default values */
	init_options();
	
	/* Read parameters and options from control file */
	if (get_parameters(fp_cnt, load_params, NULL)) exit(-1);
	print_parameters(stdout, load_params, NULL, "\n");

	if (execute_options(fp_cnt, load_options, ECHO)<=0){
		error_msg(func, "while reading load options.");
		exit(-1);
	}

	/* Initializations */
	error = init(&fps, &rec);
	if(error){
		error_msg(func, "While initializing [[load_nbr]]");
		goto on_error;
	}
	
	/* Read first record */
	report_msg("\n%%% Reading first record...\n");
	if(next_record(&fps, &rec)){
		error_msg(func, "While reading first record");
		goto on_error;
	}

	/* Fill the number, time and position structure */
	set_avg_npt(&npt, &rec, year_base, CURRENT_NPT_CODE);
	yd = npt.curr.time.yd;
	
	/* Message */
	yd_to_ymdhms_str(str, yd, year_base);
	sprintf(msg, "\n%%%%%% FIRST ENSEMBLE NUMBER %hu  TIME: %s\n",
			npt.curr.number, str);
	report_msg(msg);
	
	error = 0;
	
	/* Loop through time ranges */
	while( get_time_range(fp_cnt, &start_time, &stop_time)==1 ){
		
		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, yd, year_base);
		sprintf(msg, "\n%%%%%% TIME: %s\n", str);
		report_msg(msg);
		report_msg("%%% Outside time range ...\n");

		/* Loop outside time range */
		while(yd < start_day){
		
			short_info(&(npt.curr.number), -USHORT_VALUE_CODE);

			/* Read next record */
			error = next_record(&fps, &rec);
			if(error){
				if(error != EOF)
					error_msg(func, "While reading next record");
				goto on_error;
			}

			/* Update ensemble number position and time */
			set_avg_npt(&npt, &rec, year_base, CURRENT_NPT_CODE);
			yd = npt.curr.time.yd;

		}

		yd_to_ymdhms_str(str, yd, year_base);
		sprintf(msg, "\n%%%%%% TIME: %s\n", str);
		report_msg(msg);
		report_msg("%%% Inside time range ...\n");

		/* Start a new block for each time range */
		/* 98/08/24 PJ
			 This feature has now been moved into `init_load()' for
			 initialization, and it is controlled by an option during loading of
			 data. Currently, only the appropriate flag is set here. One could may
			 be call `init_load()' instead */
		if(option_bits & NEW_BLOCK_EACH_TRNG_BIT)
			set_flag(rec.flag_list, LOAD_BLOCK_VAR_FLAG, 0, 1);

		/* Loop inside time range */
		while((yd < stop_day) && !error) {
		

			/* Initialize averaging process */
			init_avg(&npt, &rec);
			
			/* Keep a copy of average start of ensemble number, position and 
				time */
			set_avg_npt(&npt, NULL, year_base, START_NPT_CODE);
			hun_stop = npt.start.time.hun + proc_cnt.avg_time;

			/* Loop inside averaging interval */
			while((npt.curr.time.hun < hun_stop) && !error 
				&& !(get_flag(rec.flag_list, AVERAGE_FLAG, 0))){
        
				/*
          short_info(&(npt.curr.number), -USHORT_VALUE_CODE);
        */
        
				/* Process data from record */
				error = process_data(&rec, (double *) adcp_to_ship);
				if(error){
					error_msg(func, "While processing data");
					goto on_error;
				}

				/* Update average */
				update_unistat_list(rec.stat_list, BADINT);
				
				/* Backup current ensemble number position and time */
				set_avg_npt(&npt, NULL, year_base, PREVIOUS_NPT_CODE);
				
				/* Read next record */
				error = next_record(&fps, &rec);
				if(error && (error != EOF)){
					error_msg(func, "While reading next record");
					goto on_error;
				}
					
				if(!error){					
					/* Update ensemble number position and time */
					set_avg_npt(&npt, &rec, year_base, CURRENT_NPT_CODE);
					yd = npt.curr.time.yd;
					check_avg_time(&npt, &proc_cnt, rec.flag_list);
				}

        /*
				printf("\nYD: %f %f\n", yd, stop_day);
        */
				
				
			} /* inside averaging interval */
			
			/* Update average flag */
			if(!error){
				/* Set the average flag */
				if(!(get_flag(rec.flag_list, AVERAGE_FLAG, 0)))
					set_flag(rec.flag_list, AVERAGE_FLAG, 0, NORMAL_AVERAGE_CODE);
			}
			else if(error == EOF)
				/* At EOF, ty to average the last pings */
				set_flag(rec.flag_list, AVERAGE_FLAG, 0, 
								 check_avg_time(&npt, &proc_cnt, NULL));
			 
			/* Fill number position and time for ensemble stop */
			set_avg_npt(&npt, NULL, year_base, STOP_NPT_CODE);
			set_avg_npt(&npt, NULL, year_base, DB_NPT_CODE);

			if( get_flag(rec.flag_list, AVERAGE_FLAG, 0) > 0){
				
				/* Set flag for loading profile variables */
				set_flag(rec.flag_list, LOAD_PROF_VAR_FLAG, 0, 1);
				
				/* Calculate mean values */
				calculate_unistat_list(rec.stat_list, BADINT);
			
				/* Fill navigation output structure */
				if(option_bits & USE_SCAN_NAV_BIT)
					fill_nav_output(&rec, &npt);

				/* Write navigation output */
				if(option_bits & NAV_OUTPUT_BIT)
					write_nav(fps.out, &(rec.out));

				/* Load data into the data base */
				if( load_data(&rec, &npt) ){
					error_msg(func, "Loading data into the database");
					goto on_error;
				}
			}
				
			/* Message */
			log_avg(fps.log, &npt, &rec, year_base);

		} /* Inside time range */
		
	} /* loop through time ranges */
			
	error=0;
			
on_error:

	free_memory(&rec);
	close_files(&fps, &(rec.fi));
	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;
	
}

