
#include <stdio.h>                              /* For printf and so on. */

#ifdef VMS
#include <decw$include/DwtAppl.h>       /* DECwindows Toolkit */
#else
#include <X11/DwtAppl.h>
#endif

#include "XmuX.h"
#include <X11/Xatom.h>
#include <X11/cursorfont.h>

extern char *malloc( ) ;

typedef struct _display_infos {
    char *name ;
    int   length ;
} DisplayInfos ;

static DisplayInfos display_infos[ ] = {
{ "neleus:0" , 8 } ,
{ "kaputt:0" , 8 } ,
{ "ehoop::0" , 8 } ,
{ "replay:0" , 8 } ,
{ "pylos:0" , 7 } ,
} ;

static char *XmuXDebugTable[ ] = 
    { "events" , "requests" , "resources" , "mux" , "all" } ;
    
static Widget toplevel_widget;          /* Root widget ID of our */
                                        /* application. */
static Widget main_window_widget;       /* Root widget ID of main */
                                        /* DRM fetch */
static DRMHierarchy s_DRMHierarchy;     /* DRM database hierarchy ID */
static DRMType *dummy_class;            /* and class variable. */
static char *db_filename_vec[] =        /* DRM heirachy file list. */
{ "/usr/local/common/lib/uid/helper.uid" 
} ;

static int db_filename_num =
                (sizeof db_filename_vec / sizeof db_filename_vec [0]);

/* Forward declarations */

void callback();
void create() ;
void enter() ;
void select() ;
void do_Debug() ;

/* The names and addresses of things that DRM has to bind.  The names do */
/* not have to be in alphabetical order.  */

static DRMRegisterArg reglist[] = {
    {"callback", (caddr_t) callback}, 
    {"create_proc" , (caddr_t) create} ,
    {"select" , (caddr_t) select} ,
    {"debug" , (caddr_t) do_Debug} ,
    {"enter" , (caddr_t) enter } 
};

static int reglist_num = (sizeof reglist / sizeof reglist [0]);

#define min_button           7
#define max_button           13
#define button_add_ok        7
#define button_add_cancel    8
#define button_chalk_ok      9
#define button_chalk_cancel  10
#define button_remove_ok     11
#define button_remove_cancel 12
#define button_main_quit     13
#define add_box              14
#define chalk_box            15
#define remove_box           16
#define chalk_list           17
#define remove_list          18
#define main_text            19
#define add_command          20

#define NUM_WIDGETS add_command + 1

static Widget all_widgets[ NUM_WIDGETS ] ;

static int   chalk_hosts ;
static int   chalk_dpy ;
static int   remove_hosts ;
static char  *hosts ;
static int    remove_dpy ;
static int   add_box_is_mapped = 0 ,
             remove_box_is_mapped = 0 ,
             chalk_box_is_mapped = 0 ;

Display   *dpy ;
int        screen ;
XmuXHints  mux_hints ;
Cursor cursor;

