/**---------------------------------------------------------------------------
 ** 
 ** xtract.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/08/04 19:35:18
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/08/04 19:35:30
 ** Update Count    : 1
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/apps/db/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    Undocumented.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

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

	-Introduction:

	This programme extracts data from a CODAS database.
	
	##################################################################

	-Header Files:
	*/

#include "xtract.h"

/* ##################################################################
	 --Initialization Functions:
	 ################################################################## */

#if PROTOTYPE_ALLOWED
int free_memory(EXTRACT_VARIABLE_TYPE *list)
#else
int free_memory()
#endif
{

	int i;

	for(i=0; i<MAX_VARS; i++){
		if(list[i].data != NULL){
			free(list[i].data);
			list[i].data = NULL;
		}
	}

	return(0);

}

/* ------------------------------------------------------------------
	 --Init Database:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_db(FILE_NAME_TYPE dbname)
#else
int init_db(dbname)
#endif
{

	int db_id = 1;
	int mem = 0;
	int acc = 0;
	int ierr = 0;

	DBOPEN(&db_id, (char *) dbname, &acc, &mem, &ierr);
	if(DBERROR(&ierr, "DBOPEN"))
		return(1);
		
	return(0);
}

/* ------------------------------------------------------------------
	 --Init Extract Variable:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_extract_variable(FILE *fp, char *list, int code)
#else
int init_extract_variable()
#endif
{

	int n;

	/* Check for maximal number of variables */
	if(error_found(n_var >= MAX_VARS, "Reached maximal number of variables"))
		exit(-1);

	/* Set default options in current variable list */
	strcpy(var_defs.name, "");
	sprintf(var_defs.min_str, "-1.0E38");
	sprintf(var_defs.max_str, "+1.0E38");
	var_defs.scale= (FLOAT) 1.0;

	/* Read the options for variable definition */
	if(error_found(execute_options(fp, (OPTION_TYPE *) list, 0) <= 0,
								 "Reading variable definition options"))
		exit(-1);
	printf("\n");

	/* Control input */
	if(error_found(strlen(var_defs.name) == 0, 
								 "You must specifiy a variable name"))
		exit(-1);

	/* Copy input into the variable list */
	n_var++;
	n = n_var - 1;
	memcpy((void *) &(var_list[n]), (void *) &var_defs, 
				 sizeof(EXTRACT_VARIABLE_TYPE));
	var_list[n].code     = code;
	var_list[n].min      = -BADFLOAT;
	var_list[n].max      = +BADFLOAT;
	var_list[n].n        = 0;
	var_list[n].data     = NULL;
	var_list[n].struc    = NULL;

	/* Print the selected options */
	printf("%% VARIABLE %3d: %s\n", n_var, var_list[n].name);
	printf("%%         axis: %2d\n", code);
	printf("%%          min: %s\n", var_list[n].min_str);
	printf("%%          max: %s\n", var_list[n].max_str);
	printf("%%        scale: %f\n", var_list[n].scale);  

	return(0);
}

