/**---------------------------------------------------------------------------
 ** 
 ** loaddnmi.c -- 
 ** 
 ** Author          : Pierre Jaccard
 ** Created On      : 1999/08/02 09:25:43
 ** Last Modified By: Pierre Jaccard
 ** Last Modified On: 1999/08/02 09:26:01
 ** Update Count    : 1
 ** Directory       : /home/pego/pcd1/codas3c/gfi/src/apps/misc/
 ** Version         : 0.0
 ** Status          : Unknown
 ** ---------------------------------------------------------------------- ** 
 ** DESCRIPTION: 
 ** 
 **    Undocumented.
 ** 
 ** ---------------------------------------------------------------------- ** 
 ** REVISIONS: 
 ** ---------------------------------------------------------------------- ** 
 ** CHANGES: 
 **------------------------------------------------------------------------**/

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

	-Introduction:

	Utility for loading DNMI data into a CODAS database.

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

#include "loaddnmi.h"

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

#if PROTOTYPE_ALLOWED
int init_options(DNMI_PROFILE_TYPE *dnmi)
#else
int init_options()
#endif
{

	int i, lon_180;

	/* Initializations at startup */
	if(dnmi == NULL){
		misc.grid_points = 0.0;
		misc.bits = 0x0;
		for(i=0; i<2; i++)
			ymdhms_to_bad(((YMDHMS_TIME_TYPE *) &(rng.time)) + i);
		for(i=0; i<4; i++)
			dmsh_to_bad(((DMSH_POSITION_TYPE *) &(rng.pos)) + i, (i % 2));
		
		return(0);
	}

	/* Assign pointers */
	dnmi->rng = &rng;
	dnmi->misc = &misc;

	/* Default time range */
	if(invalid_time(&(dnmi->rng->time.min)))
		ymdhms_to_min(&(dnmi->rng->time.min));
	if(invalid_time(&(dnmi->rng->time.max)))
		ymdhms_to_max(&(dnmi->rng->time.max));
	
	/* Default position range */
	lon_180 = ((dnmi->misc->bits) & LONGITUDE_180_BIT) ? -1 : 0;
	if(invalid_position(&(dnmi->rng->pos.min.lon), 0))
		dmsh_to_min(&(dnmi->rng->pos.min.lon), lon_180);
	if(invalid_position(&(dnmi->rng->pos.min.lat), 1))
		dmsh_to_min(&(dnmi->rng->pos.min.lat), 1);
	if(invalid_position(&(dnmi->rng->pos.max.lon), 0))
		dmsh_to_max(&(dnmi->rng->pos.max.lon), lon_180);
	if(invalid_position(&(dnmi->rng->pos.max.lat), 0))
		dmsh_to_max(&(dnmi->rng->pos.max.lat), 1);
	
	return(0);

}

/* ------------------------------------------------------------------
	 -Get Host Type:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int get_host_type(FILE_NAME_TYPE file)
#else
int ()
#endif
{

	FILE *fp;
	ULONG delim;
	int *i, n, host;

	int host_list[]=
	{
		PC_COMPATIBLE_HOST,
		VAXD_COMPATIBLE_HOST,
		SUN3_COMPATIBLE_HOST,
		UNKNOWN_HOST
	};

	/* Initializations */
	host = UNKNOWN_HOST;
	
	/* Open the file */
	fp = check_fopen(file, "rb");
	
	/* Loop through the host types */
	i = host_list;
	while((*i != UNKNOWN_HOST) && (host == UNKNOWN_HOST)){
		/* Get the header start delimiter */
		if(error_found(fseek(fp, 0, SEEK_SET), "Cannot position file\n"))
			return(-1);
		n = read_dnmi_data(fp, (char *) &delim, (int) sizeof(ULONG), *i, 
											 ULONG_VALUE_CODE);
		if(error_found(n != 1, "Cannot read binary file\n"))
			return(-1);
		/* Check if correct format */
		if(delim == DNMI_HEADER_DELIM)
			host = *i;

		i++;
	}
	fclose(fp);

	/* Check if a host has been found */
	if(error_found(host == UNKNOWN_HOST,
								 "Cannot determine host type for binary file\n"))
		return(-1);

	return(host);

}

