/*
 * 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.96
 */

#define CREATEW_C

#include "wafe.h"

/*
 * #include <X11/IntrinsicP.h>
 * #include <X11/CoreP.h>
 */


/*
 * The following struct is used to pass information to the widget 
 * generating tcl-command: Which WidgetClass to use and which function 
 * to generate the instance!
 */


typedef struct 
    {
    WidgetClass  wClass;
    Widget       (*wCreateFunction)();
    Boolean      createsShell;
    } wComInfo, *wComInfoPtr;


static int
tclWidgetCommand(clientData, comInterpreter, argc, argv)
ClientData   clientData;
Tcl_Interp  *comInterpreter;
int          argc;
char       **argv;
    {
    Widget         father, newWidget;
    WidgetClass    wClass;
    Widget         (*wCreateFunction)();
    char          *name;
    char          *widgetTyp;
    ArgList        args;
    int            numArgs;
    char           *displayString = NULL;
    Boolean        managed = True,
                   freeArgv = False,
                   mustManuallyManage = False;
    static char intBuffer[INT_AS_STRING];

    DBUG_ENTER("tclWidgetCommand");

    widgetTyp = *argv;
    name = *(++argv);

    if (!name || !*name || (*name <= '9' && *name >= '0') ||
	*name == '-' || *name == '*' || *name == '.')
	{
	fprintf(stderr, 
		"Wafe: Widget name should start with an alphabetic character: <%s>!\n", 
		name);
	}

    wClass = ((wComInfoPtr)clientData)->wClass;
    wCreateFunction = ((wComInfoPtr)clientData)->wCreateFunction;
    argv++;
    

    /* will open shell on a different display */
    if (wCreateFunction == XtAppCreateShell)
	displayString = *argv;
    else 
	if ((((wComInfoPtr)clientData)->createsShell))
	    /* if we create a shell, the parent can be of any class */
	    {
	    if (!(father = name2Widget(*argv)))
		DBUG_RETURN(TCL_ERROR);
	    }
	else
	    /* parent must be composite */
	    {
	    if (!(father = name2WidgetOfClass(*argv,
					      compositeWidgetClass,
					      "Composite")))
		DBUG_RETURN(TCL_ERROR);
	    }
    
    argc-=3;    
    argv++;

    if (argc)
	{
	/* Enter if creation of unmanaged widget... */ 
	if (!strcmp(*argv, "unmanaged"))
	    {
	    argv++; argc--;
	    managed = False;
	    }

	/* Check whether an attribute-value list was given
         * and replace argc and argv if so
         */
	if (argc == 1) 
	    if (wafeMergeArguments(*argv,widgetTyp,&argc,&argv))
		freeArgv = True;

	/* argc must now be even  
	 */
	if (argc % 2)
	    {
#ifdef RETURN_EMSG
	    char errorBuffer[200];
	    sprintf(errorBuffer, 
		    "Wrong # of args (%d) in %s %s widget %s", 
		    argc+3, managed? "managed": "unmanaged", widgetTyp, name);
	    Tcl_SetResult(wafeInterpreter, errorBuffer, TCL_VOLATILE);
#else
	    fprintf(stderr,
		    "Wafe(%s): Wrong # of args (%d) in %s widget %s\n", 
		    widgetTyp, argc+3, managed? "managed": "unmanaged", name);
#endif
	    DBUG_RETURN (TCL_ERROR);
	    }
	}

    
    if (wafeConvert(father, wClass, argv, &argc, &args, &numArgs, NULL))
	{
	if (wCreateFunction == NULL) /*no special create procedure used*/
	    {
	    newWidget = (managed ? XtCreateManagedWidget : XtCreateWidget)
		(name, wClass, father, args, numArgs);
	    }
	else 
	if (wCreateFunction == XtCreatePopupShell) 
	    {
	    newWidget = XtCreatePopupShell(name,wClass,father,args,numArgs);
	    MOTIF_EDITRES_HANDLER(newWidget);
	    if (!managed)
		fprintf(stderr, 
	     	    "Wafe(%s): Warning: can't create unmanaged shell; shell is managed\n", 
		     widgetTyp);
	    }
	else
	if (wCreateFunction == XtAppCreateShell) 
	    {
       	    Display *dpy;
#ifdef PRER5
	    Cardinal null = 0;
	    Cardinal *argc = &null;
#else
	    int null = 0;
	    int *argc = &null;
#endif

	    dpy = XtOpenDisplay(wafeAppContext,displayString, 
				Nil(char), Nil(char), 
				Nil(XrmOptionDescRec), 0, 
				argc, Nil(String));
	    if (dpy == NULL) 
	         {
#ifdef RETURN_EMSG
		 char errorBuffer[200];
		 sprintf(errorBuffer,
			 "Wafe(%s): cannot open display <%s>",
			 widgetTyp, displayString);
		 Tcl_SetResult(wafeInterpreter, errorBuffer, TCL_VOLATILE);
#else    
		 fprintf(stderr, "Wafe(%s): cannot open display <%s>\n",
			 widgetTyp, displayString);
#endif
		 DBUG_RETURN (TCL_ERROR);
	         }
	    newWidget = XtAppCreateShell(XtName(wafeTopLevel), 
					 wafeAppClass, wClass, dpy, 
					 args, numArgs);
	    wafeAddToEndOfWidgetList(&wafeWidgetTrees, 
				     newWidget, XtNewString(name));
	    MOTIF_EDITRES_HANDLER(newWidget);
	    if (!managed)
	      fprintf(stderr, 
		      "Wafe(%s): Warning: cannot create unmanaged shell; shell is managed\n", widgetTyp);
	    }
	else
	if (wCreateFunction == WafeDontManage) 
	    {
	    XtCreateWidget(name, wClass, father, args, numArgs);
	    }
        else
	    {
	    /* Use function pointer to create widget */
	    newWidget = (*wCreateFunction)(father, name, args, numArgs);
	    /* delay manage until all resources are set */
	    mustManuallyManage = managed; 

	    /* these commands create as a side effect a parent shell */
	    if ((((wComInfoPtr)clientData)->createsShell))
	        {
		MOTIF_EDITRES_HANDLER(XtParent(newWidget));
	        }
	}


	wafeMMsetAttribList(newWidget); /*set attriblist(newWidget) = wafeCurrentAttribList) */

/* 
    the only place where we could hide the attribListptr in
    the widget structure is the name 
 
	    {static int dummy;
             char *p;	     
	     dummy= ((strlen(newWidget -> core.name)+5) / 4)*4;

	     fprintf(stderr,"w= <%s> len = %d, pos = %d\n",
		     newWidget->core.name, strlen(newWidget->core.name), dummy);
	     p = XtMalloc(dummy+sizeof(XtPointer));
	     strcpy(p,newWidget->core.name);
	     newWidget->core.name = p;
	     *(p+dummy) = (char *)*wafeCurrentAttribList;
	    }
*/


#ifdef WIDGETLISTTRACE
	fprintf(stderr,"----------------------------\n");
	printWidgetList(NULL);
#endif
	
	DBUG_PRINT("widgets", ("Created %s %s widget <%s> [%p]", 
			       managed? "managed": "unmanaged",
			       widgetTyp, name, newWidget));
	XtFree((char*)args);

	/*
	 * now convert attributes that need the real widget 
         */
	if (argc>0) 
	    {
	    if (wafeConvert(father, wClass, argv, &argc, 
			    &args, &numArgs, newWidget))
		{
		XtSetValues(newWidget, args, numArgs);
		XtFree((String)args);
		}
	    }
	if (mustManuallyManage && XtIsRectObj(newWidget)) 
	    XtManageChild(newWidget);

	wafeCurrentAttribList = NULL;
	sprintf(intBuffer,"%ld",(long)newWidget);
	Tcl_SetResult(wafeInterpreter,intBuffer,TCL_STATIC);
	DBUG_RETURN(TCL_OK);
	}
	
    wafeCurrentAttribList = NULL;
#ifdef RETURN_EMSG
	{
	char errorBuffer[200];
	sprintf(errorBuffer,
		"Couldn't create %s %s widget named <%s>", 
		managed? "managed": "unmanaged",
		widgetTyp, name); 
	Tcl_SetResult(wafeInterpreter, errorBuffer, TCL_VOLATILE);
	}
#else    
    fprintf(stderr, "Wafe: Couldn't create %s %s widget named <%s>\n", 
	    managed? "managed": "unmanaged",
	    widgetTyp, name);
#endif
    XtFree((char*)args);
    if (freeArgv) XtFree((char *)argv);
    DBUG_RETURN(TCL_ERROR);
    }
       
