/**---------------------------------------------------------------------------
 ** 
 ** io.c -- Read data from NBR files
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/07/15 12:14:13
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/11/17 13:25:41
 ** Update Count    : 5
 ** Directory       : /pcdata1/jaccard/codas3c/gfi/src/libs/nbr/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    This file provides functions for readding data from NBR files.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

#include "io.h"

/* ------------------------------------------------------------------
   Read data from next ping. On input, if fchg is TRUE, then reading
   next ping data in next data file is allowed. On output, if fchg is
   TRUE, then file change has occured.

   RETURN: non-zero on error, or EOF if no more ping is available
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int next_nbr_ping(/* Pointer to list of data files */
                  FILE *fp, 
                  /* Information structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Place for ensemble data */
                  NBR_ENSEMBLE_TYPE *ping,
									/* Flag allowing read in successive data files */
                  char fchg) 
#else
     int next_nbr_ping(fp, fi, ping, fchg)
     FILE *fp;
     DATA_FILE_INFO_TYPE *fi;
     NBR_ENSEMBLE_TYPE *ping;
     char fchg;
#endif
{
  
  char func[]="next_nbr_ping";
  
  DATA_FILE_INFO_TYPE finfo_backup;
  NBR_ENSEMBLE_TYPE   ping_backup;
  int error=0;
  long start_pos, stop_pos;
  
  /* Copy current state */
  /* 2001/01/02 PJ
     Backup of input state has been removed
     
     memcpy((void *) &ping_backup, (void *) ping, sizeof(NBR_ENSEMBLE_TYPE));
     memcpy((void *) &finfo_backup, (void *) fi, sizeof(DATA_FILE_INFO_TYPE));
  */
  
  /* Read next ensemble */
  error = read_ensemble(fi->fp, ping, &start_pos, &stop_pos);

  /* Check for end of data file and set the change file flagg */
  if(error == EOF){
    if(fchg){
      /* Get next file and read again next ensemble */
      error = next_data_file(fp, fi);
      if(!error){
        /* 2001/01/02 PJ
           Calling recusrsively to get first ensemble
           
           error = read_ensemble(fi->fp, ping, &start_pos, &stop_pos);
           fprintf(stderr, "\nNBRERR 2: %-d POS=%-d\n", error, ftell(fi->fp));
        */
        error = next_nbr_ping(fp, fi, ping, fchg);
        return(error);
        
      }
    }
    /* Update file change flag */
    fchg = 1;
  }
  else
    fchg = 0;

		
	/* Update data file structure */
	if(!error)
		fi->data_pos = (ULONG) ftell(fi->fp);
	else{
		if(error != EOF)
			error_msg(func, "While reading next ensemble");    
    /* 2000/12/03 PJ Removed backup of data */
    if(0){
      /* Restore old values in structure */
      memcpy((void *) fi, (void *) &finfo_backup, sizeof(DATA_FILE_INFO_TYPE));
      memcpy((void *) ping,  (void *) &ping_backup, sizeof(NBR_ENSEMBLE_TYPE));
      /* Position back to previous position */
      fseek(fp, (long) fi->list_pos, SEEK_SET);
      fseek(fi->fp, (long) fi->data_pos, SEEK_SET);
    }
		return(error);
	}

	return(0);

}

/* ------------------------------------------------------------------
   Read data from previous ping. On input, if fchg is TRUE, then
   reading previous ping data in previous data file is allowed. On output, 
   if fchg is TRUE, then file change occured.

   RETURNS: non-zero on error, or EOF if no more ping is available
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int prev_nbr_ping(/* Pointer to list of data filenames */
                  FILE *fp, 
                  /* Information structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Place for ensemble data */
                  NBR_ENSEMBLE_TYPE *ping,
									/* Flag allowing reading ping in successive data files */
                  char fchg) 
#else
     int prev_nbr_ping(fp, fi, ping, fchg)
     FILE *fp;
     DATA_FILE_INFO_TYPE *fi;
     NBR_ENSEMBLE_TYPE *ping;
     char fchg;
