/*
 * Copyright (C) 1992 by Gustaf Neumann, Stefan Nusser
 *
 *      Wirtschaftsuniversitaet Wien,
 *      Abteilung fuer Wirtschaftsinformatik
 *      Augasse 2-6,
 *      A-1090 Vienna, Austria
 *      neumann@wu-wien.ac.at, nusser@wu-wien.ac.at
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appears in all copies and that both that
 * copyright notice and this permission notice appear in all supporting
 * documentation.  This software is provided "as is" without expressed or
 * implied warranty.
 *
 * Date: Mon, Apr 13 1992
 * Author: Stefan Nusser, Gustaf Neumann
 * Version: 0.9
 */

#undef NOCALLBACKRESFILE
#define CONVERTERS_C

#include "wafe.h"
#include <X11/Xmu/Converters.h>
#include <X11/Xmu/Drawing.h>
#include <X11/Shell.h>

#define	Done(type, value) \
	{							\
	    if (toVal->addr != NULL) {				\
		if (toVal->size < sizeof(type)) {		\
		    toVal->size = sizeof(type);			\
		    return False;				\
		}						\
		*(type*)(toVal->addr) = (value);		\
	    }							\
	    else {						\
		static type static_val;				\
		static_val = (value);				\
		toVal->addr = (XtPointer)&static_val;		\
	    }							\
	    toVal->size = sizeof(type);				\
	    return True;					\
	}



#include <X11/IntrinsicP.h>

/*
static Boolean
inTree(node,w)
Widget node;
Widget w;
    {
    WidgetList wl;
    Cardinal numChildren = 0;

    if (node == w)
	{
	return True;
	}

    XtVaGetValues(node, 
		  XtNchildren, &wl, 
		  XtNnumChildren, &numChildren,
		  NULL);
    
    for(;numChildren>0;numChildren--, wl++) 
	if (inTree(*wl,w))
	    return True;

    numChildren = node->core.num_popups;
    wl =  node->core.popup_list;

    for(;numChildren>0;numChildren--, wl++) 
	if (inTree(*wl,w))
	    return True;
    
    return False;
    }

Boolean
existingWidget(w)
Widget w;
    {
    WidgetListPtr ptr = wafeWidgetTrees;

#ifdef USECONTEXT
    MMattribListPtr al;
    if (!XFindContext(XtDisplay(w), (XID) w, wafeCtx, (XPointer *) &al)) 
	return True;

   fprintf(stderr, "existingWidget: Did NOT find widget! %p %p %p\n",
     XtDisplay(w), (XID) w, wafeCtx);    
#else
    if (MMgetAttribList(w,False) != NULL)
	return True;
#endif 

    while (ptr) 
	{
	if (inTree(ptr->widget, w))
	    return True;
	ptr = ptr->next;
	}
    return False;
    }

*/


/*****************************************************************************
 *    FUNCTION:  cvtNname2Widget
 *
 *    Arguments: string containing an instance's name, Boolean complain
 *               target widget class, printstring for widget class
 *    Returns:   Widget on success, otherwise NULL
 *
 *    Used by:   nearly all tcl-commands dealing with widgets
 *****************************************************************************/
Widget
wafeCvtName2Widget(name,complain,wClass,classString)
char        *name;
Boolean      complain;
WidgetClass  wClass;
char        *classString;
    {
    Widget result = NULL;
    char  starname[300];
    WidgetListPtr ptr = wafeWidgetTrees;

    if (!name)
	return(NULL);

    if ((*name <= '9' && *name >= '0') || *name == '-')
	{
	char *end;
	if ((result = (Widget)strtol(name,&end,10)))
	    {
/*	    if (existingWidget(result))
		return result;
*/
	    if (XtIsObject(result))
		{
		if (end && *end && end != name)
		    result = XtNameToWidget(result,end);
		}
	    else 
		result = NULL;
	    }
	}
    else 
	{
	*starname = '*';
	strcpy(&starname[1], name);
	while (ptr) 
	    {
	    if ((result = XtNameToWidget(ptr->widget, starname))
                || (result = XtNameToWidget(ptr->widget, name))
	        || (!strcmp((char*)(ptr->info), name) && (result=ptr->widget)))
		break;
	    ptr = ptr->next;
	    }
	}

    if (result) 
	{
	if (wClass) 
	    {
	    if (XtClass(result) == wClass 
		|| (wClass == compositeWidgetClass && XtIsComposite(result))
		|| (wClass == shellWidgetClass && XtIsShell(result))
		)
		return result;
	    else 
		{
		if (complain)
		    fprintf(stderr,
			"Wafe(name2Widget): widget %s is not of class %s\n",
			name, classString);
		return NULL;
		}
	    }
	return result;
	}

    if (complain) 
	fprintf(stderr, 
		"Wafe(name2Widget): could not convert widget reference %s to widget!\n", 
		name);
    return (NULL);
    }





