#include "assert.h"   /* must be first for use eith hc2 */
#include "Mintrins.h"
#include "alpop.h"
#include "alpopargs.h"
#include "RMFBuffer.h"
#include "rap.h"
#include "xstuff.h"
#include "ArgPack.h"
#include "alfonts.h"
#include "bool.h"
#include "alxms.h"
#include "al.h"
#include <Xm/DialogS.h>

static Bool  alpop_called;
static VOIDP alpop_return;

#define ALPOP_DOING_HELP  (1<<8)


/*--------------------------------------------------*/
NORET alpop_CB(w,rap,motifData)
Widget w;
RapPack rap;
XmAnyCallbackStruct *motifData;
{
  char *help;
  Widget pshellW=(Widget)RapPack_get(rap,0);
  switch (motifData->reason) {
  case XmCR_OK: alpop_return=(VOIDP)1;
    alpop_called=Bool_TRUE;
    break;
  case XmCR_CANCEL: alpop_return=(VOIDP)2;
    alpop_called=Bool_TRUE;
    break;
  case XmCR_HELP: 
    help=RapPack_get(rap,1);
    if (help!=NULL) {
      AlPop_Query(ALPOP_INFO,help,NULL,w,ALPOP_HANG_BELOW,
		  XtDisplay(pshellW), ALPOP_DOING_HELP);
    }
    else {
      alpop_called=Bool_TRUE;
    }
    break;
  }
}