#endif
{
	
	char func[]="prev_nbr_ping";

	DATA_FILE_INFO_TYPE finfo_backup;
	NBR_ENSEMBLE_TYPE ping_backup, ping_tmp;
	int error=0, done;
	long pos, start_pos, stop_pos;

	/* Copy current state */
	memcpy((void *) &ping_backup, (void *) ping, sizeof(NBR_ENSEMBLE_TYPE));
	memcpy((void *) &finfo_backup, (void *) fi, sizeof(DATA_FILE_INFO_TYPE));

	/* Calculate position of ensemble start in data file */
	pos = ((long)fi->data_pos) - ((long)ping->header.output_buffer_size) - 2;
	if(pos < 0){
		error_msg(func, "Invalid position in data file");
		error = READ_ERROR;
	}
	
	/* Check for beginning of file and file changes */
	if(!error && (pos == 0)){
		if(fchg){
			error = prev_data_file(fp, fi);
			fchg = 1;
		}
		else
			error = EOF;
	}
	else
		fchg = 0;
	
	/* Position to start of current data file */
	if(!error){
		if(fseek(fi->fp, 0, SEEK_SET)){
			error_msg(func, "While rewinding to beginning of data file");
			error = READ_ERROR;
		}
	}

	/* Read in data file until previous ensemble has been read */
	if(!error){
		done = 0;
		while(!done){
			/* Read next ensemble */
			if(!error){
				memcpy((void *) &ping_tmp, (void *) ping, sizeof(NBR_ENSEMBLE_TYPE));
				error = read_ensemble(fi->fp, ping, &start_pos, &stop_pos);
			}
			/* Loop exit flagg */
			if((pos == 0) && fchg)
				done = error;
			else
				done = error || (stop_pos == pos);
		}
	}
	
	/* Update data file information */
	if(!error)
		fi->data_pos = (ULONG) ftell(fi->fp);
	else{
		/* Restore previous state */
		if((error == EOF) && (pos == 0) && fchg){
			memcpy((void *) ping,  (void *) &ping_tmp, sizeof(NBR_ENSEMBLE_TYPE));
			fi->data_pos = (ULONG) ftell(fi->fp);
		}
		else{
			memcpy((void *) fi, (void *) &finfo_backup, sizeof(DATA_FILE_INFO_TYPE));
			memcpy((void *) ping,  (void *) &ping_backup, sizeof(NBR_ENSEMBLE_TYPE));
			/* Position back in file */
			fseek(fp, (long) fi->list_pos, SEEK_SET);
			fseek(fi->fp, (long) fi->data_pos, SEEK_SET);
			/* Message */
			if(error != EOF)
				error_msg(func, "While parsing until previous ensemble");
			return(error);
		}
	}

	return(0);
}

/* ------------------------------------------------------------------
   This function moves to a specified ensemble from current ping.

   RETURNS: non-zero on error, or EOF if no more ping is available
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int goto_nbr_ping(/* List of data filenames */
                  FILE *fp, 
                  /* Information structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Place for ensemble data */
                  NBR_ENSEMBLE_TYPE *ping,
                  /* Desired ensemble number */ 
									int num)
#else
     int goto_nbr_ping(fp, fi, ping, num)
     FILE *fp;
     DATA_FILE_INFO_TYPE *fi;
     NBR_ENSEMBLE_TYPE *ping;
     int num;
#endif
{

	int error=0;

	/* Move forward */
	while(((USHORT) num > ping->leader.ensemble_number) && (!error))
		error = next_nbr_ping(fp, fi, ping, 1);
		
	/* Move backwards */
	while(((USHORT) num < ping->leader.ensemble_number) && (!error))
		error = prev_nbr_ping(fp, fi, ping, 1);

	return(error);
}

/* ------------------------------------------------------------------
   This function skips a specified number of ensembles from current ping. If
   num is negative, skipping is done backwards.
   
   RETURN: non-zero on error, or EOF if no more ping is available
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int skip_nbr_ping(/* List of data file names */
                  FILE *fp, 
                  /* Informatioon structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Place for ensemble data */
                  NBR_ENSEMBLE_TYPE *ping,
                  /* Number of ensembles to skip */
									int num)
#else
     int skip_nbr_ping(fp, fi, ping, num)
     FILE *fp;
     DATA_FILE_INFO_TYPE *fi;
     NBR_ENSEMBLE_TYPE *ping;
     int num;
#endif
{

	int error=0, i=0;

	/* Move forward */
	if(num > 0){
		while((i<num) && !error){
			error = next_nbr_ping(fp, fi, ping, 1);
			i++;
		}
	}
	
	/* Move backwards */
	if(num < 0){
		while((i>num) && !error){
			error = prev_nbr_ping(fp, fi, ping, 1);
			i--;
		}
	}

	return(error);
}

/* ------------------------------------------------------------------
	 Initialize a complete set of ping structures. If fp is NULL, only
	 initialize ping addresses. Else, also fills the ping state structure with
	 the data of the first ensemble. 

   RETURN: non-zero on error, or EOF if no more ping is available
   ------------------------------------------------------------------ */
#if PROTOTYPE_ALLOWED
int init_nbr_ping(/* List of data files names */
                  FILE *fp, 
                  /* Information structure about current data file */
                  DATA_FILE_INFO_TYPE *fi, 
                  /* Place for ensemble data */
                  NBR_ENSEMBLE_TYPE *ping)
#else
int init_nbr_ping(fp, fi, ping)
FILE *fp;
DATA_FILE_INFO_TYPE *fi
NBR_ENSEMBLE_TYPE *ping;
#endif
{

	char func[]="init_nbr_ping";

	int error=0;

	init_file_info(fp, fi, "rb");

	/* Put 0xF in each byte of the ping structure */
	memset((void *) ping, (int) 0xF, sizeof(NBR_ENSEMBLE_TYPE));
		
	/* Read the first ensemble */
	if(fp != NULL){
		error = next_nbr_ping(fp, fi, ping, 1);
		if(error){
			error_msg(func, "while getting first ping data");
			return(error);
		}
	}

	return(0);

}