Boolean
CvtStringToWidget(dpy, args, num_args, fromVal, toVal, 
		  converter_data)
Display *dpy;
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal;
XrmValue *toVal;
XtPointer *converter_data;
    {
    Widget w = NULL;
    char *name = (char *)fromVal->addr;

    if (*name && !(w = name2Widget(name)))
	{
	XtDisplayStringConversionWarning(dpy, (String)name, XtRWidget);
	return False;
	}
    else
	Done(Widget, w);
    }


/* convert string to callback: gustaf Sat Jul 11 15:09:12 MET DST 1992 */
Boolean
CvtStringToCallback(dpy, args, num_args, fromVal, toVal,
		    converter_data)
Display *dpy;
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal;
XrmValue *toVal;
XtPointer *converter_data;
    {
    XtCallbackList callback_list;

    char *charp = XtCalloc(
			    sizeof(XtCallbackList)*2 +
			    sizeof(XtCallbackRec[2]) +
			    sizeof(XrmQuark) +
			    strlen((char *)fromVal->addr) + 1,
			    1);

    *(XtCallbackList*)charp = (XtCallbackList)(charp+sizeof(XtCallbackList)*2);
    *(XtCallbackList*)(charp+sizeof(XtCallbackList)) = NULL;
    callback_list = *(XtCallbackList*)charp;
    callback_list->callback = (XtCallbackProc)wafeExecCallbackProc;
    callback_list->closure = 
	charp + sizeof(XtCallbackList)*2 + sizeof(XtCallbackRec[2]);

    /* remembering quark of current resource name to determine the type 
       of resource */

    *(XrmQuark *)callback_list->closure = wafeCurrentAttrib;
    strcpy((char *)callback_list->closure + sizeof(XrmQuark), 
	   (char *)fromVal->addr);

    if (toVal->addr) 
	{
	if (toVal->size < sizeof(XtCallbackList)) 
	    {
	    toVal->size = sizeof(XtCallbackList);
	    XtFree((char *)charp);
	    return False;
	    }
	
	*(XtCallbackList *)(toVal->addr) = callback_list;
	}
    else 
	{
	toVal->addr = (caddr_t)charp;
	wafeMMreplace(wafeCurrentAttribList, 
		      wafeCurrentAttrib, 
		      (char *)charp, XtFree);
	}

    toVal->size = sizeof(XtCallbackList);

/*
    {int i; char *p;
     for(p=charp,i=0; i<=
			    sizeof(XtCallbackList)*2 +
			    sizeof(XtCallbackRec[2]) +
			    sizeof(XrmQuark) +
			    strlen((char *)fromVal->addr) + 1 ;
	 i++,p++) fprintf(stderr,"%x[%c] ",*p & 0xff,*p & 0xff);
       fprintf(stderr,"\n");
   }
*/
    return True;
    }


/* convert string to Pointer: gustaf Sat Jul 11 15:09:12 MET DST 1992 */
Boolean
CvtStringToPointer(dpy, args, num_args, fromVal, toVal,
		   converter_data)
Display *dpy;
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal;
XrmValue *toVal;
XtPointer *converter_data;
    {
    static int argc;
    static char ** argv;
   
    Tcl_SplitList(wafeInterpreter,(char *)fromVal->addr, &argc,&argv);

    if (toVal->addr) 
	{
	if (toVal->size < sizeof(String *)) 
	    {
	    toVal->size = sizeof(String *);
	    XtFree((char *)argv);
	    return False;
	    }
	*(String **)(toVal->addr) = (String *)argv;
	}
    else
	{
	toVal->addr = (caddr_t)&argv;
	wafeMMreplace(wafeCurrentAttribList, wafeCurrentAttrib, 
		      (char *)argv, XtFree);
	}
    toVal->size = sizeof(String *);
    return True;
    }



/* convert string to Pointer: gustaf Sat Jul 11 15:09:12 MET DST 1992 */
Boolean
CvtStringToWidgetList(dpy, args, num_args, fromVal, toVal,
		   converter_data)
