#define MM_C
#include "wafe.h"
#include <X11/Shell.h>

#undef WIDGETLISTTRACE

#undef USECONTEXT
static WidgetListPtr MMwidgetListHead;

#ifdef USECONTEXT
static XContext wafeCtx = 0;
#endif

/*
 * The following function returnes the address from the corresponding
 * attribute/type list.
 */

extern
freeProc
wafeGetFreeProc (
#if NeedFunctionPrototypes
     XrmQuark
#endif
);


#ifdef WIDGETLISTTRACE
void
printAttributeList(al)
MMattribListPtr al;
    {
    
    while(al)
	{
	fprintf(stderr,"     al = %p\n",al);
	fprintf(stderr,"          attribute = %s\n",
		XrmQuarkToString(al->attribute));
	fprintf(stderr,"          value     = %p <%s>\n",
		al->value, al->value);
	fprintf(stderr,"          next      = %p\n",
		al->next);

	al = al->next;
	}
    }

void
printWidgetList(wl)
WidgetListPtr   wl;
    {
   
    if (!wl) 
	wl = MMwidgetListHead;

    while(wl)
	{
	fprintf(stderr,"  wl = %p\n",wl);
	fprintf(stderr,"       widget = %p %s\n",
		wl->widget, XtName(wl->widget));
	fprintf(stderr,"       info   = %p \n",
		wl->info);
	fprintf(stderr,"       next   = %p \n",
		wl->next);
        printAttributeList(wl->info);
	wl = wl->next;
	fprintf(stderr,"\n");
	}
    }
#endif




void
wafeAddToEndOfWidgetList(wl,w,info)
WidgetListPtr *wl;
Widget         w;
XtPointer      info;
    {
    WidgetListPtr *ptr=wl;
    while (*ptr)
	ptr = &((*ptr)->next);
    *ptr = (WidgetListPtr)XtMalloc(sizeof(WidgetListItem));
    (*ptr)->widget = w;
    (*ptr)->next = NULL;
    (*ptr)->info = info;
/*
   fprintf(stderr,
           "add to end of widgetlist *ptr %p, widget= %p, tree=%p info <%s>\n",
	   *ptr, (*ptr)->widget, wafeWidgetTrees, (char*)((*ptr)->info));
*/
    }

/*
 * when a topLevel widget (typically on a different display) is 
 * deleted, it has to be removed from widgetTrees, which is 
 * used primarily by name2widget
 */
static void
deleteFromWidgetList(wl,w)
WidgetListPtr *wl;
Widget         w;
    {
    WidgetListPtr *ptr=wl;
    WidgetListPtr tmpPtr;
    while (*ptr && (*ptr)->widget != w)
	ptr = &((*ptr)->next);
    if (!*ptr) 
	return;

    XtFree((*ptr)->info);  /* let us assume, info is always mallocated */
    tmpPtr = (*ptr)->next;     

    XtFree((char *)(*ptr));
    *ptr = tmpPtr;
    }