/* ------------------------------------------------------------------
	 -Fill Profile Variables:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int fill_profile_variables(DNMI_PROFILE_TYPE *dnmi)
#else
int ()
#endif
{

	/* Short cuts */
	DNMI_DB_PRF_TYPE *p;
	DNMI_ANCILLARY_1_TYPE *a;
	DNMI_HEADER_TYPE *h;
	int n, *r;
	SHORT *s, *u, *v;
	DNMI_CONFIGURATION_1_TYPE *c;
	
	int i, j;
	
	/* Initializations */
	p = &(dnmi->db.prf);
	a = &(p->anc_1);
	h = &(dnmi->s.hdr);
	n = dnmi->rng->n;
	r = dnmi->rng->index;
	s = (dnmi->s).data;
	u = (dnmi->u).data;
	v = (dnmi->v).data;
	c = &(dnmi->db.blk.config_1);

	/* Release memory from previous call */
	dnmi_free_pointer((char **) &(p->s));
	dnmi_free_pointer((char **) &(p->u));
	dnmi_free_pointer((char **) &(p->v));
	dnmi_free_pointer((char **) &(p->f));

	/* Fill ANCILLARY_1 */
	a->rel_hour = h->relative_hour;

	/* Initialize memory fpr data */
	p->s = (FLOAT *) calloc((size_t) n, sizeof(FLOAT));
	if(error_found(!(p->s), "Insufficient memory (S)\n")) return(-1);
	p->u = (FLOAT *) calloc((size_t)n, sizeof(FLOAT));
	if(error_found(!(p->u), "Insufficient memory (U)\n")) return(-1);
	p->v = (FLOAT *) calloc((size_t)n, sizeof(FLOAT));
	if(error_found(!(p->v), "Insufficient memory (V)\n")) return(-1);
	p->f = (UBYTE *) calloc((size_t)n, sizeof(UBYTE));
	if(error_found(!(p->f), "Insufficient memory (f)\n")) return(-1);
	
	/* Fill data arrays: Bad data can be +/- BADSHORT */
	for(i=0; i<n; i++){
		j = r[i];
		if(abs_val(s[j]) != BADSHORT)
			p->s[i] = ((FLOAT) s[j]) * c->S_scaling_factor;
		else
			p->s[i] = BADFLOAT;
		if(abs_val(u[j]) != BADSHORT)
			p->u[i] = ((FLOAT) u[j]) * c->U_scaling_factor;
		else
			p->u[i] = BADFLOAT;
		if(abs_val(v[j]) != BADSHORT)
			p->v[i] = ((FLOAT) v[j]) * c->V_scaling_factor;
		else
			p->v[i] = BADFLOAT;
		p->f[i] = 0;
	}

	return(0);

}

/* ------------------------------------------------------------------
	 -Fill Block Variables:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int fill_block_variables(DNMI_PROFILE_TYPE *dnmi)
#else
int ()
#endif
{

	/* Short cuts */
	DNMI_DB_BLK_TYPE *b;
	DNMI_HEADER_TYPE *h, *s, *u, *v;
	YMDHMS_TIME_TYPE *t;
	DNMI_MISC_TYPE   *m;
	DNMI_CONFIGURATION_1_TYPE *c;
	int n, *r;

	int i;
	
	/* Initializations */
	b = &(dnmi->db.blk);
	h = &(dnmi->s.hdr);
	t = &(dnmi->prf_time);
	m = dnmi->misc;
	u = &(dnmi->u.hdr);
	v = &(dnmi->v.hdr);
	s = &(dnmi->s.hdr);
	c = &(b->config_1);
	n = dnmi->rng->n;
	r = dnmi->rng->index;

	/* Release memory from previous call */
	dnmi_free_pointer((char **) &(b->x));
	dnmi_free_pointer((char **) &(b->y));

	/* Fill the CONFIGURATION_1 structure */
	c->producer                  = h->producer;
	c->grid_area								 = h->grid_area;
	c->prognosis								 = h->prognosis;
	c->vertical_coord_type			 = h->vertical_coord_type;
	c->vertical_coord_reference	 = (SHORT) h->vertical_reference;
	c->grid_type								 = h->grid_type;
	c->x_grid_number						 = h->x_grid_number;
	c->y_grid_number						 = h->y_grid_number;
	c->origin_year							 = t->year;
	c->origin_month							 = t->month;
	c->origin_day								 = t->day;
	c->origin_hour							 = t->hour;
	c->x_coord_N_pole						 = (FLOAT) h->x_coord_N_pole;
	c->y_coord_N_pole						 = (FLOAT) h->y_coord_N_pole;
	c->grid_spacing_flag				 = (BYTE) (h->grid_spacing < 0) ? -1 : 1;
	c->grid_spacing							 = (FLOAT) 
		((abs_val((double) h->grid_spacing)/10.0) * 1000.0);
	c->grid_points							 = (FLOAT) m->grid_points;
	c->y_axis_parallel_longitude = (FLOAT) h->y_axis_parallel_longitude;
	c->S_scaling_factor					 = (FLOAT) 
		exp(log(10.0)*((double) s->scaling_factor));
	c->U_scaling_factor					 = (FLOAT) 
		exp(log(10.0)*((double) u->scaling_factor));
	c->V_scaling_factor					 = (FLOAT) 
		exp(log(10.0)*((double) v->scaling_factor));
	c->original_host_type        = (BYTE) m->from_host;

	/* Fill x and y positions */
	b->x = calloc((size_t) n, sizeof(FLOAT));
	if(error_found(!(b->x), "Insufficient memory (x)\n")) return(-1);
	b->y = calloc((size_t) n, sizeof(FLOAT));
	if(error_found(!(b->y), "Insufficient memory (y)\n")) return(-1);
	for(i=0; i<n; i++){
		(b->x)[i] = (FLOAT) (dnmi->lon)[r[i]];
		(b->y)[i] = (FLOAT) (dnmi->lat)[r[i]];
	}
	
	return(0);

}