/*--------------------------------------------------*/
VOIDP AlPop_query(type,message,helpMessage,hangW,hangDirection,display,
		  buttons,message_box_name)
     Display *display;
     AlPopType type;
     char *message;
     char *helpMessage;
     Widget hangW;
     AlPopHangDirection hangDirection;
     int buttons;
     char *message_box_name;
{
  Widget mbox, pshellW;
  Widget AppShellW=NULL;
  Window root, rrW, crW;
  ArgPack AP;
  static Registry strings=NULL;
  XmString XmMessage;
  XEvent event;
  XtAppContext AppContext;
  RapPack rap;
  int w,h,x,y, hang_w, hang_h, hang_w_orig, hang_h_orig, units, d1, d2, d3;
  int width, height, screen_width, screen_height, bottom_x, bottom_y;
  Screen* screen;

  if (display==NULL)
    Al_fatal_error("AlPop_Query: passed NULL diaplay\n");

  x=(-10);
  if (hangW!=NULL) {
    AlPop_make_hang_coordinates(hangW,hangDirection,
				(int)ALPOP_SHELL_UNIT_TYPE,
				&x,&y);
  }
  else {
    /* get the root window */
    root=XDefaultRootWindow(display);
    
    /* get x and y coordinates of pointer so we can pop yp a window. */
    XQueryPointer(display,root,&rrW,&crW,
		  &x,&y,
		  &d1,&d2,&d3); /* return info that I don't need */
    x=x-50;
    y=y-50;
  }

  AP=ArgPack_duplicate_args(alpop_shell);
  AppShellW=XtAppCreateShell("Argus-dialogs","Argus",
			     vendorShellWidgetClass,
			     display,
			     ArgPack_the_args(AP), ArgPack_num_args(AP) );
  ArgPack_delete(AP);
  
  assert(x>=0);

  if (strings==NULL)
    strings=Alxms_create_registry();

  XmMessage=Alxms_create_ltor(strings,message,ALFONTS_TEXT);

  AP=ArgPack_duplicate_args(alpop_mbox);
  ArgPack_add_arg(AP,XmNmessageString, (XtArgVal) XmMessage);
  switch (type) {
  case ALPOP_INFO:
    ArgPack_add_arg(AP,XmNdialogType, (XtArgVal) XmDIALOG_INFORMATION );
    break;
  case ALPOP_ERROR:
    ArgPack_add_arg(AP,XmNdialogType, (XtArgVal) XmDIALOG_ERROR );
    break;
  case ALPOP_QUESTION:
    ArgPack_add_arg(AP,XmNdialogType, (XtArgVal) XmDIALOG_QUESTION );
    break;
  case ALPOP_WARNING:
    ArgPack_add_arg(AP,XmNdialogType, (XtArgVal) XmDIALOG_WARNING );
    break;
  case ALPOP_MESSAGE:
    ArgPack_add_arg(AP,XmNdialogType, (XtArgVal) XmDIALOG_MESSAGE );
    break;
  default: Al_warning("AlPop_Query: invalid popup type specified.");
    break;
  }
  mbox=XmCreateMessageBox(AppShellW,  
			  message_box_name,
			  ArgPack_the_args(AP),
			  ArgPack_num_args(AP));
  ArgPack_delete(AP);

  rap=RapPack_create2(AppShellW,helpMessage);

  if (buttons & ALPOP_CANCEL)
    XtAddCallback(mbox,XmNcancelCallback,
		  alpop_CB,
		  rap);
  else {
    Widget cancelW=XmMessageBoxGetChild(mbox,XmDIALOG_CANCEL_BUTTON);
    assert(cancelW);
    XtUnmanageChild(cancelW);
    XtDestroyWidget(cancelW);
  }

  if (buttons & ALPOP_DOING_HELP) {
    XmString DoneWHelp;
    Widget okW=XmMessageBoxGetChild(mbox,XmDIALOG_OK_BUTTON);
    DoneWHelp=Alxms_create_ltor(strings,"Done With Help",
				ALFONTS_MINOR_HEADING);
    Alxt_SetArg(okW,XmNlabelString,(XtArgVal)DoneWHelp);
    XtAddCallback(mbox,XmNokCallback,
		  alpop_CB,
		  rap);
  }
  else if (buttons & ALPOP_OK)
    XtAddCallback(mbox,XmNokCallback,
		  alpop_CB,
		  rap);
  else {
    Widget okW=XmMessageBoxGetChild(mbox,XmDIALOG_OK_BUTTON);
    XtUnmanageChild(okW);
    XtDestroyWidget(okW);
  }

  if ((buttons & ALPOP_HELP) && (helpMessage!=NULL)) 
    XtAddCallback(mbox,XmNhelpCallback,
		  alpop_CB,
		  rap);
  else {
    Widget helpW=XmMessageBoxGetChild(mbox,XmDIALOG_HELP_BUTTON);
    assert(helpW);
    XtUnmanageChild(helpW);
    XtDestroyWidget(helpW);
  }

  alpop_called=Bool_FALSE;
  alpop_return=NULL;

  XtManageChild(mbox);

  /* this odd sequence of reading the resource, and then setting it to the */
  /* shell and the widget it was just read from seems to be the only way I */
  /* could get the shell to be the right size.  Intuitive right? */
  width=(int)Alxt_get_widget_feature(mbox,XmNwidth);
  height=(int)Alxt_get_widget_feature(mbox,XmNheight);
  Alxt_SetArg(AppShellW,XmNwidth,(XtArgVal)width);
  Alxt_SetArg(AppShellW,XmNheight,(XtArgVal)height);
  Alxt_SetArg(mbox,XmNwidth,(XtArgVal)width);
  Alxt_SetArg(mbox,XmNheight,(XtArgVal)height);

  /* make sure the popup is on the screen */
  bottom_x=x+width;
  bottom_y=y+height;

  if (hangW!=NULL)
    screen=XtScreen(hangW);
  else
    screen=XDefaultScreenOfDisplay(display);

  screen_width=XWidthOfScreen(screen);
  screen_height=XHeightOfScreen(screen);

  if (bottom_x>screen_width)
    x=screen_width-width-5;

  if (bottom_y>screen_height)
    y=screen_height-height-5;
  
  /* make sure left top is always visible */
  if (x<0) x=0; if (y<0) y=0;

  /* set the x and y of the shell and pop up ! */
  Alxt_SetArg(AppShellW,XmNx,(XtArgVal)x);
  Alxt_SetArg(AppShellW,XmNy,(XtArgVal)y);
 
  XtPopup(AppShellW,XtGrabNone);

  XtManageChild(mbox);

  AlUI_AttachCursor(AppShellW,132); 
  
  AppContext=XtWidgetToApplicationContext(AppShellW);

  while(alpop_called==Bool_FALSE) {
    XtAppNextEvent(AppContext, &event);
    XtDispatchEvent(&event);
  }
  alpop_called=Bool_FALSE;
  RapPack_destroy(rap);
  XtPopdown(AppShellW);
  XtUnmanageChild(mbox);
  XtDestroyWidget(mbox);
  return(alpop_return);
}