/* ------------------------------------------------------------------
	 --Init Extract Product:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int init_extract_product(FILE *fp, char *list, int code)
#else
int init_extract_product()
#endif
{

	FILE *fp_out;
	char prd_str[50];
	int n, i;

	/* Print the product name */
	if(code == VAR_PRD_CODE)
		strcpy(prd_str, "VARIABLES");
	else if(code == CNT_PRD_CODE)
		strcpy(prd_str, "CONTOUR");
	else if(code == PRF_PRD_CODE)
		strcpy(prd_str, "PROFILE");
	else
		strcpy(prd_str, "");

	printf("\n%% =======\n");
	printf("%% OPTIONS: %s\n", prd_str);
	printf("%% -------\n");

	/* Check for maximal number of products */
	if(error_found(n_prd >= MAX_PRDS, "Reached maximal number of products"))
		exit(-1);

	/* Initialize the output file */
	strcpy((char *) prd_defs.file, "");
	prd_defs.start_var = -1;
	prd_defs.stop_var = -1;
	prd_defs.bits = 0x0;

	/* Read all variable definitions */
	n = n_var;
	if(error_found(execute_options(fp, (OPTION_TYPE *) list, 0) <= 0,
								 "Reading product definitions"))
		exit(-1);

	/* Control if correct number of variables */
	i = n_var - n;
	if(error_found( (code == VAR_PRD_CODE) && (i < 1),
									"You must specify at least one variable"))
		exit(-1);
	if(error_found( (code == PRF_PRD_CODE) && (i < 2),
									"You must specify at least two variables"))
	if(error_found( (code == CNT_PRD_CODE) && (i < 3),
									"You must specify at least three variables"))
		exit(-1);

	/* Finish initializing variable list structure */
	n_prd++;
	i = n_prd - 1;
	prd_list[i].code = code;
	strcpy((char *) prd_list[i].file, (char *) prd_defs.file);
	prd_list[i].start_var = n;
	prd_list[i].stop_var  = n_var - 1;
	prd_list[i].bits = prd_defs.bits;

	/* Initialize the output file */
	if(strlen((char *) prd_list[i].file))
		fp_out = check_fopen((char *) prd_list[i].file, "w");
	
	return(0);
}

/* ##################################################################
	 -Miscellaneous:
	 ################################################################## */

#if PROTOTYPE_ALLOWED
int set_bad_flags(EXTRACT_VARIABLE_TYPE *list, int n, int imin, 
									int imax, int *i_list, int *all_bad, int *no_bad)
#else
int set_bad_flags()
#endif
{

	EXTRACT_VARIABLE_TYPE *xvar;
	int i, n_bad;

	/* Calculate the number of bad values */
	n_bad = 0;
	for(i=imin; i<=imax; i++){
		if(i_list != NULL)
			xvar = &(list[i_list[i]]);
		else
			xvar = &(list[i]);
		if(!(is_defined(xvar,n) && is_good(xvar,n)))
			n_bad++;
	}
	
	*all_bad = (n_bad == (imax-imin+1)) ? 1 : 0;
	*no_bad  = (n_bad == 0) ? 1 : 0;

	return(n_bad);

}

/* ##################################################################
	 -Product functions:
	 ################################################################## */

/* ------------------------------------------------------------------
	 --Extract Variable:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int extract_variable(EXTRACT_PRODUCT_TYPE *prd)
#else
int extract_variable()
#endif
{

	EXTRACT_VARIABLE_TYPE *xvar;
	FILE *fp;
	int i, n, nmax, nmin, n_bad, all_bad, no_bad;
	
	/* Get maximal and minimal number of data per variable */
	nmax = 0;
	nmin = MAXINT;
	for(i=prd->start_var; i<= prd->stop_var; i++){
		nmax = max_val(nmax, (int) var_list[i].n);
		nmin = min_val(nmin, (int) var_list[i].n);
	}

	/* Select for combined output */
	if(prd->bits & COMBINED_OUTPUT_BIT)
		nmax = nmin;
	
	/* Open the output file */
	if(strlen((char *) prd->file))
		fp = check_fopen((char *) prd->file, "a+");
	else
		fp = stdout;

	/* Loop through the bins */
	for(n=0; n<nmax; n++){
		/* Get the number of bad */
		n_bad = set_bad_flags(var_list, n, prd->start_var, prd->stop_var, NULL,
													&all_bad, &no_bad);
		/* 1998/12/08 PJ
			            Modified the test below to allow output of data even all of
			            them are bad. I think the previous test was not correct. 

		if((!all_bad) && (!(prd->bits & NO_BAD_OUTPUT_BIT) || no_bad)){ */
		if(!(prd->bits & NO_BAD_OUTPUT_BIT) || 
			 (!all_bad && no_bad && (prd->bits & NO_BAD_OUTPUT_BIT))){ 
			/* Loop through the variables */
			for(i=prd->start_var; i<=prd->stop_var; i++){
				xvar = &(var_list[i]);
				if(is_defined(xvar, n)){
					if(is_good(xvar,n))
						fprintf(fp, "%12.6f  ", (xvar->data)[n]);
					else
						fprintf(fp, "      1.0E38  ");
				}
				else if(prd->bits & UNDEFINED_OUTPUT_BIT)
					fprintf(fp, "     -1.0E38  ");
				else
					fprintf(fp, "      1.0E38  ");
			}
			fprintf(fp, "\n");
		}
	}
	
	/* Close the output file */
	if(prd->bits & SEPARATE_OUTPUT_BIT)
		fprintf(fp, "%%\n");
	if(strlen((char *) prd->file))
		fclose(fp);

	return(0);
	
}