/* ------------------------------------------------------------------
	 -Load Block Variables:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int load_block_variables(DNMI_PROFILE_TYPE *dnmi)
#else
	int load_block_variables()
#endif
{
	
	/* Short cuts */
	DNMI_DB_BLK_TYPE *b;
	unsigned int n, nbad;
	int db_type, ierr;

	/* Initializations */
	b = &(dnmi->db.blk);
	
	/* Fill block variables */
	if(error_found(fill_block_variables(dnmi), "fill_block_variables()\n"))
		return(-1);

	/* Load block variables */
	if(dbadd_cnf(CONFIGURATION_1, (char *) &(b->config_1),
							 sizeof(DNMI_CONFIGURATION_1_TYPE), "Adding CONFIGURATION_1\n"))
		return(-1);

	db_type = X;
	n = (unsigned int) dnmi->rng->n;
	DBADD_F(&db_type, b->x, &n, &nbad, &ierr);
	if(DBERROR(&ierr, "DBADD_F(X)")) return(ierr);
	db_type = Y;
	n = (unsigned int) dnmi->rng->n;
	DBADD_F(&db_type, b->y, &n, &nbad, &ierr);
	if(DBERROR(&ierr, "DBADD_F(Y)")) return(ierr);
	
	return(0);

}

/* ------------------------------------------------------------------
	 -Load Profile Variables:
	 ------------------------------------------------------------------ */

#if PROTOTYPE_ALLOWED
int load_profile_variables(DNMI_PROFILE_TYPE *dnmi)
#else
int ()
#endif
{
	
	/* Short cuts */
	DNMI_DB_PRF_TYPE *p;
	unsigned int n, nbad;

	int db_type, ierr;

	/* Initializations */
	p = &(dnmi->db.prf);

	/* Fill profile variables */
	if(error_found(fill_profile_variables(dnmi), "fill_profile_variables()\n"))
		return(-1);

	/* Load profile variables */
	if(dbadd_cnf(ANCILLARY_1, (char *) &(p->anc_1), 
							 (unsigned int) sizeof(DNMI_ANCILLARY_1_TYPE), 
							 "Adding ANCILLARY_1\n"))
		return(-1);
	n = (unsigned int) dnmi->rng->n;
	if(dbadd_cnf(PROFILE_FLAGS, (char *) &(p->f), 
							 (unsigned int) (n*sizeof(UBYTE)), "Adding PROFILE_FLAGS\n"))
		return(-1);

	db_type = SEA_SURFACE;
	n = (unsigned int) dnmi->rng->n;
	DBADD_F(&db_type, p->s, &n, &nbad, &ierr);
	if(DBERROR(&ierr, "DBADD_F(S)")) return(ierr);
	db_type = U;
	n = (unsigned int) dnmi->rng->n;
	DBADD_F(&db_type, p->u, &n, &nbad, &ierr);
	if(DBERROR(&ierr, "DBADD_F(U)")) return(ierr);
	db_type = V;
	n = (unsigned int) dnmi->rng->n;
	DBADD_F(&db_type, p->v, &n, &nbad, &ierr);
	if(DBERROR(&ierr, "DBADD_F(V)")) return(ierr);
	
	return(0);

}


