/*****************************************************************************
* Setting attributes for objects.					     *
*									     *
* Written by:  Gershon Elber				Ver 0.2, Mar. 1990   *
*****************************************************************************/

#include <string.h>
#include <stdio.h>
#include <math.h>
#include "irit_sm.h"
#include "imalloc.h"
#include "miscattr.h"

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to set an integer attribute.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:     Attribute list where to place new attribute.                  M
*   Name:      Name of thely introducedattribute                             M
*   Data:      Ingeter attribute to save.                                    M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrSetIntAttrib, attributes                                             M
*****************************************************************************/
void AttrSetIntAttrib(IPAttributeStruct **Attrs, char *Name, int Data)
{
    IPAttributeStruct
        *Attr = AttrFindAttribute(*Attrs, Name);
    
    if (Attr) {
	_AttrFreeAttributeData(Attr);
	Attr -> U.I = Data;
	Attr -> Type = IP_ATTR_INT;
    }
    else {
	Attr = _AttrMallocAttribute(Name, IP_ATTR_INT);
	Attr -> U.I = Data;
	Attr -> Pnext = *Attrs;
	*Attrs = Attr;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to get an integer attribute.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:    Attribute list to search for requested attribute.              M
*   Name:     Name of requested attribute.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:      Found attribute, or IP_ATTR_BAD_INT if not found.              M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrGetIntAttrib, attributes                                             M
*****************************************************************************/
int AttrGetIntAttrib(IPAttributeStruct *Attrs, char *Name)
{
    IPAttributeStruct
	*Attr = AttrFindAttribute(Attrs, Name);

    if (Attr != NULL) {
	if (Attr -> Type == IP_ATTR_INT)
	    return Attr -> U.I;
	else if (Attr -> Type == IP_ATTR_REAL)
	    return (int) Attr -> U.R;
	else if (Attr -> Type == IP_ATTR_STR)
	    return atoi(Attr -> U.Str);
    }

    return IP_ATTR_BAD_INT;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to set a pointer attribute.		 			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:     Attribute list where to place new attribute.                  M
*   Name:      Name of thely introducedattribute                             M
*   Data:      Pointer attribute to save.                                    M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrSetPtrAttrib, attributes                                             M
*****************************************************************************/
void AttrSetPtrAttrib(IPAttributeStruct **Attrs, char *Name, VoidPtr Data)
{
    IPAttributeStruct
        *Attr = AttrFindAttribute(*Attrs, Name);

    if (Attr) {
	_AttrFreeAttributeData(Attr);
	Attr -> U.Ptr = Data;
	Attr -> Type = IP_ATTR_PTR;
    }
    else {
	Attr = _AttrMallocAttribute(Name, IP_ATTR_PTR);
	Attr -> U.Ptr = Data;
	Attr -> Pnext = *Attrs;
	*Attrs = Attr;
    }
}
/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to get a pointer attribute.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:    Attribute list to search for requested attribute.              M
*   Name:     Name of requested attribute.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   VoidPtr: Found attribute, or NULL if not found. 		             M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrGetPtrAttrib, attributes                                             M
*****************************************************************************/
VoidPtr AttrGetPtrAttrib(IPAttributeStruct *Attrs, char *Name)
{
    IPAttributeStruct
	*Attr = AttrFindAttribute(Attrs, Name);

    if (Attr != NULL && Attr -> Type == IP_ATTR_PTR)
        return Attr -> U.Ptr;
    else
        return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to set a RealType attribute.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:     Attribute list where to place new attribute.                  M
*   Name:      Name of thely introducedattribute                             M
*   Data:      RealType attribute to save.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrSetRealAttrib, attributes                                            M
*****************************************************************************/
void AttrSetRealAttrib(IPAttributeStruct **Attrs, char *Name, RealType Data)
{
    IPAttributeStruct
        *Attr = AttrFindAttribute(*Attrs, Name);
    
    if (Attr) {
	_AttrFreeAttributeData(Attr);
	Attr -> U.R = Data;
	Attr -> Type = IP_ATTR_REAL;
    }
    else {
	Attr = _AttrMallocAttribute(Name, IP_ATTR_REAL);
	Attr -> U.R = Data;
	Attr -> Pnext = *Attrs;
	*Attrs = Attr;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to get a RealType attribute.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:    Attribute list to search for requested attribute.              M
*   Name:     Name of requested attribute.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   RealType: Found attribute, or IP_ATTR_BAD_REAL if not found.             M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrGetRealAttrib, attributes                                            M
*****************************************************************************/
RealType AttrGetRealAttrib(IPAttributeStruct *Attrs, char *Name)
{
    IPAttributeStruct
	*Attr = AttrFindAttribute(Attrs, Name);

    if (Attr != NULL) {
	if (Attr -> Type == IP_ATTR_REAL)
	    return Attr -> U.R;
	else if (Attr -> Type == IP_ATTR_INT)
	    return (RealType) Attr -> U.I;
	else if (Attr -> Type == IP_ATTR_STR)
	{
	    RealType r;

	    sscanf("%lf", Attr -> U.Str, &r);
	    return r;
	}
    }

    return IP_ATTR_BAD_REAL * 10;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to set a string attribute.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:     Attribute list where to place new attribute.                  M
*   Name:      Name of thely introducedattribute                             M
*   Data:      String attribute to save.                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrSetStrAttrib, attributes                                             M
*****************************************************************************/
void AttrSetStrAttrib(IPAttributeStruct **Attrs, char *Name, char *Data)
{
    IPAttributeStruct
        *Attr = AttrFindAttribute(*Attrs, Name);

    if (Attr) {
	_AttrFreeAttributeData(Attr);
	Attr -> U.Str = IritStrdup(Data);
	Attr -> Type = IP_ATTR_STR;
    }
    else {
	Attr = _AttrMallocAttribute(Name, IP_ATTR_STR);
	Attr -> U.Str = IritStrdup(Data);
	Attr -> Pnext = *Attrs;
	*Attrs = Attr;
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to get a string attribute.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:    Attribute list to search for requested attribute.              M
*   Name:     Name of requested attribute.                                   M
*                                                                            *
* RETURN VALUE:                                                              M
*   char *:   Found attribute, or NULL if not found.   		             M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrGetStrAttrib, attributes                                             M
*****************************************************************************/
char *AttrGetStrAttrib(IPAttributeStruct *Attrs, char *Name)
{
    IPAttributeStruct
	*Attr = AttrFindAttribute(Attrs, Name);

    if (Attr != NULL && Attr -> Type == IP_ATTR_STR)
        return Attr -> U.Str;
    else
        return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to aid in scanning a list of attributes.                           M
*   If TraceAttrs != NULL, a ptr to its attribute list is saved and the      M
* next attribute is returned every call until the end of the list is         M
* reached, in which NULL is returned.                                        M
*   FirstAttrs should be NULL in all but the first call in the sequence.     M
*   Attributes with names starting with an underscore '_' are assumed to be  M
* temporary or internal and are skipped.				     M 
*                                                                            *
* PARAMETERS:                                                                M
*   TraceAttrs:    If not NULL, contains the previously returned attribute.  M
*   FirstAttrs:    First attribute in list, usually NULL in all but the      M
*                  first invokation in a psuence.			     M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPAttributeStruct *:  Next attribute in list.                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrTraceAttributes, attributes                                          M
*****************************************************************************/
IPAttributeStruct *AttrTraceAttributes(IPAttributeStruct *TraceAttrs,
				       IPAttributeStruct *FirstAttrs)
{
    if (FirstAttrs != NULL)
	TraceAttrs = FirstAttrs;
    else if (TraceAttrs != NULL)
	TraceAttrs = TraceAttrs -> Pnext;
    else
	return NULL;

    while (TraceAttrs) {
	if (TraceAttrs -> Name[0] != '_') {
	    return TraceAttrs;
	}
	else
	    TraceAttrs = TraceAttrs -> Pnext;
    }

    return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to convert an attribute to a string.			     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attr:      To convert to a string.                                       M
*                                                                            *
* RETURN VALUE:                                                              M
*   char *:    A pointer to a static string representing/describing the      M
*              given attribute.						     M
*                                                                            *
* KEYWORDS:                                                                  M
*   Attr2String, attributes                                                  M
*****************************************************************************/
char *Attr2String(IPAttributeStruct *Attr)
{
    static char Str[LINE_LEN_LONG];

    Str[0] = 0;

    switch (Attr -> Type) {
	case IP_ATTR_INT:
	    sprintf(Str, "[%s %d]", Attr -> Name, Attr -> U.I);
	    break;
	case IP_ATTR_REAL:
	    sprintf(Str, "[%s %g]", Attr -> Name, Attr -> U.R);
	    break;
	case IP_ATTR_STR:
	    if (strchr(Attr -> U.Str, '"') != NULL) {
		/* Need to escape the quotes. */
	        int i, j;

		sprintf(Str, "[%s \"", Attr -> Name);

		/* Need to quote the string or escape the internal " */
		for (i = j = 0; i < strlen(Attr -> U.Str); i++) {
		    if (Attr -> U.Str[i] == '"')
			Str[j++] = '\\';
		    Str[j++] = Attr -> U.Str[i];
		}
		Str[j] = 0;
		strcat(Str, "\"]");
	    }
	    else if (strlen(Attr -> U.Str) > 0)
	        sprintf(Str, "[%s \"%s\"]", Attr -> Name, Attr -> U.Str);
	    else
		sprintf(Str, "[%s]", Attr -> Name);
	    break;
	case IP_ATTR_OBJ:
	    sprintf(Str, "[%s _OBJ_ATTR_NOT_CNVRTED_]", Attr -> Name);
	    break;
	case IP_ATTR_PTR:
	    sprintf(Str, "[%s _PTR_ATTR_NOT_CNVRTED_]", Attr -> Name);
	    break;
	default:
	    IritFatalError("Undefined attribute type");
	    break;
    }

    return Str;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to initialize the attributes of the given Attr list.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:   To initialize.                                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrResetAttributes, attributes                                          M
*****************************************************************************/
void AttrResetAttributes(IPAttributeStruct **Attrs)
{
    *Attrs = NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to search for an attribute by Name.				     M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:    Attribute list to search.                                      M
*   Name:     Attribute to search by this name.                              M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPAttributeStruct *:  Attribute if found, otherwise NULL.                M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrFindAttribute, attributes                                            M
*****************************************************************************/
IPAttributeStruct *AttrFindAttribute(IPAttributeStruct *Attrs, char *Name)
{
    for (; Attrs != NULL; Attrs = Attrs -> Pnext)
	if (stricmp(Name, Attrs -> Name) == 0)
	    return Attrs;

    return NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Allocated a new attribute structure.                                       *
*                                                                            *
* PARAMETERS:                                                                *
*   Name:   Name of newly created attribute.                                 *
*   Type:   Type of newly created attribute.                                 *
*                                                                            *
* RETURN VALUE:                                                              *
*   IPAttributeStruct *:  The newly created attribute.                       *
*****************************************************************************/
IPAttributeStruct *_AttrMallocAttribute(char *Name, IPAttributeType Type)
{
    IPAttributeStruct
	*Attr = (IPAttributeStruct *) IritMalloc(sizeof(IPAttributeStruct));

    Attr -> Type = Type;
    Attr -> Name = IritStrdup(Name);
    Attr -> Pnext = NULL;

    return Attr;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to remove and delete the attribute named Name from the given       M
* Attr list.                                                                 M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:   To search for an attribute named Name and remove and delete it. M
*   Name:    Name of attribute to remove and delete.                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrFreeOneAttribute, attributes                                         M
*****************************************************************************/
void AttrFreeOneAttribute(IPAttributeStruct **Attrs, char *Name)
{
    IPAttributeStruct *TmpAttr,
	*Attr = *Attrs;

    if (Attr) {
	if (stricmp(Name, Attr -> Name) == 0) {
	    /* It is the first one - delete first in list. */
	    *Attrs = Attr -> Pnext;
	    Attr -> Pnext = NULL;
	    AttrFreeAttributes(&Attr);
	}
	else {
	    /* Search the rest of the list and delete if found. */
	    while (Attr -> Pnext != NULL) {
		if (stricmp(Name, Attr -> Pnext -> Name) == 0) {
		    TmpAttr = Attr -> Pnext;
		    Attr -> Pnext = TmpAttr -> Pnext;
		    TmpAttr -> Pnext = NULL;
		    AttrFreeAttributes(&TmpAttr);
		}
		else
		    Attr = Attr -> Pnext;
	    }
	}
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Routine to remove anddelete all attributes of the given Attr list.         M
*                                                                            *
* PARAMETERS:                                                                M
*   Attrs:   To remove and delete.                                           M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrFreeAttributes, attributes                                           M
*****************************************************************************/
void AttrFreeAttributes(IPAttributeStruct **Attrs)
{
    IPAttributeStruct *Attr;

    if (*Attrs == NULL)
	return;

    for (Attr = *Attrs; Attr != NULL; ) {
    	IPAttributeStruct
	    *Next = Attr -> Pnext;

	_AttrFreeAttributeData(Attr);
	IritFree((VoidPtr) Attr -> Name);
	IritFree((VoidPtr) Attr);
	Attr = Next;
    }

    *Attrs = NULL;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Routine to copy an attribute list.					     M
*                                                                            *
* PARAMETERS:                                                                M
*   Src:       Attribute list to duplicate.                                  M
*                                                                            *
* RETURN VALUE:                                                              M
*   IPAttributeStruct *:   Duplicated attribute list.                        M
*                                                                            *
* KEYWORDS:                                                                  M
*   AttrCopyAttributes,attributes                                            M
*****************************************************************************/
IPAttributeStruct *AttrCopyAttributes(IPAttributeStruct *Src)
{
    IPAttributeStruct
	*DestAttr = NULL,
	*Dest = NULL;

    for ( ; Src != NULL; Src = Src -> Pnext) {
	if (Src -> Name[0] == '_')       /* Do not copy internal attributes. */
	    continue;

	if (Dest == NULL) {	
	    Dest = DestAttr = AttrCopyOneAttribute(Src);
	}
	else {
	    DestAttr -> Pnext = AttrCopyOneAttribute(Src);

	    DestAttr = DestAttr -> Pnext;
	}
    }

    return Dest;
}