MMattribListPtr *
wafeMMgetAttribList(w, add)
Widget w; 
Boolean add;
    {
    WidgetListPtr   *ptr = &MMwidgetListHead;
    WidgetListPtr   ptrTmp;
#ifdef USECONTEXT
    MMattribListPtr al;
#endif    

    DBUG_ENTER ("MMgetAttribList");

#ifdef USECONTEXT
    if (wafeCurrentAttribList) 
	{
	DBUG_RETURN(wafeCurrentAttribList);
	}
    if (!wafeCtx) 
	wafeCtx = XUniqueContext();

    if(XFindContext(XtDisplay(w), (XID) w, wafeCtx, (XPointer *) &al)) {
          (void) fprintf(stderr, "mmget: cannot find context!\n");
	  DBUG_RETURN((MMattribListPtr *)NULL);
	  }
    
    DBUG_RETURN(&al);
#else
#ifdef WIDGETLISTTRACE
	{
	WidgetListPtr   *tmpPtr = &MMwidgetListHead;
	while (*tmpPtr) 
	    {
	    fprintf(stderr,"  -> widget %s (%p) ist %p, next=%p\n",
		    XtName((*tmpPtr)->widget),
		    (*tmpPtr)->widget,
		    (*tmpPtr)->info,
		    (*tmpPtr)->next);
	    
	    tmpPtr = &(*tmpPtr)->next;
	    }
	printWidgetList(*ptr);
	}
#endif

    if (wafeCurrentAttribList) 
      {
/*
      fprintf(stderr,
	      "MMgetAttribList: returning current Attrib list %p for %p %s\n",
	      wafeCurrentAttribList, w, XtName(w));
*/
      DBUG_RETURN(wafeCurrentAttribList);
      }

    while (*ptr) 
	{
	if ((*ptr)->widget == w) 
	    {
/*
	    fprintf(stderr,"MMgetAttribList: found al %p for widget %p\n",
		    (*ptr)->info,w);
 */
	    DBUG_RETURN((MMattribListPtr*)&((*ptr)->info));
	    }
	ptr = &(*ptr)->next;
	}

    if (!add) 
	{
	DBUG_RETURN(NULL);
	}
    /* not found; add new widgets to the front fo the list */
    
    ptrTmp = MMwidgetListHead;
    MMwidgetListHead = (WidgetListPtr)XtMalloc(sizeof(WidgetListItem));

/*    fprintf(stderr,"MMgetAttribList: new widgetlist at %p, returning %p for %p\n",
	    MMwidgetListHead,&(MMwidgetListHead->info),w);
 */
    MMwidgetListHead->next = ptrTmp;
    MMwidgetListHead->widget = w;
    MMwidgetListHead->info = NULL;
    DBUG_RETURN((MMattribListPtr*)&(MMwidgetListHead->info));
#endif
    }
    
void
wafeMMsetAttribList(w)
Widget w; 
    {
#ifdef USECONTEXT
    if (!wafeCtx) 
	wafeCtx = XUniqueContext();
    XSaveContext(XtDisplay(w), (XID) w, wafeCtx, 
		 (_Xconst char *)*wafeCurrentAttribList);
#else
    WidgetListPtr ptrTmp = MMwidgetListHead;

    MMwidgetListHead = (WidgetListPtr)XtMalloc(sizeof(WidgetListItem));
    MMwidgetListHead->next = ptrTmp;
    MMwidgetListHead->widget = w;
    MMwidgetListHead->info = (XtPointer)*wafeCurrentAttribList;
/*
    fprintf(stderr,"MMset: setting al %p for widget %p <%s>\n",
	    *wafeCurrentAttribList,w,XtName(w));
 */
#endif
    }

char *
wafeMMgetValue(al,descriptor)
MMattribListPtr *al;
XrmQuark         descriptor;
    {
    MMattribListPtr *ptr = al;
    while(*ptr) 
	{

/* fprintf(stderr,"MMgetValue: comparing %s with %s\n",
       XrmQuarkToString(descriptor),
       XrmQuarkToString((*ptr)->attribute));
*/
	if ((*ptr)->attribute == descriptor) 
	    return (*ptr)->value;

	ptr = &((*ptr)->next);
	}
    return NULL;
    }


void
wafeMMreplace(al,descriptor,value,freeFunc)
MMattribListPtr *al;
XrmQuark         descriptor;
char            *value;
freeProc         freeFunc;
    {
    MMattribListPtr *ptr = al;
    DBUG_ENTER("MMreplace");
    
    if (ptr==NULL) 
	{
#ifdef LAZY_GETATTRIB
	if (wafeCurrentAttribList == NULL) 
	    {
/*
	    fprintf(stderr,"MMreplace: returning al of current: %s\n",
                    XtName(wafeCurrentWidget));
 */
	    wafeCurrentAttribList = 
	      wafeMMgetAttribList(wafeCurrentWidget,True);
	    }
		

	ptr = wafeCurrentAttribList;
#else
	DBUG_VOID_RETURN;       /* only for safety in error conditions */
#endif
	}
    
    while(*ptr) 
	{
/*
	fprintf(stderr,"comparing desc %d (%s) and att %d (%s)\n",
		descriptor,XrmQuarkToString(descriptor),
		(*ptr)->attribute,XrmQuarkToString((*ptr)->attribute));
 */

	if ((*ptr)->attribute == descriptor) 
	    {
/*
	    fprintf(stderr,"MMreplace: freeing value %p for <%s> setting %p\n",
		    (*ptr)->value,XrmQuarkToString((*ptr)->attribute),value);
 */
	    (*freeFunc)((*ptr)->value);
	    (*ptr)->value = value;
	    DBUG_VOID_RETURN;
	    }
	ptr = &((*ptr)->next);
	}

    *ptr = (MMattribListPtr)XtMalloc(sizeof(MMattribList));
    (*ptr)->next = NULL;                    
    (*ptr)->attribute = descriptor;
/*
    fprintf(stderr,
            "MMreplace: new attriblistelement %p for %s in al %p, value=%p\n",
	    *ptr,XrmQuarkToString((*ptr)->attribute),al,value);
*/
    (*ptr)->value = value;

#ifdef WIDGETLISTTRACE
   printAttributeList(*ptr);
#endif
    DBUG_VOID_RETURN;
    }
     

