#include <stdarg.h>
#include "guiobj.h"
#include "struc/llistobj.h"
#include "struc/iterator.h"

@implementation WDCGUIObject

- free
{
  id iter;
  [self unManage];
  XtFree(_widget);
  iter=[[WDCListIterator alloc] initFrom:_childrenList];
  while ([iter goNext]) [[[iter getCurrentObject] getContent] free];
  [_childrenList free];
  XtFree(_arglist);
}

- initWithName:(char*)aName managedBy:anObject
{
  [self setWidget:XtCreateManagedWidget(aName,
					[self getWidgetClass],
					[anObject getWidget],
	      				[self getArgList], 
					[self getNumArgs])];
  [self setParentObject:anObject];
  return [self setAction];
}

- setWidget:(Widget)aWidget
{
  _widget=aWidget;
  return self;
}

- (Widget)getWidget
{
  return _widget;
}

- setParentObject:anObject
{
  if (!_parentObject)
    {
      _parentObject=anObject;
      if ([anObject respondsTo:@selector(setChildObject:)])
	[_parentObject setChildObject:self];
    }
  return self;
}

- getParentObject
{
  return _parentObject;
}

- getRootParentObject
{
  id root;
  if (!_parentObject)
    root=self;
  else
    root=[_parentObject getRootParentObject];
  return root;
}

- getShellObject
{
  id shell;
  if (XtIsShell([self getWidget]))
    shell=self;
  else
    shell=[_parentObject getShellObject];
  return shell;
}

- getTopShellObject
{
  return [self getRootParentObject];
}

- getApplicationObject
{
  return [self getRootParentObject];
}

- (XtAppContext)getApplicationContext
{
  return XtWidgetToApplicationContext([self getWidget]);
}

- (Display*)getDisplay
{
  return XtDisplay([[self getApplicationObject] getWidget]);
}

- (Window)getWindow
{
  return XtWindow([self getWidget]);
}

- (WidgetClass)getWidgetClass
{
  [self subclassResponsibility:_cmd];
  return 0;
}

- setChildObject:anObject
{
  if (!_childrenList) _childrenList=[WDCLListOfObject alloc];
  [_childrenList addContent:anObject];
  if ([anObject respondsTo:@selector(setParentObject:)])
    [anObject setParentObject:self];
  return self;
}

- getChildObject
{
  return [_childrenList getContent];
}

- getChildObjectNamed:(char*)aName
{
  id retval, object, iter;
  SEL aSel;
  iter=[[WDCListIterator alloc] initFrom:[self getChildren]];
  while ([iter goNext])
    {
      aSel=@selector(getName);
      object=[iter getCurrentObject];
      if ([object respondsTo:aSel] && 
	  !strcmp(aName, (char*)[object perform:aSel]))
	{
	  retval=object;
	  break;
	}
    }
  return retval; 
}

- getChildren
{
  return _childrenList;
}

- (char*)getActionMessage
{
  return _actionMessage;
}

- getArg:(char *)name into:(void *)value
{
  Widget w;
  if (w=[self getWidget]) {
    XtVaGetValues(w, name, value, NULL);
  } else {
    fprintf(stderr,"GUIObject: no widgetid in getarg\n");
  }
  return self;
}

- (char*)getArgValue:(char*)name
{
  // this method does not work yet. So, don't use it.
  char* value;
  [self getArg:name into:&value];
  return value;
}

- setCallData:(XtPointer)call_data
{
  return [self subclassResponsibility:_cmd]; 
}

- setAction
{
  return [self subclassResponsibility:_cmd];
}
  
- setArg:(char*)name to:(char*)value
{
  if ([self getWidget]) {
    XtVaSetValues([self getWidget], name, value, NULL);
  } else {
    [self addArg:name with:value];
  }
  return self;
}

- setActionMessage:(char*)message,...
{
  va_list alist;
  id object;
  if (_actionMessage)
    free(_actionMessage);
  _actionMessage=(char*)malloc(strlen(message)+1);
  strcpy(_actionMessage, message);
  va_start(alist, message);
  // object=va_arg(alist, id);
  [self setActionMessageReceiver : va_arg(alist, id)];
  [self setActionMessageObject1 : va_arg(alist, id)];
  [self setActionMessageObject2 : va_arg(alist, id)];
  va_end(alist);
  return self;
}

