/*-=-=-=-=-=-=-=-=-=-=-=- RCCL/RCI Notice of Copyright -=-=-=-=-=-=-=-=-=-=-*
 *									    *
 *	Copyright (C) 1987, 1991 by John E. Lloyd.			    *
 *									    *
 *	Information on copyright permissions, as well as a complete	    *
 *	disclaimer of warranty, is given in the file COPYRIGHT.		    *
 *									    *
 *-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*---------------------------------------------------------------------------
 *		
 * MODULE NAME:	parameterDefs
 *
 * DESCRIPTION:	The RCI 'parameters' package, with which a set of parameters
 *		can be defined in the file '.rciparams' and referenced
 *		by an application program through various interface routines.
 * 
 * CAVEATS:	The 'parameters' package should be made obsolete
 *		by a new 'database' package that I am working on.
 *
 * AUTHOR/DATE:	John Lloyd, Fall 1987
 *
 * MODIFICATION HISTORY:
 *
 *--------------------------------------------------------------------------*/

#include "../h/cdefs.h"
#include "../h/errorCodes.h"
#include "../h/rciParameters.h"

#include "../rci/parameters.h"
#include "../rci/link.h"

static int parameterInit();
static PARAM *findparam();
static PARAM *setupParam();

static PARAMSPEC *parameterList = NULL;

static int initDone = 0;
#define INIT_CHECK()	if (!initDone) doInit();
static doInit()
{
	initDone = 1;
	if (parameterList != NULL)
	 { PARAMSPEC *spec, *spec_next;
	   for (spec=parameterList; spec!=parameterList; spec=spec_next)
	    { spec_next = spec->next;
	      freeParameterSpec(spec);
	    }
	   FREE(parameterList);
	   parameterList = NULL;
	 }
	requestFlagInit (&initDone);
}

/* ----- Error Messages. Defined externally to save space ----- */

static char *cantDoInitMsg	= "%s -- can't initialize\n";
static char *outOfMemoryMsg	= "%s -- out of memory\n";
static char *noRCCLEnvMsg	= "%s -- environment variable RCCL not set\n";
static char *cantReadFileMsg	= "%s -- can't read file\n";

rciParameters (name, write)
const char *name;
int write;
{
	char *fxnName = "rciParameters()";
	register PARAMSPEC *p;

	INIT_CHECK();

	if (!planningLevelCheck(fxnName))
	 { return (-1);
	 }
	if (parameterList == NULL)
	 { if (parameterInit() < 0) 
	    { errorMsg (getErrorCode(0), cantDoInitMsg, fxnName);
	      return (-1);
	    }
	 }
	for (p=parameterList->next; p != parameterList; p = p->next)
	 { if (strcmp (name, p->name) == 0)
	    { if (write)
	       { p->writeable = 1;
	       }
	      return ((int)p);
	    }
	 }
	if (write)
	 { /* create an entry for the parameter set */

	   if ((p = ALLOC(PARAMSPEC)) == NULL)
	    { errorMsg (EMemory, outOfMemoryMsg, fxnName);
	      return (-1);
	    }
	   p->list.next = p->list.prev = &(p->list);
	   LINK (p, parameterList);
	   p->writeable = 1;
	   return ((int)p);
	 }
	return (0);	
}

static parameterInit()
{
	char *fxnName = "parameterInit()";

	/* Called the first time rciAttachRobot() is called.
	   Reads in definitions from the config file and sets up
	   the parameter list.
	 */

	char fileName[256];
	char *dir;

	if ((dir = (char*)getenvRCCL()) == NULL)
	 { errorMsg (EEnviron, noRCCLEnvMsg, fxnName);
	   return (-1);
	 }
	if ((parameterList = ALLOC(PARAMSPEC)) == NULL)
	 { errorMsg (EMemory, outOfMemoryMsg, fxnName);
	   return (-1);
	 }
	parameterList->next = parameterList->prev = parameterList;
	sprintf (fileName, "%s/conf/.rciparams", dir);
	if (readParameterFile (fileName, parameterList) < 0)
	 { errorMsg (getErrorCode(0), cantReadFileMsg, fxnName);
	   return (-1);
	 }
	if (dir = (char*)getenvHOME())
	 { sprintf (fileName, "%s/.rciparams", dir);
	   if (readParameterFile (fileName, parameterList) < 0)
	    { if (getErrorCode(0) != EBadAccess)
	       { errorMsg (getErrorCode(0), cantReadFileMsg, fxnName);
		 return (-1);	
	       }
	      else
	       { clearErrors();
	       }
	    }
	 }
	if (readParameterFile (".rciparams", parameterList) < 0)
	 { if (getErrorCode(0) != EBadAccess)
	    { errorMsg (getErrorCode(0), cantReadFileMsg, fxnName);
	      return (-1);	
	    }
	   else
	    { clearErrors();
	    }
	 }

	return (1);
}