Display *dpy;
XrmValue *args;
Cardinal *num_args;
XrmValue *fromVal;
XrmValue *toVal;
XtPointer *converter_data;
    {
    static int argc;
    static char ** argv;
    int i;

    Tcl_SplitList(wafeInterpreter,(char*)fromVal->addr, &argc,&argv);

    for ( i = 0; i < argc; i++ )   
	/* we assume that sizeof(char*) = sizeof(Widget) */
	if (!(argv[i] = (char *) name2Widget(argv[i])))
	    {
	    wafeConvError("stringToWidgetList","n",argv[i],"Widget");
	    return False;
	    }

    toVal->size = sizeof(char **);
    toVal->addr = (caddr_t)&argv;

    wafeMMreplace(wafeCurrentAttribList, wafeCurrentAttrib, 
		  (char *)argv, XtFree);
    return True;
    }


void 
wafeEscapedStrcpy(output, input)
char * output;
char * input;
    {
    char * p = input;

    if (!p) 
      {
	*output = '\0';
	return;
      }

    while (*p) 
	{
	if (*p == '"' || *p == '$' || *p == '[' || *p == '\\' ) 
	    *output++ = '\\';

	*output++ = *p++;
	}

    *output = *p;
    }

char *
wafeCvtWidgetListToList(buffer,num, widgetArray)
char      *buffer;
Cardinal   num;
WidgetList widgetArray;
    {
    int     i;
    char *output;
    if (buffer) 
	{
	output = buffer;
	for (i=0; i<num; i++)
	    {
	    sprintf(output, "%ld ", (long)widgetArray[i]);
	    output += strlen(output);
	    }
	}
    else 
	{
	int offset = 0;
    	int buffersize = 64; 
	buffer = XtMalloc(buffersize);

	for (i=0; i<num; i++)
	    {
	    if ((buffersize-offset) < LONG_AS_STRING) 
		{
		buffersize += 64;
		buffer = XtRealloc(buffer,buffersize);
		}
	    output = buffer+offset;
	    sprintf(output, "%ld ", (long)widgetArray[i]);
	    offset += strlen(output);
	    }
	output = buffer+offset;
	}
    
    if (num>0) *(output-1) = '\0';
    else *output = '\0';
    return buffer;
    }

char *
wafeCvtIntsToTcl(buffer, num, intArray)
char      *buffer;
Cardinal   num;
int       *intArray;
    {
    int     i;
    char *output;
    if (buffer) 
	{
	output = buffer;
	for (i=0; i<num; i++)
	    {
	    sprintf(output, "%d ", intArray[i]);
	    output += strlen(output);
	    }
	}
    else 
	{
	int offset = 0;
    	int buffersize = 64; 
	buffer = XtMalloc(buffersize);

	for (i=0; i<num; i++)
	    {
	    if ((buffersize-offset) < INT_AS_STRING) 
		{
		buffersize += 64;
		buffer = XtRealloc(buffer,buffersize);
		}
	    output = buffer+offset;
	    sprintf(output, "%d ", intArray[i]);
	    offset += strlen(output);
	    }
	output = buffer+offset;
	}
    
    if (num>0) *(output-1) = '\0';
    else *output = '\0';
    return buffer;
    }
          

/*****************************************************************************
 *    FUNCTION:  convert                                                    
 *               Takes attribute/value pairs, both of them strings, and     
 *               constructs a proper X11 Arglist by converting the string   
 *               values to the requested data type.                         
 *                                                                          
 *    Arguments: parent widget                                              
 *               widgetClass of widget                                      
 *               argv and argc (containing the attribute/value pairs)       
 *               A Pointer to an Arglist and an int for passing the result,
 *               the actual widget (if available or NULL)
 *                                                                          
 *    Returns:   1 on success, 0 on error                                   
 *                                                                          
 *    Used by:   setValues, tclWidgetCommand                                
 *****************************************************************************/