static int
warningCommand(clientData, comInterpreter, argc, argv)
ClientData   clientData;
Tcl_Interp  *comInterpreter;
int          argc;
char       **argv;
    {
    wafeFatal((char *)clientData,
            "This command is not available in your configuration", NULL);
    return(TCL_OK);
    }

void 
wafeCreateWidgetCommand(command, wClass, wCreateFunction, createsShell)
char *command;
WidgetClass wClass;
Widget (*wCreateFunction)();
Boolean createsShell;
    {
    wComInfoPtr  wInfoPtr;

    DBUG_ENTER("wafeCreateWidgetCommand");

    if (!wClass)
	{
	Tcl_CreateCommand(wafeInterpreter, command, 
			  warningCommand, (ClientData) command, NULL);
	DBUG_PRINT("widgets",("Warning command %s created", command));
	DBUG_VOID_RETURN;
	}

    XtInitializeWidgetClass(wClass); 

    wInfoPtr = (wComInfoPtr)XtMalloc(sizeof(wComInfo));
    wInfoPtr->wClass = wClass;
    wInfoPtr->wCreateFunction = wCreateFunction;
    wInfoPtr->createsShell = createsShell;

    Tcl_CreateCommand(wafeInterpreter, command, 
		      tclWidgetCommand, (ClientData)wInfoPtr, NULL);

    DBUG_PRINT("widgets",("Command %s created", command));
    DBUG_VOID_RETURN;
    }