/* ------------------------------------------------------------------
	 --Extract Profile:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int extract_profile(EXTRACT_PRODUCT_TYPE *prd)
#else
int extract_profile()
#endif
{

	EXTRACT_VARIABLE_TYPE *xvar;
	FILE *fp;
	int i, n, nmax, nmin, imax, i_list[MAX_VARS];
	int good_x, good_y, n_bad, all_bad, no_bad;
	char x_str[50];
	
	/* Create the index list with x and y variables at its beginning */
	n = 1;
	for(i=prd->start_var; i<= prd->stop_var; i++){
		if(is_x(var_list+i)) i_list[0] = i;
		else{
			i_list[n] = i;
			n++;
		}
	}
	if(error_found((prd->stop_var - prd->start_var + 1 != n),
								 "Problem with X and Y variables"))
		return(1);
	imax = n;

	/* Get maximal and minimal number of data per variable */
	nmax = 0;
	nmin = MAXINT;
	for(i=1; i< imax; i++){
		nmax = max_val(nmax, (int) var_list[i_list[i]].n);
		nmin = min_val(nmin, (int) var_list[i_list[i]].n);
	}

	/* Select for combined output */
	if(prd->bits & COMBINED_OUTPUT_BIT)
		nmax = nmin;

	/* Open the output file */
	if(strlen((char *) prd->file))
		fp = check_fopen((char *) prd->file, "a+");
	else
		fp = stdout;

	/* Loop through the bins */
	for(n=0; n<nmax; n++){
		/* Get the number of bad y variables */
		n_bad = set_bad_flags(var_list, n, 1, imax-1, i_list, &all_bad, &no_bad);

		if(!all_bad && (!(prd->bits & NO_BAD_OUTPUT_BIT) || no_bad)){
			good_x = good_y = 0;
			strcpy(x_str, "");
			/* Loop through the variables */
			for(i=0; i<imax; i++){
				xvar = &(var_list[i_list[i]]);
				if(is_x(xvar) && is_defined(xvar,n) && is_good(xvar,n)){
					sprintf(x_str, "%12.6f  ", (xvar->data)[n]);
					good_x = 1;
				}
				if(good_x){
					fprintf(fp, "%s", x_str);
					good_x = 0;
					good_y = 1;
				}
				if(is_y(xvar) && good_y){
					if(is_defined(xvar,n)){
						if(is_good(xvar,n))
							fprintf(fp, "%12.6f  ", (xvar->data)[n]);
						else
							fprintf(fp, "      1.0E38  ");
					}
					else if(prd->bits & UNDEFINED_OUTPUT_BIT)
						fprintf(fp, "     -1.0E38  ");
					else
						fprintf(fp, "      1.0E38  ");
				}
			}
			if(good_y)
			   fprintf(fp, "\n");
		}
	}
	
	/* Close the output file */
	if(prd->bits & SEPARATE_OUTPUT_BIT)
		fprintf(fp, "%%\n");
	if(strlen((char *) prd->file))
		fclose(fp);

	return(0);
	
}