int
wafeConvert(parent, wClass, argv, argcp, args, numArgs, widget)
Widget        parent;    
WidgetClass   wClass;    
char        **argv;      
int          *argcp;      
ArgList      *args;                /* RETURN */
int          *numArgs;             /* RETURN */
Widget        widget;
    {
    int               pairNum;  
    ArgList           argPtr;   
    XrmValue          input;    
    XrmValue          output;   
    XrmQuark          Qtype,Qname;
    int               count = 0; 
    int               delayedArgc = 0;
    char           ** returnArgvPtr = argv;
    int               argc = *argcp;
    static MMattribListPtr currentStrInfo;
    
    DBUG_ENTER("convert");

    if (argc == 0)
	{
	/* nothing to convert */
	*numArgs = 0;
	*args =NULL;
	currentStrInfo = Nil(MMattribList);
        wafeCurrentAttribList = &currentStrInfo;
	DBUG_RETURN (1);
	}

    if (argc % 2)
	{
	/* error condition */
	fprintf(stderr, "Wafe(convert): Wrong # of args\n");
        wafeCurrentAttribList = NULL;
	DBUG_RETURN (0);
	}
    
    argPtr = *args = (ArgList)XtMalloc((argc/2)*sizeof(Arg));

    if (widget) 
        {
#ifdef LAZY_GETATTRIB
	wafeCurrentWidget = widget;  
	/*
	   fprintf(stderr,"convert: setting current widget to <%s>\n",XtName(widget));
	 */
	/* wafeCurrentAttribList stays unmodified (normally NULL) */
#else
	wafeCurrentAttribList = wafeMMgetAttribList(widget,True);
	currentStrInfo = *wafeCurrentAttribList;
#endif
        }
    else
        {
	wafeCurrentWidget = (Widget)NULL;
        currentStrInfo = Nil(MMattribList);
        wafeCurrentAttribList = &currentStrInfo;
        }
 
    for (pairNum = 1; pairNum <= argc/2; pairNum++)
	{
	Qname = XrmStringToQuark(*argv); 
	Qtype = wafeGetQTypeOfAttribute(wClass, parent, Qname);

	if(Qtype)
	    { 
	    if ((!widget) && (
		Qtype == qCallback
#ifdef MOTIF11
		|| Qtype == qHorizontalDimension
		|| Qtype == qVerticalDimension 
		|| Qtype == qPrimForegroundPixmap
#endif
	       ))
		{
		/* delaying conversion until widget is created
		 */ 
		*(returnArgvPtr++) = *(argv++);
		*(returnArgvPtr++) = *(argv++);
		delayedArgc += 2;
	        }
            else
                {
		  DBUG_PRINT("conv", ("N: %s, T: %s", 
				      *argv, XrmQuarkToString(Qtype))); 
	    
		  argPtr->name = *argv;         /* Name of attrib */  
		  wafeCurrentAttrib = Qname;    /* Remember quark */
		  input.addr = *(++argv);       /* Den Wert konvertieren.. */
		  input.size = strlen(*argv)+1;
		  output.addr =  NULL;
		  
		  DBUG_PRINT("conv", ("Input: String %s, size %d", 
				      input.addr, input.size));
		  
		  IFCONVERTANDSTORE(widget?widget:parent, "String", input, 
				    XrmQuarkToString(Qtype), output)
		    {
		      DBUG_PRINT("conv", ("Konv OK, Gr: %u", output.size));
		
		      if (Qtype == qString) 
			{
			  argPtr->value = (XtArgVal)XtNewString(output.addr);
			  wafeMMreplace(wafeCurrentAttribList, 
					wafeCurrentAttrib,
					(char *)(argPtr->value), XtFree);
			}
#ifdef MOTIF11
		      else
			if (Qtype == qXmString) 
			  {
			    argPtr->value = (XtArgVal)output.addr;
			  }
#endif
		      else 
			if (output.size == sizeof(int))
			  argPtr->value = (XtArgVal) *(int *)output.addr;
		      else
			if (output.size == sizeof(long))
			  argPtr->value = (XtArgVal) *(long *)output.addr;
		      else
			if (output.size == sizeof(short))
			  argPtr->value = (XtArgVal) *(short *)output.addr;
		      else 
			if (output.size == sizeof(double))
			  {
			    /* we have to copy doubles to allow multiple 
			     * doubles in one widget creation or setValue 
			     * command 
			     */
			    argPtr->value = (XtArgVal)XtMalloc(sizeof(double));
			    *(double *)(argPtr->value) = *(double *)(output.addr);
			    wafeMMreplace(wafeCurrentAttribList, 
					  wafeCurrentAttrib,
					  (char *)(argPtr->value), XtFree);
			  }
		      else 
			if (output.size == sizeof(char))
			  argPtr->value = (XtArgVal) *(char *)output.addr;
		      else
			if (output.size == sizeof(XtArgVal)) 
			  argPtr->value = *(XtArgVal *)output.addr;
		      else
			fprintf(stderr, 
			  "Wafe(convert): converter for StringTo%s returns unreasonable size (%d)\n",
			  XrmQuarkToString(Qtype),output.size);
		      argPtr++; 
		      count++; 
		    }
		  argv++;
		}
	    }
	else 
	    {
	    fprintf(stderr, "Wafe(convert):Attribute unknown: %s\n", *argv);
	    argv += 2; 
	    }
	}

    *argcp = delayedArgc;
    *numArgs = count;
    DBUG_RETURN (1); 
    }


String
wafeTopLevelWidget(w)
Widget w;
    {
    WidgetListPtr ptr;
    
    for(ptr = wafeWidgetTrees; ptr; ptr = ptr->next)
	if (w == ptr->widget)
	    return (String)ptr->info;
    return NULL;
    }