/*--------------------------------------------------*/
NORET AlPop_make_hang_coordinates(hangW,HangDirection,
				  shellUnits,retX,retY)
Widget hangW;
AlPopHangDirection HangDirection;
int shellUnits;
int *retX, *retY;
{
  Window RootWin, ChildWin;
  Display *dis;
  int hang_w, hang_h, hang_w_orig, hang_h_orig, x, y;
  unsigned char ShellUnits=(unsigned char)shellUnits;
  unsigned char units;

  hang_w_orig=(int)Alxt_get_widget_feature(hangW,XmNwidth);
  hang_h_orig=(int)Alxt_get_widget_feature(hangW,XmNheight);

  dis=XtDisplay(hangW);
  RootWin=XDefaultRootWindow(dis);
  if (XTranslateCoordinates(dis,
			    XtWindow(hangW),
			    RootWin,0,0,
			    &x,&y,&ChildWin)==0) 
    Al_fatal_error("in point_above_member: fatal error in the extreme-5\n");

  /* WARNING !!! bad kludge below */
/*  units=(unsigned char)Alxt_get_widget_feature(hangW,XmNunitType); */
  units=Xm100TH_MILLIMETERS;
  hang_w=XmConvertUnits(hangW,
			XmHORIZONTAL,
			units,
			hang_w_orig,
			ShellUnits);
  hang_h=XmConvertUnits(hangW,
			XmVERTICAL,
			units,
			hang_h_orig,
			ShellUnits);

  /* x,y,hang_w and hang_h are in pixels at this point */

/*  printf("hw_o=%d hho=%d ",hang_w_orig, hang_h_orig);
    printf("hw=%d hh=%d\n",hang_w, hang_h);
    printf("x=%d y=%d\n",x,y);
    printf("units=%d\n",units); */

  switch(HangDirection) {
  case ALPOP_HANG_BOTTOM_RIGHT: 
    x=x+hang_w-ALPOP_INC;
    y=y+hang_h-ALPOP_INC;
    break;
  case ALPOP_HANG_BOTTOM_LEFT:  /* should know width of popup here */ 
    x=x-5;
    y=y+hang_h-ALPOP_INC;
    break;
  case ALPOP_HANG_BELOW: 
    y=y+hang_h-ALPOP_INC;
    break;
  }
  *retX=x;
  *retY=y;
}


/*  {
    int width, height;
    width=(int)Alxt_get_widget_feature(mbox,XmNwidth);
    height=(int)Alxt_get_widget_feature(mbox,XmNheight);
    
    width=XmConvertUnits(mbox,
			 XmHORIZONTAL,
			 Xm100TH_MILLIMETERS,
			 width,
			 ALPOP_SHELL_UNIT_TYPE);
    height=XmConvertUnits(mbox,
			  XmVERTICAL,
			  Xm100TH_MILLIMETERS,
			  height,
			  ALPOP_SHELL_UNIT_TYPE);
    
    Alxt_SetArg(AppShellW,XmNwidth, (XtArgVal) width); 
    
    Alxt_SetArg(AppShellW,XmNheight, (XtArgVal) height);
  }
  */



/*--------------------------------------------------*/
VOIDP AlPop_Query(type,message,helpMessage,hangW,hangDirection,display,buttons)
     Display *display;
     AlPopType type;
     char *message;
     char *helpMessage;
     Widget hangW;
     AlPopHangDirection hangDirection;
     int buttons;
{
  AlPop_query(type,message,helpMessage,hangW,hangDirection,display,buttons,
	      "argus-pop-dialog");
}

/*--------------------------------------------------*/
VOIDP AlPop_Query_named(type,message,helpMessage,hangW,
			hangDirection,display,buttons,message_box_name)
     Display *display;
     AlPopType type;
     char *message;
     char *helpMessage;
     Widget hangW;
     AlPopHangDirection hangDirection;
     int buttons;
     char *message_box_name;
{
  AlPop_query(type,message,helpMessage,hangW,hangDirection,display,buttons,
	      message_box_name);
}
