/*	PPVL_selections.c

Find named parameters and put their values in internal variables. This is an
add-on function to the PIRL Parameter Value Logic module.


Use:

	#include	"PPVL_selections.h"

	int
	PPVL_selections
		(
		PPVL_Parameter				*The_Aggregate,
		PPVL_Parameter_Selections	*The_Selections
		)


Description:

The_Aggregate is a pointer to a PPVL parameters aggregate (see the
documentation for the PPVL module), typically obtained by the
PPVL_read_aggregate function.

The_Selections is a pointer to a PPVL_Parameter_Selections structure:

typedef struct
	{
	char		*name;		Name of parameter to find.
	PPVL_Type	type;		Data type of value expected.
	int			count;		Number of values sought.
	void		*value;		Location of value storage.
	}
	PPVL_Parameter_Selections;

The PPVL_Parameter_Selections provide a generic way to specify what to look
for in a PPVL_Parameter aggregate, and the program variables that will store
what is found. This is typically the linkage between the external file
information structure and the internal program information structure.

The "type" entry is one of the PPVL_Type values:

	PPVL_TYPE_INTEGER - unsigned long
	PPVL_TYPE_REAL    - double
	PPVL_TYPE_STRING  - char *

For the two numeric types, the "value" is the address of an appropriate 
variable (or array, or array member). If the variable has not been typed the
same as the specific PPVL_Type, then appropriate casting may be necessary when
the variable is used. For strings, the variable used for "value" is expected
to be typed as a "char **" - i.e. a pointer to a string pointer (or array or
member of an array of strings) and it will be assigned the string pointer. >>>
WARNING <<< The string characters will not be copied so don't free the
parameters until the strings are no longer needed or have been copied.

Parameters that are not found in The_Aggregate result in no change to the
value storage for that parameter. So it may be appropriate to initialize value
storage with a default value. However, the same value storage may be referred
to by more than one parameter name, in which case the value of the last
parameter name found, if any, will be placed in the value storage. It may be
desirable to initialize value storage with a special value that can be used to
indicate that no parameter was found for that variable.

Parameters that are found to have the selected name but do not have the 
selected type will be silently ignored. However, the same parameter name may
be listed more than once with a different selected type (and possibly a
different value storage reference).

Parameter values are stored in sequential value storage locations starting a
the value storage address selected up to the count of values selected or the
number of values available, whichever is less. Since arrays of parameter
values may have different types for each value, only the values of the
selected type are used.

DON'T FORGET to NULL-terminate The_Selections list. This is easily done by
using PPVL_PARAMETER_SELECTIONS_END as the last entry in the list.


Return values:

	On success: PPVL_SUCCESS (0)
	On failure: Non-zero PPVL_errno value
		and PPVL_selections_error points at the problem selection.

		Note: The return value, and PPVL_errno, will be set to
		PPVL_ERROR_ILLEGAL_SYNTAX if an array data type is selected and the
		selected parameter value is an array. Since this parameter value does
		not have an assignable value it is ignored and processing will
		continue. PPVL_selections_error will be set to point to this selection.
		This error condition is thus really just a warning and can be ignored
		if desired.
		

Author:

Bradford Castalia                       Castalia@Arizona.edu
Senior Systems Analyst                  (520) 621-6946
Planetary Image Research Laboratory     (520) 621-4824
Department of Planetary Sciences        FAX: (520) 621-9628
University of Arizona                   Space Sciences Bldg.
1629 E. University Blvd.                Room 429
Tucson, Arizona  85721-0092

"Build an image in your mind, fit yourself into it."
    The log of Cyradis seeress of Kell.


SCCS ID:	@(#)PPVL_selections.c	1.6 10/04/00
*/
static char		*SCCS_ID = "@(#)PPVL_selections.c	1.6 10/04/00";

/*******************************************************************************

Copyright (C) 2000  Bradford Castalia, University of Arizona

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


Bradford Castalia                       Castalia@Arizona.edu
Senior Systems Analyst                  http://PIRL.LPL.Arizona.edu/~castalia
Planetary Image Research Laboratory     520-621-4824
Department of Planetary Sciences        FAX: 520-621-9628
University of Arizona                   Space Sciences Bldg.
1629 E. University Blvd.                Room 429
Tucson, Arizona  85721-0092

"Build an image in your mind, fit yourself into it."
    The Log of Cyradis, Seeress of Kell.

*******************************************************************************/