/* ------------------------------------------------------------------
	 -Main:
	 ------------------------------------------------------------------ */

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

	DNMI_PROFILE_TYPE dnmi_prf;
	DNMI_HEADER_TYPE  dnmi_hdr;
	FILE_NAME_TYPE dnmi_file;
	FILE *fp;
	int ierr;

	char msg[200], str[200];

	/* Initialize DNMI profile parameters */
	init_dnmi(&dnmi_prf);
	set_byte((UBYTE *) &dnmi_hdr, (UBYTE) '\0', sizeof(DNMI_HEADER_TYPE));
	
	/* Initialize options */
	init_options(NULL);

	/* Get parameters */
	check_error(get_parameters(fp_cnt, param, NULL),
							"get_parameters()");
	print_parameters(stdout, param, NULL, "\n");
	
	/* Execute options */
	check_error(execute_options(fp_cnt, options, ECHO) <= 0,
							"execute_options()");

	/* Process options */
	init_options(&dnmi_prf);

	/* Initialize database */
	check_error(create_db(1, dbname, prd_file), "open_db()");

	/* Loop through the list of input files */
	ierr = 0;
	while(!ierr && (fscanf(fp_cnt, "%s", (char *) dnmi_file) == 1)){
		
		/* Get host type */
		ierr = get_host_type(dnmi_file);
		if(ierr < 0) break;
		(dnmi_prf.misc)->from_host = ierr;
		ierr = 0;
		printf("\n\n%% Correct host type is: %-d\n\n", (dnmi_prf.misc)->from_host);
		
		/* Initialize input file */
		fp = check_fopen(dnmi_file, "rb");
		
		/* Loop through the records */
		ierr = 0;
		while(!ierr){
			
			/* Get Data for a profile */
			dnmi_free_data(&dnmi_prf);
			ierr = get_dnmi_profile(fp, &dnmi_prf);
			if(ierr < 0) break;
			(dnmi_prf.misc)->n_data = ierr;
			ierr = 0;

			/* Get profile time */
			ierr = dnmi_to_ymdhmh_time(&(dnmi_prf.prf_time), &(dnmi_prf.s.hdr));
			if(error_found(ierr, "dnmi_to_ymdhmh_time()\n")) break;
			ymdhms_to_str(str, &(dnmi_prf.prf_time), 1);
			sprintf(msg, "%% DNMI Time: %s", str);

			/* Check if inside desired time range */
			if(time_inside_range(&(dnmi_prf.rng->time.min), &(dnmi_prf.rng->time.max),
													 &(dnmi_prf.prf_time))){
				
				/* Update time information */
				strcat(msg, " [+]\n");
				report_msg(msg);

				/* Check for header changes */
				if(dnmi_cmp_hdr(&dnmi_hdr, &(dnmi_prf.s.hdr))){
					/* Keep copy of header */
					memcpy((void *) &dnmi_hdr, (void *) &(dnmi_prf.s.hdr),
								 sizeof(DNMI_HEADER_TYPE));
					/* Calculate new positions */
					ierr = dnmi_to_gpos(&dnmi_prf);
					if(error_found((ierr<0) || (ierr != (dnmi_prf.misc)->n_data), 
												 "dnmi_to_gpos()\n")) break;
					/* Initialize index flags */
					ierr = dnmi_set_xy(&dnmi_prf);
					if(error_found(ierr<0, "dnmi_set_xy()\n")) break;
					dnmi_prf.rng->n = ierr;
					
					/* Add a new block */
					ierr = open_blk();
					if(error_found(ierr, "open_blk()\n")) break;
					/* Load block variables */
					ierr = load_block_variables(&dnmi_prf);
					if(error_found(ierr, "load_block_variables()\n")) break;
				}
				/* Open profile */
				ierr = open_prf(&(dnmi_prf.prf_time));
				if(error_found(ierr, "open_prf()\n")) break;
				/* Load profile variables */
				ierr = load_profile_variables(&dnmi_prf);
				if(error_found(ierr, "load_profile_variables()\n")) break;
			}
			else{
				strcat(msg, " [-]\n");
				report_msg(msg);
			}

			/* Exit loop if current profile time is newer than time range */
			if(TIMCMP(&(dnmi_prf.prf_time), &(dnmi_prf.rng->time.max)) == 2)
				break;

		}
		
		/* Check error */
		if(ierr && feof(fp))
			ierr = 0;
		fclose(fp);
		
	}
	
	/* Close database */
	if(error_found(close_db(), "close_db()\n"))
		ierr = -1;

	/* Check error */
	if(!(feof(fp_cnt)))
		ierr = -1;
	
	/* Release memory */
	dnmi_free_data(&dnmi_prf);

	/* Final Message */
	if(ierr)
		printf("\nLOADDNMI terminated on ERROR\n\n");
	else
		printf("\nLOADDNMI terminated successfully\n\n");
		
	return;

}