Window 
Select_Window(dpy)
     Display *dpy;
{
  int status;
  XEvent event;
  Window target_win = None;
  int buttons = 0 ;
  char message[ 256 ] ,
      *curr_str ;

  bzero( message , 256 ) ;

  /* Grab the pointer using target cursor, letting it room all over */
  status = XGrabPointer(dpy, RootWindow(dpy, screen), False,
			ButtonPressMask|ButtonReleaseMask, GrabModeSync,
			GrabModeAsync, None, cursor, CurrentTime);
  if (status != GrabSuccess) 
  {
      printf("Can't grab the mouse.");
      exit( 1 ) ;
  }

  /* Let the user select a window... */
  while ((target_win == None) || (buttons != 0)) {
    /* allow one more event */
    XAllowEvents(dpy, SyncPointer, CurrentTime);
    XWindowEvent(dpy, RootWindow(dpy, screen),
		 ButtonPressMask|ButtonReleaseMask, &event);
    switch (event.type) {
    case ButtonPress:
      if (target_win == None) 
      { Window child , win , root ;
	int rx , ry , x, y , keys ;
	char *win_name = NULL ;

	child = event.xbutton.subwindow ;
	if( !child ) 
	    child = RootWindow( dpy ,screen ) ;
	
	win = child ;
	XFetchName( dpy , child , &win_name ) ;

	/* 
	 * -- go down the tree: stop at the first toplevel window 
	 * -- A window manager may fool us by creating a "pseudo root"
	 * -- that's why we use the win_name here 
	 */
	while( child && child != RootWindow(dpy,screen) && win_name == NULL )
	{
	    target_win = win ;
	    XFetchName( dpy , target_win , &win_name ) ;
	    XQueryPointer( dpy , win , &root , &child , &rx ,&ry , &x , &y ,
			   &keys ) ;
	    
	    win = child ;
	} 
	if (target_win == None)
	  target_win = event.xbutton.subwindow ? event.xbutton.subwindow :
	               RootWindow( dpy , screen ) ;
      }
      buttons++;
      break;
    case ButtonRelease:
      if (buttons > 0) /* there may have been some down before we started */
	buttons--;
       break;
    }
  } 

  XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */

  return(target_win);
}

int
XmuXSetHints( dpy , target , hints )

Display   *dpy ;
Window     target ;
XmuXHints *hints ;

{   Atom atom ;

    if( hints->type == XMUXProperty )
    {   
	if( !hints->u.strings[ XMUXType ] || !hints->u.strings[ XMUXSubtype ] )
	{
	    printf( "Invalid data! \n" ) ;
	    return( BadValue ) ;
	}
	atom = XInternAtom( dpy , hints->u.strings[ XMUXType ] , True ) ;
	if( !atom )
	{
	    printf( "Atom %s not valid!\n" , hints->u.strings[ XMUXType ] ) ;
	    return( BadAtom ) ;
	}
	printf( "Change property on window 0x%lx , value = %s (%d)\n" ,
	         target , hints->u.strings[ XMUXSubtype ] , 
	         strlen( hints->u.strings[ XMUXSubtype ] ) ) ;
	XChangeProperty( dpy , target , atom , XA_STRING , 8 , 
			 PropModeReplace , hints->u.strings[ XMUXSubtype ] , 
			 strlen( hints->u.strings[ XMUXSubtype ] ) + 1 ) ;
    }
    else
    {   XEvent message ;
	
	message.type               = ClientMessage ;
	message.xclient.display    = dpy ;
	message.xclient.window = target ;
	atom = XInternAtom( dpy , XMUX_MESSAGE_NAME , False ) ;
	if( !atom )
        {
            printf( "Atom %s not valid!\n" , XMUX_MESSAGE_NAME ) ;
            return( BadAtom ) ;
        }
	message.xclient.message_type = atom ;
	message.xclient.format = XMUX_MESSAGE_FORMAT ;
	message.xclient.data.l[ XMUXType ] = hints->u.mess[ XMUXType ] ;
	message.xclient.data.l[ XMUXSubtype ] = hints->u.mess[ XMUXSubtype ] ;
	message.xclient.data.l[ XMUXDetail ] = hints->u.mess[ XMUXDetail ] ;
	printf( "Send event w =  0x%lx , atom = %d" , target , atom ) ;
	if( hints->u.mess[ XMUXSubtype ] == XMUXPassChalk )
	    printf( " message = pass chalk\n" ) ;
	else
	    printf( " message = debug %s\n" ,
		    XmuXDebugTable[ hints->u.mess[ XMUXDetail ] - 1 ] ) ;
	XSendEvent( dpy , target , False , PropertyChangeMask , &message ) ;
    }
    return( Success ) ;
}

void
do_Multiplex( dpy , target , string )
    
register Display *dpy ;
register Window   target ;
register char    *string ;