#include	<stdio.h>

#include	"PPVL_selections.h"


/*	Reports a problem parameter selection.

	Note: Setting PPVL_selections_error to -1 will cause a report of found
	parameters and their values to be sent to stderr.
*/
PPVL_Parameter_Selections
	*PPVL_selections_error;


#define ERROR(condition)                         \
	{                                            \
	if (condition)                               \
		PPVL_errno = condition;                  \
	PPVL_selections_error = parameter_selection; \
	goto Error_condition;                        \
	}



int
PPVL_selections
	(
	PPVL_Parameter				*The_Aggregate,
	PPVL_Parameter_Selections	*The_Selections
	)
{
PPVL_Parameter_Selections
	*parameter_selection = NULL;
PPVL_Parameter
	*parameter;
PPVL_Value
	**parameter_value;
void
	*selection_value;
int
	count;


PPVL_errno = PPVL_SUCCESS;
if ((int)PPVL_selections_error != -1)
	PPVL_selections_error = NULL;

if (! The_Aggregate ||
	! The_Selections)
	ERROR (PPVL_ERROR_BAD_ARGUMENT);

for (parameter_selection = The_Selections;
	 parameter_selection->name;
	 parameter_selection++)
	{
	/*	Find the named parameter.
	*/
	if (parameter = PPVL_find_parameter
			(
			The_Aggregate,
			PPVL_SEARCH_FROM_THE_TOP,
			PPVL_SELECT_NAME,
			parameter_selection->name,
			NULL
			))
		{
		if ((int)PPVL_selections_error == -1
			)
			fprintf (stderr, "PPVL_selections: Found %s\n",
				parameter_selection->name);

		if (! PPVL_Class_Is_Assignment (parameter->classification))
			continue;

		if (PPVL_Type_Is_Array (parameter->content.value->type))

			/*	Values array.
			*/
			parameter_value = parameter->content.value->data.array;

		else

			/*	Single value.
			*/
			parameter_value = &parameter->content.value;

		for (count = 0,
			 	selection_value = parameter_selection->value;
			 count < parameter_selection->count &&
			 	*parameter_value;
			)
			{
			if (PPVL_Type_Is ((*parameter_value)->type,
					parameter_selection->type))
				{
				/*	The parameter has the selected data type.
					Put the parameter value in the selected variable.
				*/
				switch (parameter_selection->type)
					{
					case PPVL_TYPE_INTEGER:
						((unsigned long *)selection_value)[count] =
							(*parameter_value)->data.integer;
						if ((int)PPVL_selections_error == -1
							)
							fprintf (stderr, "\tinteger - %ld\n",
								(*parameter_value)->data.integer);
						break;
					case PPVL_TYPE_REAL:
						((double *)selection_value)[count] =
							(*parameter_value)->data.real;
						if ((int)PPVL_selections_error == -1
							)
							fprintf (stderr, "\treal - %g\n",
								(*parameter_value)->data.real);
						break;
					case PPVL_TYPE_STRING:
						((char **)selection_value)[count] =
							(*parameter_value)->data.string;
						if ((int)PPVL_selections_error == -1
							)
							fprintf (stderr, "\tstring - %s\n",
								(*parameter_value)->data.string);
						break;
					default:
						/*
							This can only happen if the parameter value is an
							array type and the selection is one of the array
							types. But there is no valid value to get from such
							a parameter value. So note the condition with a
							syntax warning and skip this value.
						*/
						PPVL_errno = PPVL_ERROR_ILLEGAL_SYNTAX;
						PPVL_selections_error = parameter_selection;
					}
				count++;
				}
			/*
				Only array parameters can provide more than one value.
			*/
			if (PPVL_Type_Is_Array (parameter->content.value->type))
				parameter_value++;
			else
				break;
			}
		}
	}


Error_condition:

/*	Nothing special for an error condition;
	just return the error code.
*/

return (PPVL_errno);
}