/*
 * wafeMMfreeGarbage(widget)
 * frees grabage frames and data 
 * when a widget is deleted
 * gustaf Sat Jul 11 15:09:12 MET DST 1992
 */
Widget
wafeMMfreeGarbage(w)
Widget      w;
    {
    WidgetListPtr    *ptr = &MMwidgetListHead;
    WidgetListPtr     ptrTmp;
    MMattribListPtr   al,alTmp;
    int               count = 0;
    freeProc          wafeFree;

/*    fprintf(stderr,"+++ garbage: freeing garbage for widget <%s>\n",
	    XtName(w));
 */

    if (XtIsComposite(w)) 
	{
	Cardinal numChildren;
	WidgetList children;

	XtVaGetValues(w, 
		      XtNnumChildren, &numChildren,
		      XtNchildren, &children, 
		      NULL);

	while(numChildren) 
	    {
/*
	    fprintf(stderr,"    clearing for %p <%s> child of %p <%s>\n",
		    *children,XtName(*children),w,XtName(w));
 */
	    wafeMMfreeGarbage(*children);
	    numChildren--;
	    children++;        
	    }

	if (XtIsApplicationShell(w))
	    deleteFromWidgetList(&wafeWidgetTrees, w);
	}

/*
    fprintf(stderr,"----------after recursion %p %p\n",MMwidgetListHead,*ptr);
    printWidgetList(*ptr);
 */

#ifdef USECONTEXT
    if(XFindContext(XtDisplay(w), (XID) w, wafeCtx, (XPointer *) &al)) 
	{
	(void) fprintf(stderr, "free garbage: cannot find context!\n");
	}
    while(al) 
	{
/*
        fprintf(stderr,"+++ garbage: attribute=%s freeing value %p\n",
			XrmQuarkToString(al->attribute),al->value);
	fprintf(stderr,"+++ garbage: string = <%s>\n",
			al->value);
 */
	if ((wafeFree = wafeGetFreeProc(al->attribute))) 
	    (wafeFree)(al->value);
 /*
	 fprintf(stderr,"+++ garbage: freeing attribute list %p\n",
			al);
  */
	alTmp = al->next;
	XtFree((char*)al);
	al = alTmp;
	}
    XDeleteContext(XtDisplay(w), (XID) w, wafeCtx);
#else
    while (*ptr) 
	{
/*
   fprintf(stderr,"garbage: widget to delete %p <%s>, actual widget %p <%s>\n",
   (*ptr)->widget,XtName((*ptr)->widget),w,XtName(w));
 */
	if ((*ptr)->widget == w) 
	    {
	    al = (MMattribListPtr)(*ptr)->info;

	    while(al) 
		{
/*
		fprintf(stderr,"+++ garbage: attribute=%s freeing value %p\n",
			XrmQuarkToString(al->attribute),al->value);
		fprintf(stderr,"+++ garbage: string = <%s>\n",
			al->value);
 */
		if ((wafeFree = wafeGetFreeProc(al->attribute))) 
		    (wafeFree)(al->value);
/*
		fprintf(stderr,"+++ garbage: freeing attribute list %p\n",
			al);
 */
		alTmp = al->next;
		XtFree((char*)al);
		al = alTmp;
		}

/*	 fprintf(stderr,"garbage: freeing widgetlist %p\n", *ptr);*/
	    ptrTmp = (*ptr)->next; 
	    XtFree((char*)*ptr);
	    *ptr = ptrTmp;
	    break;
	    }
	ptr = &(*ptr)->next;
	count++;
	}
#endif
/*
    fprintf(stderr,"counting %d frames\n", count);
 */
    return w;
    }