{   register char *displays ,
	          *bufptr ;
    register int i , 
                 length ;

    if( !target )
    {
	printf( "no target window found!\n" ) ;
	return ;
    }
    
    length = strlen( string ) + 1 ;
    if( ( displays = malloc( length + 1 ) ) == NULL ) 
    {
        printf( "Can't allocate display name array!\n" ) ;
        return ;
    }
    displays[ 0 ] = '+' ;
    strcpy( &displays[ 1 ] , string ) ;
    displays[ length ] = '\0' ;
    mux_hints.type     = XMUXProperty ;
    mux_hints.u.strings[ 0 ] = XMUX_CPORT_NAME ;
    mux_hints.u.strings[ 1 ] = displays ;
    XmuXSetHints( dpy , target , &mux_hints ) ;
    free( displays ) ;
}

void
do_Demultiplex( dpy , target )

register Display *dpy ;
register Window  target ;

{   register char *display ,
	          *bufptr ;
    register int i ;

    bufptr = hosts ;
    for( i = 0 ; i < remove_dpy - 1 ; i++ )
	bufptr += ( strlen( bufptr ) + 1 );

    if( ( display = malloc( strlen( bufptr ) + 2 ) ) == NULL )
	return ;
    display[ 0 ] = '-' ;
    strcpy( &display[ 1 ] , bufptr ) ;
    display[ strlen( bufptr ) + 1 ] = '\0' ;

    mux_hints.type     = XMUXProperty ;
    mux_hints.u.strings[ 0 ] = XMUX_CPORT_NAME ;
    mux_hints.u.strings[ 1 ] = display ;
    XmuXSetHints( dpy , target , &mux_hints ) ;
    free( display ) ;
}

void
do_PassChalk( dpy , target )

register Display *dpy ;
register Window  target ;

{   
    if( !target )
    {
	printf( "no target window found!\n" ) ;
	return ;
    }
    mux_hints.type        = XMUXMessage ;
    mux_hints.u.mess[ XMUXType ]    = XMUXAction ;
    mux_hints.u.mess[ XMUXSubtype ] = XMUXPassChalk ;
    printf( "selected host no. %d\n" , chalk_dpy - 1 ) ;
    mux_hints.u.mess[ XMUXDetail  ] = chalk_dpy - 1 ;
    XmuXSetHints( dpy , target , &mux_hints ) ;
}

static
void
do_Debug( widget , tag , reason ) 

Widget widget ;
int    *tag ;
unsigned long reason ;

{   register Window  target ;

    target = Select_Window( dpy ) ;
    if( !target )
    {
	printf( "no target window found!\n" ) ;
	return ;
    }
    mux_hints.type        = XMUXMessage ;
    mux_hints.u.mess[ 0 ] = XMUXAction ;
    mux_hints.u.mess[ 1 ] = XMUXDebug ;
    mux_hints.u.mess[ 2 ] = *tag ;
    XmuXSetHints( dpy , target , &mux_hints ) ;
}

/* OS transfer point.  The main routine does all the one-time setup and */
/* then calls XtMainLoop.                                               */

unsigned int main(argc, argv)
    unsigned int argc;                  /* Command line argument count. */
    char *argv[];                       /* Pointers to command line args. */
{   register int i ;

    for( i = 0 ; i < NUM_WIDGETS ; i++ )
	all_widgets[ i ] = 0 ;

    DwtInitializeDRM();                 /* Initialize DRM before initializing */
                                        /* the X Toolkit. */

    /* If we had user-defined widgets, we would register them with DRM here. */

    /* Initialize the X Toolkit. We get back a top level shell widget. */

    toplevel_widget = XtInitialize ("Helper",  /* Main banner text. */
                                    "shxhelper",        /* Root class name. */
                                    NULL,             /* No option list. */
                                    0,                /* Number of options. */
                                    &argc,            /* Address of argc */
                                    argv);            /* argv */


    dpy = XtDisplay( toplevel_widget ) ;
    screen = DefaultScreen( dpy ) ;

    /* Make the target cursor */
    cursor = XCreateFontCursor(dpy, XC_crosshair);

    /* Open the UID files (the output of the UIL compiler) in the hierarchy*/

    if (DwtOpenHierarchy (db_filename_num, /* Number of files. */
                          db_filename_vec, /* Array of file names.  */
                          NULL,            /* Default OS extenstion. */
                          &s_DRMHierarchy) /* Pointer to returned DRM ID */
          != DRMSuccess) {
      printf ("can't open hierarchy\n");
      exit (0);
    }  

    /* Register the items DRM needs to bind for us. */

    DwtRegisterDRMNames(reglist, reglist_num);

    /* Go get the main part of the application. */

    if (DwtFetchWidget(s_DRMHierarchy, "Main", toplevel_widget,
                       &main_window_widget, &dummy_class) != DRMSuccess) {
      printf ("can't fetch main window\n");
      exit (0);
    }

    /* Manage the main part and realize everything.  The interface comes up */
    /* on the display now. */

    XtManageChild(main_window_widget);
    XtRealizeWidget(toplevel_widget);

    /* Sit around forever waiting to process X-events.  We never leave  */
    /* XtMainLoop. From here on, we only execute our callback routines. */

    XtMainLoop();
}