- setActionMessage:(char*)message withReceiver:receiver
{
  return [self setActionMessage:message,receiver,0];
}

- setActionMessage:(char*)message withReceiver:receiver passObject:object
{
  return [self setActionMessage:message,receiver, object, 0];
}

- setActionMessage:(char*)message 
 withReceiver:receiver passObject:object1 and:object2
{
  return [self setActionMessage:message,receiver, object1, object2, 0];
}
  
- setActionMessageReceiver : object
{
  _actionMessageReceiver=object;
  return self;
}

- setActionMessageObject1 : object
{
  _actionMessageObject1=object;
  return self;
}

- setActionMessageObject2 : object
{
  _actionMessageObject2=object;
  return self;
}

- getActionMessageReceiver
{
  return _actionMessageReceiver;
}

- getActionMessageObject1
{
  return _actionMessageObject1;
}

- getActionMessageObject2
{
  return _actionMessageObject2;
}

- (Arg*)getArgList
{
  return _arglist;
}

- (int)getNumArgs
{
  return _numargs;
}

- addArg:(char *)name with:(char *)value
{
  Arg *args = _arglist;
  if (++_numargs > _allocedargs ) {
    _allocedargs = (_allocedargs) ? 2*_allocedargs : 10;
    /* XtRealloc handles error checking and calling malloc if args
       is NULL  */ 
    args = _arglist = (Arg*)XtRealloc(_arglist, (_allocedargs)*sizeof(Arg));
  }
  args[_numargs-1].name = (char *)name;
  args[_numargs-1].value = (XtArgVal)value;
  return self;
}

- doAction
{
  /* This is the default behavior of "doAction" that will be triggered
     from a XtCallbackFunc. You can redifine it if you think this is not 
     very efficient and do not need a dynamic doAction behavior.
     This method depends on the "setActionMessage" method to setup the
     desired action to be taken.
     */
  SEL aSel;
  if (aSel=sel_get_uid([self getActionMessage]))
    [[self getActionMessageReceiver]
     perform : aSel
     with : [self getActionMessageObject1]
     with : [self getActionMessageObject2]];
  return self;
}

- manage
{
  XtManageChild([self getWidget]);
  return self;
}

- unManage
{
  /*
     id child=[self getChildObject];
     if ([child isManaged]) [child unManage];
     */
  XtUnmanageChild([self getWidget]);
  return self;
}

- toggleManagedState
{
  return [self perform:sel_get_uid([self isManaged]
				   ? "unManage"
				   : "manage")];
}

- (BOOL)isSensitive
{
  return XtIsSensitive([self getWidget]);
}

- setSensitive:(BOOL)value
{
  XtSetSensitive([self getWidget], value);
  return self;
}

- toggleSensitivity
{
  return [self setSensitive: [self isSensitive]?False:True];
}

- popUp
{
  XWindowAttributes wa;
  XtAppContext app;
  XEvent event;
  if (![self isManaged])
    [self manage];
  while (XGetWindowAttributes([self getDisplay], 
			   [[self getShellObject] getWindow], &wa) &&
	 wa.map_state!=IsViewable)
    {
      XtAppNextEvent([self getApplicationContext], &event);
      XtDispatchEvent(&event);
    }
  XmUpdateDisplay([[self getApplicationObject] getWidget]);
  return self;
}

- popDown
{
  [self unManage];
  XmUpdateDisplay([[self getApplicationObject] getWidget]);
  return self;
}

- (BOOL)isManaged
{
  return XtIsManaged([self getWidget]);
}

- (BOOL)isViewable
{
  XWindowAttributes wa;
  BOOL value;
  if (XGetWindowAttributes([self getDisplay], 
			   [[self getShellObject] getWindow], &wa))
    value=(wa.map_state==IsViewable);
  else
    value=NO;
  return value;
}
		       

@end


