/* This is a companion routine to load_station_table for array beam code
tables.  At the moment it is essentially identical to the load_station_table
function, but changes may eventually occur in the beam table that will
make them diverge so I have produced to seperate functions */
Arr *load_array_table(Pf *pf)
{
	Arr *a;
	Tbl *t;
	int i;
	char *value;

	Seismic_Array *s;

        double elev_datum;
 
        a = newarr(0);
        elev_datum = pfget_double_wdef(pf,"elevation_datum",0.0);
	t = pfget_tbl(pf,"seismic_arrays");
	for(i=0;i<maxtbl(t);++i)
	{
		s = (Seismic_Array *) malloc(sizeof(Seismic_Array));
		if(s == NULL) elog_die(1,"load_array_table:  Cannot malloc Seismic_Array structure entry\n");
		value = gettbl(t,i);
		if(sscanf(value,"%s %lf %lf %lf",s->name,
			&(s->lat),&(s->lon),&(s->elev)) != 4)
			elog_complain(1,"Warning(load_array_table):  \
Read error in array tbl read from parameter file\n\
The following line of the array table was skipped\n%s\n",
				value);
		else
		{
                        s->elev -= elev_datum;
			setarr(a,s->name,s);
		}
	}
	return(a);
}
/* this is a parallel routine to dbload_station_table.  In fact, the
code is identical except it returns an associative array of 
Seismic_Array pointers rather than pointers to Station structures.  
This is consistent with CSS3.0 perspective that any station is a
candidate for making slowness measurements, even though that is 
rarely the case in practice.  It makes this table larger than 
necessary, but simplifies a lot of things and makes this code
of more general use.  

Author:  Gary L. Pavlis
Written:  January 1997
*/ 
Arr *dbload_array_table(Dbptr db,int row_start,int row_end,Pf *pf)
{
	Arr *a;
        Seismic_Array *s;
	char *prog="dbform_station_table";
	/* Values set by dbgetv from row of view */
	double lat, lon, elev;
	char staname[12];
	char laststa[12];
	double elev_datum;

	a = newarr(0);
        elev_datum = pfget_double_wdef(pf,"elevation_datum",0.0);

	for(db.record=row_start;db.record<row_end;++db.record)
	{
		if((dbgetv( db, 0,
			"sta",staname,
			"lat",&lat,
			"lon",&lon,
			"elev",&elev,
			NULL )) == dbINVALID) die(1,"%s:  dbgetv error\n",prog);
		if(db.record == row_start) strcpy(laststa,staname);
		if( (db.record == row_start) || strcmp(staname,laststa))
		{
			s = (Seismic_Array *) malloc(sizeof(Seismic_Array));
                	if(s == NULL) 
				die(1,"%s:  Cannot malloc Seismic_Array structure\n",
					prog);
			strcpy(laststa,staname);
			strcpy(s->name,staname);
			s->lat = lat;
			s->lon = lon;
			elev -= elev_datum;
			s->elev = elev;
			setarr(a,s->name,s);
		}
	}
	return(a);
}
Location_options parse_options_pf (Pf *pf)
{
	Location_options o;
	char *s;  /* string buffer */
	int i;
	int recenter=0;  /* recenter flag */

	o = load_default_options();
	s = pfget_string(pf,"arrival_residual_weight_method");
	/* Note this implicitly accepts the default if the keyword is missing */
	if(s != NULL)
	{
		if(!strcasecmp(s,"bisquare")) o.atime_residual_weight = BISQUARE;
		if(!strcasecmp(s,"thomson")) o.atime_residual_weight = THOMSON;
		if(!strcasecmp(s,"huber")) o.atime_residual_weight = HUBER;
		if(!strcasecmp(s,"none")) o.atime_residual_weight = NONE;
	}
	/* Do the same for slowness */
	s = pfget_string(pf,"slowness_residual_weight_method");
	if(s != NULL)
	{
		if(!strcasecmp(s,"bisquare")) o.slow_residual_weight = BISQUARE;
		if(!strcasecmp(s,"thomson")) o.slow_residual_weight = THOMSON;
		if(!strcasecmp(s,"huber")) o.slow_residual_weight = HUBER;
		if(!strcasecmp(s,"none")) o.slow_residual_weight = NONE;
	}

	o.atime_distance_weight = pfget_boolean_wdef(pf,
		"time_distance_weighting",o.atime_distance_weight);
	o.slow_distance_weight = pfget_boolean_wdef(pf,
			"slowness_distance_weighting",o.slow_distance_weight);
	o.slowness_weight_scale_factor = (float) pfget_double_wdef(pf,
				"slowness_weight_scale_factor",
				o.slowness_weight_scale_factor);
	o.min_error_scale = (float) pfget_double_wdef(pf,
				"min_error_scale",o.min_error_scale);
	o.max_error_scale = (float) pfget_double_wdef(pf,
					"max_error_scale",o.max_error_scale);
	for(i=0;i<4;++i) o.fix[i] = 0;
	if(pfget_boolean_wdef(pf,"fix_longitude",0)) o.fix[0] = 1;
	if(pfget_boolean_wdef(pf,"fix_latitude",0)) o.fix[1] = 1;
	if(pfget_boolean_wdef(pf,"fix_depth",0)) o.fix[2] = 1;
	if(pfget_boolean_wdef(pf,"fix_origin_time",0)) o.fix[3] = 1;
	if(pfget_boolean_wdef(pf,"recenter",0)) recenter = 1;
	s = pfget_string(pf,"generalized_inverse");
	if(s != NULL)
	{
	    if(!strcasecmp(s,"marquardt"))
	    {
		o.min_relative_damp = (float) pfget_double_wdef(pf,
			"min_relative_damp",o.min_relative_damp);
		if(o.min_relative_damp < FLT_EPSILON)
		{
			elog_log(0,"Warning:  minimum relative damping must be at least single precision epsilon.\nParameter file wanted %f\nReset to %f\n",
				o.min_relative_damp, FLT_EPSILON);
			o.min_relative_damp = FLT_EPSILON;
		}
		o.max_relative_damp = (float) pfget_double_wdef(pf,
				"max_relative_damp",o.max_relative_damp);
		o.damp_adjust_factor = (float) pfget_double_wdef(pf,
			"damp_adjust_factor",o.damp_adjust_factor);
		if(recenter)
			o.generalized_inverse = DAMPED_RECENTERED;
		else
			o.generalized_inverse = DAMPED_INVERSE;
	    }
	    if(!strcasecmp(s,"pseudoinverse"))
	    {
		o.sv_relative_cutoff = (float) pfget_double_wdef(pf,
				"singular_value_cutoff",o.sv_relative_cutoff);
		if(recenter)
			o.generalized_inverse = PSEUDO_RECENTERED;
		else
			o.generalized_inverse = PSEUDOINVERSE;
	    }
	}
	o.depth_ceiling = (float) pfget_double_wdef(pf,
				"depth_ceiling",o.depth_ceiling);
	o.depth_floor = (float) pfget_double_wdef(pf,
			"depth_floor",o.depth_floor);
	o.step_length_scale_factor = (float) pfget_double_wdef(pf,
			"step_length_scale_factor",o.step_length_scale_factor);
	o.min_step_length_scale = (float) pfget_double_wdef(pf,
			"min_step_length_scale",o.min_step_length_scale);
	if(o.step_length_scale_factor >= 1.0) 
	{
		elog_log(0,"Step length damping factors reset\nScale factors must be less than 1.0\nResetting to default of %f\n",DEFAULT_SLSF);
		o.step_length_scale_factor = DEFAULT_SLSF;
		if(o.min_step_length_scale >= o.step_length_scale_factor)
		{
			
			o.min_step_length_scale = (float)pow(DEFAULT_SLSF,SLSF_POW_MIN);
			elog_log(0,"Min step length scale also reset to %f\n",
					o.min_step_length_scale);
		}
	}
	if(o.min_step_length_scale >= o.step_length_scale_factor)
	{
		o.min_step_length_scale = (float)pow(o.step_length_scale_factor,
								SLSF_POW_MIN);
		elog_log(0,"Min step length scale is not consistent with step length scale factor parameter\nReset to %f\n",
			o.min_step_length_scale);
	}
	o.max_hypo_adjustments = pfget_int_wdef(pf,
		"maximum_hypocenter_adjustments",o.max_hypo_adjustments);
	o.dx_convergence = (float) pfget_double_wdef(pf,
		"deltax_convergence_size",o.dx_convergence);
	o.relative_rms_convergence = (float) pfget_double_wdef(pf,
		"relative_rms_convergence_value",o.relative_rms_convergence);
	return(o);
}