static void show_hosts( window , list_widget ) 

Window window ;
Widget list_widget ;

{   char     *bufptr ,
	     *end ;
    Atom      xmux_hosts ,
              actual_type ;
    int       actual_format ,
              actual_length ,
              num_hosts ,
              bytes_after ;

    
    if( ( xmux_hosts = XInternAtom( dpy , XMUX_HOSTS_NAME , True ) ) == 0 )
	return ;
    hosts = NULL ;
    XGetWindowProperty( dpy , window , xmux_hosts , 0 , 8192L , False ,
		        AnyPropertyType , &actual_type , &actual_format ,
		        &actual_length , &bytes_after , &hosts ) ;
    if( !hosts )
	return ;
    num_hosts = 1 ;
    for( bufptr = hosts ; *bufptr != '\0'  ; bufptr++ )
    {   char *host ;

	if( ( end = index( bufptr , ',' ) ) == NULL )
	    if( ( end = index( bufptr , '\0' ) ) == NULL )
	       break ;
	hosts[ end - hosts ] = '\0' ;
	num_hosts++ ;
	DwtListBoxAddItem( list_widget , DwtLatin1String( bufptr ) , 0 ) ;
	bufptr += strlen( bufptr ) ;
    }
    if( list_widget == all_widgets[ chalk_list ] )
	chalk_hosts = num_hosts ;
    else
	remove_hosts = num_hosts ;
}

static void reset_list( list_widget )

Widget list_widget ;

{   register int i ;

    if( list_widget == all_widgets[chalk_list ] )
	for( i = 0 ; i < chalk_hosts ; i++ )
	    DwtListBoxDeletePos( list_widget , 1 ) ;
    else
	for( i = 0 ; i < remove_hosts ; i++ ) 
	    DwtListBoxDeletePos( list_widget , 1 ) ;
}

static void callback (widget, tag, reason)

Widget widget;
int   *tag;
unsigned long reason;