/* ------------------------------------------------------------------
	 --Extract Contour:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int extract_contour(EXTRACT_PRODUCT_TYPE *prd)
#else
int extract_contour()
#endif
{

	EXTRACT_VARIABLE_TYPE *xvar;
	FILE *fp;
	int i, n, m, nmin, nmax, imax, i_list[MAX_VARS];
	int good_x, good_y, good_z, n_bad, no_bad, all_bad;
	char xy_str[50];
	
	/* Create the index list with x and y variables at its beginning */
	n = 2;
	for(i=prd->start_var; i<= prd->stop_var; i++){
		if     (is_x(var_list+i)) i_list[0] = i;
		else if(is_y(var_list+i)) i_list[1] = i;
		else{
			i_list[n] = i;
			n++;
		}
	}
	if(error_found((prd->stop_var - prd->start_var + 1 != n),
								 "Problem with X, Y and Z variables"))
		return(1);
	imax = n;

	/* Get maximal number of data per variable */
	nmax = 0;
	nmin = MAXINT;
	for(i=2; i< imax; i++){
		nmax = max_val(nmax, (int) var_list[i_list[i]].n);
		nmin = min_val(nmin, (int) var_list[i_list[i]].n);
	}

	/* Select combined output */
	if(prd->bits & COMBINED_OUTPUT_BIT)
		nmax = nmin;

	/* Open the output file */
	if(strlen((char *) prd->file))
		fp = check_fopen((char *) prd->file, "a+");
	else
		fp = stdout;

	/* Loop through the bins */
	for(n=0; n<nmax; n++){
		/* Get the number of bad z variables */
		n_bad = set_bad_flags(var_list, n, 2, imax-1, i_list, &all_bad, &no_bad); 

		if(!all_bad && (!(prd->bits & NO_BAD_OUTPUT_BIT) || no_bad)){			
			good_x = good_y = good_z = 0;
			strcpy(xy_str, "");
			/* Loop through the variables */
			for(i=0; i<imax; i++){
				xvar = &(var_list[i_list[i]]);
				m = n % xvar->n;
				if(is_x(xvar) && is_defined(xvar,m) && is_good(xvar,m)){
					sprintf(xy_str, "%12.6f  ", (xvar->data)[m]);
					good_x = 1;
				}
				else if(is_y(xvar) && is_defined(xvar,m) && is_good(xvar,m)){
					sprintf(xy_str, "%s%12.6f  ", xy_str, (xvar->data)[m]);
					good_y = 1;
				}
				if(good_x && good_y){
					fprintf(fp, "%s", xy_str);
					good_x = good_y = 0;
					good_z = 1;
				}
				if(is_z(xvar) && good_z){
					if(is_defined(xvar,n)){
						if(is_good(xvar,n))
							fprintf(fp, "%12.6f  ", (xvar->data)[n]);
						else
							fprintf(fp, "      1.0E38  ");
					}
					else if(prd->bits & UNDEFINED_OUTPUT_BIT)
						fprintf(fp, "     -1.0E38  ");
					else
						fprintf(fp, "      1.0E38  ");
				}
			}
			if(good_z)
			   fprintf(fp, "\n");
		}
	}
	
	/* Close the output file */
	if(prd->bits & SEPARATE_OUTPUT_BIT)
		fprintf(fp, "%%\n");
	if(strlen((char *) prd->file))
		fclose(fp);

	return(0);
	
}

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

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

	char func[]="do_it";

	YMDHMS_TIME_TYPE this, start_time, stop_time;
	FLOAT tmp_f;
	int i, j, error=0, search;
	char msg[200], str[200], str_lon[80];

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

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

	/* Initializations */
	if(error_found(init_db(dbname), "Opening database"))
		exit(-1);

	/* Loop through the time ranges */
	while(!(DBERROR(&error, NULL)) && 
				(get_time_range(fp_cnt, &start_time, &stop_time) == 1)){
		
		/* Message */
		time_range_to_str(str, &start_time, &stop_time);
		sprintf(msg, "\n%%%%%% TIME RANGE: %s\n", str);
		report_msg(msg);
		
		/* Position database to correct time */
		search = TIME_SEARCH;
		DBSRCH(&search, (char *) &start_time, &error);
		if(error && (error != SEARCH_BEFORE_BEGINNING)){
			DBERROR(&error, "DBSRCH");
			exit(-1);
		}

		error = 0;
		/* Loop through the database within time range */
		while(!(DBERROR(&error, NULL)) && 
					check_time(&this, &start_time, &stop_time)){
			/* Print time */
			print_ymdhms_time(stdout, &this);
			printf("\n");
			fflush(stdout);
		
			/* Get all variables */
			for(i=0; i<n_var; i++){
				/* Find the associated product definition */
				j = 0;
				prd_defs = prd_list[j];
				while((i < prd_list[j].start_var) && (i > prd_list[j].stop_var) 
							&& (j < n_prd))
					j++;
				if(error_found(j == n_prd, 
											 "Cannot find product definitions for this variable")){
					error = READ_ERROR;
					goto on_error;
				}
				prd_defs = prd_list[j];
				
				/* Get the data */
				var_list[i].n = 
					(unsigned int) extract_prf_var_f(&(var_list[i]), year_base);
				if(error_found(var_list[i].n <= 0, "Extracting variable data")){
					error = READ_ERROR;
					goto on_error;
				}

				/* Get range values for the variable */
				if(error_found(extract_range_values_f(&(var_list[i]), year_base),
											 "Getting range values"))
					goto on_error;

				/* Process longitude */
				strcpy(str_lon, var_list[i].name);
				for(j=0; j<((int) strlen(str_lon)); j++)
					str_lon[j] = toupper(str_lon[j]);
				if((strstr(str_lon, "LONGITUDE") != NULL) && 
					 (prd_defs.bits & LONGITUDE_180_BIT)){
					for(j=0; j<((int) var_list[i].n); j++){			         
						if((var_list[i].data)[j] > 180.0)
							(var_list[i].data)[j] -= 360.0;
					}
				}
  			
  			/* Scale the data */
  			for(j=0; j<((int) var_list[i].n); j++){
  			   (var_list[i].data)[j] *= var_list[i].scale;
				}
				var_list[i].min *= var_list[i].scale;
				var_list[i].max *= var_list[i].scale;
				if(var_list[i].max < var_list[i].min){
					tmp_f = var_list[i].min;
					var_list[i].min = var_list[i].max;
					var_list[i].max = tmp_f;
				}
			}
	
			/* Generate the products */
			for(i=0; i<n_prd; i++){
				switch(prd_list[i].code){
				case VAR_PRD_CODE:
					if(error_found(extract_variable(&(prd_list[i])), 
												 "Extract Variable Product"))
						goto on_error;
					break;
				case CNT_PRD_CODE:
					if(error_found(extract_contour(&(prd_list[i])), 
												 "Extract Contour Product"))
						goto on_error;
					break;
				case PRF_PRD_CODE:
					if(error_found(extract_profile(&(prd_list[i])), 
												 "Extract Profile Product"))
						goto on_error;
					break;
				default:
					error_found(1, "Undefined product code");
					goto on_error;
					break;
				}
			}

			/* Release memory from pointer allocation */
			free_memory(var_list);

			/* Increment database */
			DBMOVE(&steps, &error);
		}
	}
	error = 0;
	
on_error:
	/* Release memory from pointer allocation */
	free_memory(var_list);
	/* Close the database */
	if(db && db->db_is_open){
		DBCLOSE(&error);
		DBERROR(&error, "DBCLOSE");
	}
	/* 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;
}
	