static PARAM *findparam (handle, key)
int handle;
const char *key;
{
	PARAM *list = &((PARAMSPEC*)handle)->list;
	PARAM *p;

	for (p = list->next; p != list; p = p->next)
	 { if (strcmp (p->keyword, key) == 0)
	    { return (p);
	    }
	 }
	return (NULL);
}

getparFloat (d, key, handle)
float *d;
int handle;
const char *key;
{
	char *fxnName = "getparFloat()";
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (p = findparam (handle, key))
	 { if (p->type == FLOAT_TYPE)
	    { *d = p->val.d;
	      return (1);
	    }
	   else if (p->type == INTEGER_TYPE)
	    { *d = p->val.i;
	      return (1);
	    }
	   return (-1);
	 }
	return (0);
}

getparInteger (i, key, handle)
int *i;
int handle;
const char *key;
{
	char *fxnName = "getparInteger()";
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (p = findparam (handle, key))
	 { if (p->type == INTEGER_TYPE)
	    { *i = p->val.i;
	      return (1);
	    }
	   return (-1);
	 }
	return (0);
}

getparString (s, key, handle)
char **s;
int handle;
const char *key;
{
	char *fxnName = "getparString()";
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (p = findparam (handle, key))
	 { if (p->type == STRING_TYPE ||
	       p->type == IDENTIFIER_TYPE)
	    { *s = p->val.s;
	      return (1);
	    }
	   return (-1);
	 }
	return (0);
}

getparIdentifier (s, key, handle)
char **s;
int handle;
const char *key;
{
	char *fxnName = "getparIdentifier()";
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (p = findparam (handle, key))
	 { if (p->type == IDENTIFIER_TYPE)
	    { *s = p->val.s;
	      return (1);
	    }
	   return (-1);
	 }
	return (0);
}

static PARAM *setupParam (handle, key)
int handle;
const char *key;
{
	PARAMSPEC *spec = (PARAMSPEC*)handle;
	PARAM *p;

	if (!(p = findparam (handle, key)))
	 { if ((p = ALLOC(PARAM)) == NULL)
	    { return (NULL);
	    }
	   LINK (p, &spec->list);
	 }
	else
	 { if (p->type == IDENTIFIER_TYPE ||
	       p->type == STRING_TYPE)
	    { free (p->val.s);
	    }
	 }
	return (p);
}

setparInteger (i, key, handle)
int i;
int handle;
const char *key;
{
	char *fxnName = "setparInteger()";
	PARAMSPEC *spec = (PARAMSPEC*)handle;
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (!spec->writeable)
	 { return (0);
	 }
	if ((p = setupParam (handle, key)) == NULL)
	 { return (-1);
	 }
	p->type = INTEGER_TYPE;
	p->val.i = i;
	return (1);
}

setparFloat (f, key, handle)
double f;
int handle;
const char *key;
{
	char *fxnName = "setparFloat()";
	PARAMSPEC *spec = (PARAMSPEC*)handle;
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (!spec->writeable)
	 { return (0);
	 }
	if ((p = setupParam (handle, key)) == NULL)
	 { return (-1);
	 }
	p->type = FLOAT_TYPE;
	p->val.d = f;
	return (1);
}

setparString (sval, key, handle)
char *sval;
int handle;
const char *key;
{
	char *fxnName = "setparString()";
	PARAMSPEC *spec = (PARAMSPEC*)handle;
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (!spec->writeable)
	 { return (0);
	 }
	if ((p = setupParam (handle, key)) == NULL)
	 { return (-1);
	 }
	p->type = STRING_TYPE;
	p->val.s = (char *)strcpy((char *)malloc(strlen(sval)+1), sval);
	return (1);
}

setparIdentifier (sval, key, handle)
char *sval;
int handle;
const char *key;
{
	char *fxnName = "setparIdentifier()";
	PARAMSPEC *spec = (PARAMSPEC*)handle;
	PARAM *p;

	if (!planningLevelCheck(fxnName))
	 { return (0);
	 }
	if (!spec->writeable)
	 { return (0);
	 }
	if ((p = setupParam (handle, key)) == NULL)
	 { return (-1);
	 }
	p->type = IDENTIFIER_TYPE;
	p->val.s = (char *)strcpy((char *)malloc(strlen(sval)+1), sval);
	return (1);
}