{
  static Widget add_widget   = 0 ,
                chalk_widget = 0 ,
                rem_widget   = 0 ,
                list_widget = 0 ;
  static Window rem_window ,
                chalk_window ;
  DRMType       *dummy_class;

  switch( *tag ) 
  {
  case add_box :
    if( all_widgets[ add_box ] == 0) 
    {
	if (DwtFetchWidget ( s_DRMHierarchy, "AddBox", toplevel_widget,
			     &add_widget, &dummy_class) != DRMSuccess) 
	{
	    printf ("can't fetch add box widget\n");
	} 
	else 
	{
	    add_box_is_mapped = 1 ;
	    all_widgets[ add_box ] = add_widget ;
	    XtManageChild (add_widget);
	}
    } 
    else 
	if( !add_box_is_mapped )
	{
	    add_box_is_mapped = 1 ;
	    XtManageChild( all_widgets[ add_box ] ) ;
	}
    break ;

  case remove_box :
    if( all_widgets[ remove_box ] == 0) 
    {
	if (DwtFetchWidget ( s_DRMHierarchy, "RemoveBox", toplevel_widget,
			     &rem_widget, &dummy_class) != DRMSuccess) 
	{
	    printf ("can't fetch remove box widget\n");
	} 
	else 
	{
	    remove_box_is_mapped = 1 ;
	    all_widgets[ remove_box ] = rem_widget ;
	    XtManageChild (rem_widget);
	    rem_window = Select_Window( dpy ) ;
	    if( rem_window == None ) 
		return ;
	    show_hosts( rem_window , all_widgets[ remove_list ] ) ;
	}
    } 
    else 
	if( !remove_box_is_mapped )
	{
	    remove_box_is_mapped = 1 ;
	    XtManageChild( all_widgets[ remove_box ] ) ;
	    rem_window = Select_Window( dpy ) ;
	    if( rem_window == None ) 
		return ;
	    show_hosts( rem_window , all_widgets[ remove_list ] ) ;
	}
    break ;

  case chalk_box :
    
    if( all_widgets[ chalk_box ] == 0) 
    {
	if (DwtFetchWidget ( s_DRMHierarchy, "ChalkBox", toplevel_widget,
			     &chalk_widget, &dummy_class) != DRMSuccess) 
	{
	    printf ("can't fetch chalk box widget\n");
	} 
	else
	{
	    all_widgets[ chalk_box ] = chalk_widget ;
	    XtManageChild (chalk_widget);
	    chalk_box_is_mapped = 1 ;
	    chalk_window = Select_Window( dpy ) ;
	    if( chalk_window == None ) 
		return ;
	    show_hosts( chalk_window , all_widgets[ chalk_list ] ) ;
	}
    } 
    else 
    {
	if( !chalk_box_is_mapped )
	    XtManageChild( all_widgets[ chalk_box ] ) ;
	chalk_box_is_mapped = 1 ;
	chalk_window = Select_Window( dpy ) ;
	if( chalk_window == None ) 
	    return ;
	show_hosts( chalk_window , all_widgets[ chalk_list ] ) ;
    }
    break ;

 case button_add_ok :
     do_Multiplex( dpy , Select_Window( dpy ) , NULL ) ;
     /* -- no break -- */
 case button_add_cancel :
     XtUnmanageChild( all_widgets[ add_box ] ) ;
     add_box_is_mapped = 0 ;
     break ;

 case button_chalk_ok :
     do_PassChalk( dpy , chalk_window ) ;
     /* -- no break -- */
 case button_chalk_cancel :
     reset_list( all_widgets[ chalk_list ] ) ;
     XtUnmanageChild( all_widgets[ chalk_box ] ) ;
     chalk_box_is_mapped = 0 ;
     break ;

 case button_remove_ok :
     do_Demultiplex( dpy , rem_window ) ;
     /* -- no break -- */
 case button_remove_cancel :
     reset_list( all_widgets[ remove_list ] ) ;
     XtUnmanageChild( all_widgets[ remove_box ] ) ;
     remove_box_is_mapped = 0 ;
     break ;
 case button_main_quit :
     exit (0);
    break ;

    default :
	printf ("tag '%s' (no action)\n", tag);
  }  
}


void
create( widget , tag , reason )

Widget         widget ;
int           *tag ;
unsigned long *reason ;

{
    all_widgets[ *tag ] = widget ;
}

static void enter( widget , tag , reason )

Widget  widget ;
int    *tag ;
DwtCommandWindowCallbackStruct *reason ;

{   
    if( *tag == add_command )
    {
	do_Multiplex( dpy , Select_Window( dpy ) , reason->value ) ;
	XtUnmanageChild( all_widgets[ add_box ] ) ;
	add_box_is_mapped = 0 ;
    }

}

static void select( widget , tag , reason )

Widget  widget ;
int    *tag ;
DwtListBoxCallbackStruct *reason ;

{
    if( *tag == chalk_list )
	chalk_dpy = reason->item_number ;
    else
	remove_dpy = reason->item_number ;
}
