/*****************************************************************************
* 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"

/*****************************************************************************
*   Routine to set an integer attribute.				     *
*****************************************************************************/
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;
    }
}

/*****************************************************************************
*   Routine to get an integer attribute.				     *
*****************************************************************************/
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;
}

/*****************************************************************************
*   Routine to set a pointer attribute.					     *
*****************************************************************************/
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;
    }
}

/*****************************************************************************
*   Routine to get a pointer attribute.					     *
*****************************************************************************/
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;
}

/*****************************************************************************
*   Routine to set a real attribute.					     *
*****************************************************************************/
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;
    }
}

/*****************************************************************************
*   Routine to get a real attribute from an object.			     *
*****************************************************************************/
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;
}

/*****************************************************************************
*   Routine to set a string attribute.					     *
*****************************************************************************/
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;
    }
}

/*****************************************************************************
*   Routine to get a string attribute.					     *
*****************************************************************************/
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;
}

/*****************************************************************************
*   Routine to scan a list of attributes. If TraceAttrs != NULL, a ptr to    *
* its attribute list is saved and the next attribute is returned every call  *
* until the end of the list is reached, in which NULL is returned.	     *
*   TraceAttrs should be NULL in all but the first call in the sequence.     *
*   Attributes with names starting with an underscore '_' are assumed to be  *
* temporary or internal and are skipped.				     * 
*****************************************************************************/
IPAttributeStruct *AttrTraceAttributes(IPAttributeStruct *TraceAttrs)
{
    static IPAttributeStruct
	*Attrs = NULL;

    if (TraceAttrs != NULL)
	Attrs = TraceAttrs;

    while (Attrs) {
	if (Attrs -> Name[0] != '_') {
	    IPAttributeStruct
	        *RetVal = Attrs;

	    Attrs = Attrs -> Pnext;
	    return RetVal;
	}
	else
	    Attrs = Attrs -> Pnext;
    }

    return NULL;
}

/*****************************************************************************
*   Routine to convert an attribute to a string.			     *
*****************************************************************************/
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 %lg]", 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
	        sprintf(Str, "[%s \"%s\"]", Attr -> Name, Attr -> U.Str);
	    break;
	case IP_ATTR_OBJ:
	case IP_ATTR_PTR:
	    break;
	default:
	    IritFatalError("Undefined attribute type");
	    break;
    }

    return Str;
}

/*****************************************************************************
*   Routine to initialize the Attributes of the given Attr list.	     *
*****************************************************************************/
void AttrResetAttributes(IPAttributeStruct **Attrs)
{
    *Attrs = NULL;
}

/*****************************************************************************
*   Routine to search for an attribute by name.				     *
*****************************************************************************/
IPAttributeStruct *AttrFindAttribute(IPAttributeStruct *Attrs, char *Name)
{
    for (; Attrs != NULL; Attrs = Attrs -> Pnext)
	if (stricmp(Name, Attrs -> Name) == 0)
	    return Attrs;

    return NULL;
}

/*****************************************************************************
*   Routine to set the color of an object.				     *
*****************************************************************************/
IPAttributeStruct *_AttrMallocAttribute(char *Name, IPAttributeType Type)
{
    IPAttributeStruct
	*Attr = (IPAttributeStruct *) IritMalloc(sizeof(IPAttributeStruct));

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

    return Attr;
}

/*****************************************************************************
*   Routine to release attribute named Name from the given Attr list.	     *
*****************************************************************************/
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;
	    }
	}
    }
}

/*****************************************************************************
*   Routine to release all attributes of the given Attr list.		     *
*****************************************************************************/
void AttrFreeAttributes(IPAttributeStruct **Attrs)
{
    IPAttributeStruct
	*Attr = *Attrs;

    while (Attr) {
    	IPAttributeStruct
	    *Next = Attr -> Pnext;

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

    *Attrs = NULL;
}
