#include "assert.h"   /* must be first for use eith hc2 */
#include "ArgPack.h"
#include "Mintrins.h"
#include "alfonts.h"
#include "alpop.h"
#include "alxms.h"
#include "d2field.h"
#include "d2fieldargs.h"
#include "d2args.h"
#include "darray.h"
#include "debug.h"
#include "menupack.h"
#include "rem.h"
#include "widgets.h"
#include "xstuff.h"
#include "rl.h"
#include "ed.h"
#include <Xm/BulletinB.h>
#include <Xm/PanedW.h>
#include <Xm/Separator.h>

extern NORET d2_KeyModify_CB  PROTOTYPE((Widget,reid,caddr_t));
extern NORET RapDarray_print PROTOTYPE((char*,Darray));

MenuPack d2_Field_make_key_menu PROTOTYPE((REField));
NORET    d2_Field_manage_key    PROTOTYPE((REField,ArgPack));
NORET    d2_Field_layout_get_simple_key_args PROTOTYPE((REField,ArgPack));
NORET    d2_Field_layout_get_complex_key_args PROTOTYPE((REField,ArgPack));
NORET    d2_Field_select_CB PROTOTYPE((Widget,REField,caddr_t));
NORET    d2_Field_select_E PROTOTYPE((Widget, XEvent*, char**, int*));
NORET    d2_Field_add_focus PROTOTYPE((REField,Widget));
extern NORET d2_Fields_print PROTOTYPE ((int,REMember));
NORET    d2_Field_remake_field_size PROTOTYPE((REField));
extern   d2_Buttons_update PROTOTYPE((reid));
extern   d2_Refresh_tab_groups PROTOTYPE((reid));
#define PROCESSING_STATE "Processing State"
#define MESSAGE_PROPERTY "Message Properties"


XtActionsRec d2_FieldActions[]={
  { "d2_Field_select_E", d2_Field_select_E },
};
#define d2_FieldActionsCount          1

char* d2_FieldFocusEvent="<FocusIn>:d2_Field_select_E() ManagerFocusIn()";

/*--------------------------------------------------*/
Widget d2_Field_create(field,parentW,previousW)
     REField field;
     Widget parentW,previousW;
{
  reid rei=field->rei;
  ArgPack AP;

  AP=ArgPack_duplicate_args(d2_field_form);
  if (previousW==NULL)
    ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal) XmATTACH_FORM );
  else {
    ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal) XmATTACH_WIDGET );
    ArgPack_add_arg(AP, XmNtopWidget, (XtArgVal) previousW );
  }
  if (field->VisibleMode==RE_MODE_COMPLEX)
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) 
		    (2*rei->if_field_height) ); 
  else
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );  
  field->ContainerW=XmCreateForm(parentW,
				 "field-container",
				 ArgPack_the_args(AP),
				 ArgPack_num_args(AP));
  ArgPack_delete(AP);
  
  if (field->VisibleMode==RE_MODE_SIMPLE)
    d2_Field_create_simple(field);
  else 
    d2_Field_create_complex(field);

  XtManageChild(field->LeftContainerW);
  XtManageChild(field->RightContainerW);
  
  /* make sure the field isn't too tall.  We do this here because we have to */
  /* wait untill the rei->if_field_inner_height variable is filled in */
  /* d2_field_create_simple */
  if (field->VisibleMode==RE_MODE_COMPLEX)
    Alxt_SetArg(field->ContainerW,XmNheight,(XtArgVal)
		(2*rei->if_field_height));
  
  return(field->ContainerW);
}


/*--------------------------------------------------*/
NORET d2_Field_create_simple(field)
     REField field;
{
  ArgPack AP, Args;
  reid rei=field->rei;
  extern NORET Alxt_center_text_in_text_widget();

  AP=ArgPack_duplicate_args(d2_field_inner_form);
  ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal) XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_NONE/*7*/ );
  field->LeftContainerW=XmCreateForm(field->ContainerW,"field-left-side",
				     ArgPack_the_args(AP),
				     ArgPack_num_args(AP));
  ArgPack_delete(AP);

  AP=ArgPack_duplicate_args(d2_field_inner_form);
  ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal) XmATTACH_WIDGET );
  ArgPack_add_arg(AP, XmNleftWidget, (XtArgVal) field->LeftContainerW );
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_FORM );
  field->RightContainerW=XmCreateForm(field->ContainerW,"field-right-side",
				      ArgPack_the_args(AP),
				      ArgPack_num_args(AP));
  ArgPack_delete(AP);

  Args=ArgPack_duplicate_args(d2_field_key_simple);
  d2_Field_manage_key(field,Args);
  ArgPack_delete(Args);
  
  if (field->ShowOp==Bool_TRUE) {
    if (field->OpMenu==NULL)
      field->OpMenu=rl_MakeOpMenu(field);
    AP=ArgPack_duplicate_args(d2_field_option_menu);
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
    ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
    MenuPack_option_set_args(field->OpMenu,AP);
    MenuPack_attach_to_widget(field->OpMenu,field->RightContainerW);
    MenuPack_make_menu(field->OpMenu);
    ArgPack_delete(AP);
    field->OpW=MenuPack_get_top_level_manager(field->OpMenu);
    /* ADD FOCUS CATCHING STUFF */
    d2_Field_add_focus(field,field->OpW);
    d2_Field_shrink_option_menu(rei,field->OpMenu,field->OpW);
  }

  /*
   * ADD THE VALUE WIDGET FIRST
   */
  AP=ArgPack_duplicate_args(d2_field_edit);
  ArgPack_add_arg(AP, XmNmaxLength, (XtArgVal) field->MaxValueBufferLength );
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_FORM/*7*/ );
  if (field->ShowOp==Bool_TRUE) {
    ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal)  XmATTACH_WIDGET );
    ArgPack_add_arg(AP, XmNleftWidget, (XtArgVal)  field->OpW  );
  }
  else {
    ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal)  XmATTACH_FORM );
  }
  ArgPack_add_arg(AP, XmNvalue, (XtArgVal)  field->Value);
  ArgPack_add_arg(AP, XmNresizeWidth, (XtArgVal) TRUE  );
  ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
  ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
  ArgPack_add_arg(AP,XmNfontList, (XtArgVal)  
		  AlFonts_get_specific_fonts(rei->OuterW, ALFONTS_TEXT_MASK));
  field->ValueW=XtCreateManagedWidget("field-value",
				      xmTextWidgetClass,
				      field->RightContainerW,
				      ArgPack_the_args(AP),
				      ArgPack_num_args(AP));
  XtAddCallback(field->ValueW,XmNfocusCallback,
		d2_Field_select_CB,
		field);
  XtAddCallback(field->ValueW,XmNvalueChangedCallback,
		d2_KeyModify_CB,
		rei);
  MuSetSingleLineEmacsBindings(field->ValueW);
  ArgPack_delete(AP);

  rei->if_field_inner_height=(int)rei->if_field_height-
    (2*((int)Alxt_get_widget_feature(field->ValueW,XmNborderWidth)));
  
  RE_debug2("IF H=%d,%d\n",rei->if_field_height,
	    rei->if_field_inner_height);
  
  rei->if_value_width=(int)Alxt_get_widget_feature(field->ValueW,XmNwidth);

  RE_debug("added simple valuueW.\n");

}

/*--------------------------------------------------*/
NORET d2_Field_create_complex(field)
     REField field;
{
  d2_Field_create_simple(field);

  d2_Field_to_complex(field);

}

/*--------------------------------------------------*/
NORET d2_Field_to_complex(field)
     REField field;
{
  ArgPack AP;
  reid rei=field->rei;
  Bool MapAtEnd;

  if (field->VisibleMode==RE_MODE_COMPLEX &&
      field->ClassW!=NULL)
    return;

  MapAtEnd=Bool_FALSE;
  if (XtIsRealized(field->LeftContainerW)==TRUE) {
    MapAtEnd=Bool_TRUE;
    XtUnmapWidget(field->LeftContainerW);
    XtUnmapWidget(field->RightContainerW);
  }

  RE_debug2("key=%s, value=%s\n",field->Key,field->Value);
  if (field->ClassW==NULL) {
    if (field->ClassMenu==NULL) {
      RE_debug("making class menu\n");
      field->ClassMenu=d2_Field_make_class_menu(field);
    }
    AP=ArgPack_duplicate_args(d2_field_menu);
    ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal)    XmATTACH_FORM );
    ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal)   XmATTACH_FORM );
    ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_FORM );
    ArgPack_add_arg(AP, XmNbottomAttachment, (XtArgVal) XmATTACH_NONE );
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
    ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
    MenuPack_option_set_args(field->ClassMenu,AP);
    MenuPack_attach_to_widget(field->ClassMenu,field->LeftContainerW); 
    MenuPack_make_menu(field->ClassMenu);
    ArgPack_delete(AP);
    field->ClassW=MenuPack_get_top_level_manager(field->ClassMenu);

    /* ADD FOCUS CATCHING STUFF */
    d2_Field_add_focus(field,field->ClassW);
    d2_Field_shrink_option_menu(rei,field->ClassMenu,field->ClassW);
  }
  else {
    XtManageChild(field->ClassW);
  }

  AP=ArgPack_create();
  ArgPack_add_arg(AP,XmNtopWidget, (XtArgVal) field->ClassW);
  ArgPack_add_arg(AP,XmNtopAttachment,(XtArgVal) XmATTACH_WIDGET);
  XtSetValues(field->KeyW,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  if (field->TypeW==NULL) {
    if (field->TypeMenu==NULL) {
      RE_debug("making type menu\n");
      field->TypeMenu=d2_Field_make_type_menu(field);
    }
    AP=ArgPack_duplicate_args(d2_field_menu);
    ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal)    XmATTACH_FORM );
    ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal)   XmATTACH_FORM );
    ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_NONE );
    ArgPack_add_arg(AP, XmNbottomAttachment, (XtArgVal) XmATTACH_NONE );
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
    ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
    MenuPack_option_set_args(field->TypeMenu,AP);
    MenuPack_attach_to_widget(field->TypeMenu,field->RightContainerW); 
    /* MenuPack_set_shadow(field->TypeMenu,75);
       MenuPack_set_highlight(field->TypeMenu,75); */
    MenuPack_make_menu(field->TypeMenu);
    ArgPack_delete(AP);
    field->TypeW=MenuPack_get_top_level_manager(field->TypeMenu);

    /* ADD FOCUS CATCHING STUFF */
    d2_Field_add_focus(field,field->TypeW);
    d2_Field_shrink_option_menu(rei,field->TypeMenu,field->TypeW);
  }
  else
    XtManageChild(field->TypeW);

  if (field->OpW==NULL) {
    if (field->OpMenu==NULL)
      field->OpMenu=rl_MakeOpMenu(field);
    AP=ArgPack_duplicate_args(d2_field_option_menu);
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
    ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal)    XmATTACH_WIDGET );
    ArgPack_add_arg(AP, XmNtopWidget, (XtArgVal)   field->TypeW );
    ArgPack_add_arg(AP, XmNmarginHeight,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
    MenuPack_option_set_args(field->OpMenu,AP);
    MenuPack_attach_to_widget(field->OpMenu,field->RightContainerW);
    MenuPack_make_menu(field->OpMenu);
    ArgPack_delete(AP);

    field->OpW=MenuPack_get_top_level_manager(field->OpMenu);
    d2_Field_shrink_option_menu(rei,field->OpMenu,field->OpW);

  }
  else {
    if (field->ShowOp==Bool_TRUE && field->OpW!=NULL)
      XtUnmanageChild(field->OpW);
    Alxt_SetArg(field->OpW,XmNtopAttachment,   XmATTACH_WIDGET);
    Alxt_SetArg(field->OpW, XmNleftAttachment, (XtArgVal)   XmATTACH_FORM );
    Alxt_SetArg(field->OpW, XmNtopWidget, (XtArgVal)   field->TypeW );
    Alxt_SetArg(field->OpW,XmNrightAttachment, XmATTACH_NONE);
    Alxt_SetArg(field->OpW,XmNbottomAttachment,XmATTACH_FORM);
    XtManageChild(field->OpW);
    d2_Field_shrink_option_menu(rei,field->OpMenu,field->OpW);
  }
  /* ADD FOCUS CATCHING STUFF */
  d2_Field_add_focus(field,field->OpW);


  AP=ArgPack_create();
  ArgPack_add_arg(AP,XmNtopWidget, (XtArgVal) field->TypeW);
  ArgPack_add_arg(AP,XmNtopAttachment,(XtArgVal) XmATTACH_WIDGET);
  ArgPack_add_arg(AP,XmNleftAttachment,(XtArgVal) XmATTACH_WIDGET); 
  ArgPack_add_arg(AP,XmNleftWidget, (XtArgVal) field->OpW); 
  ArgPack_add_arg(AP,XmNbottomAttachment,(XtArgVal) XmATTACH_FORM); 
  ArgPack_add_arg(AP,XmNrightAttachment,(XtArgVal) XmATTACH_FORM); 
  XtSetValues(field->ValueW,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);
  
  /*
  AP=ArgPack_create();
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_WIDGET );
  ArgPack_add_arg(AP,XmNrightWidget,(XtArgVal) field->ValueW); 
  XtSetValues(field->OpW,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);
  d2_Field_shrink_option_menu(rei,field->OpMenu,field->OpW);
  */

  field->VisibleMode=RE_MODE_COMPLEX;

  d2_Field_remake_field_size(field);	      

  if (MapAtEnd==Bool_TRUE) {
    XtMapWidget(field->LeftContainerW);
    XtMapWidget(field->RightContainerW);
  }
}
  
/*--------------------------------------------------*/
NORET d2_Field_select_FT_CB(w,rap,data)
     Widget w;
     RapPack rap;
     caddr_t data;
{
  AlFieldType FT;
  Darray Ops=Darray_create();
  REField field=(REField)  RapPack_get(rap,0);
  char* newFieldType=(char*)RapPack_get(rap,1);
  reid rei=field->rei;
  ArgPack AP;

  /* free up the old string and replace with the new one */
  if (strcmp(field->FieldType,newFieldType)==0) return;
  
  Memory_free(field->FieldType);
  field->FieldType=RapStr_duplicate(newFieldType);
  FT=AlFTreg_string_to_obj(field->FieldType);
  field->FieldTypeObject=FT;
  if (field->TypeMenu!=NULL)
    MenuPack_set_as_default(field->TypeMenu,field->FieldType);

  /* reset the show op */
  field->ShowOp=( (Registry_get(ShowOpOnTheseFieldTypes_GR,
				field->FieldType)==NULL) 
		 ? Bool_FALSE : Bool_TRUE );
  
  /* get the default field operator which is the first one in the list of */
  if ((AlFieldType_get_field_op_list(FT,Ops))==Bool_FALSE)
    Al_fatal_error("couldn;t get default field operator\n");

  if (field->FieldOp!=NULL)
    Memory_free(field->FieldOp);
  field->FieldOp=RapStr_duplicate((char*)Darray_get(Ops,(unsigned)0));
  assert(field->FieldOp);
  Darray_destroy(Ops);
  
  /* REMAKE THE FIELD OPERATORS MENU*/
  if (field->ShowOp==Bool_TRUE || field->VisibleMode==RE_MODE_COMPLEX) {
    if (field->OpW!=NULL) {
      XtDestroyWidget(field->OpW);
      field->OpW=NULL;
    }
    if (field->OpMenu!=NULL) {
      MenuPack_destroy(field->OpMenu);
      field->OpMenu=NULL;
    }
    field->OpMenu=rl_MakeOpMenu(field);
    {
      AP=ArgPack_duplicate_args(d2_field_option_menu);
      ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
      ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal)    XmATTACH_WIDGET );
      ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal)   XmATTACH_FORM );
      ArgPack_add_arg(AP, XmNtopWidget, (XtArgVal)   field->TypeW );
      ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_NONE );
      ArgPack_add_arg(AP, XmNbottomAttachment, (XtArgVal) XmATTACH_FORM );
      ArgPack_add_arg(AP, XmNmarginHeight,  (XtArgVal) 0 );
      ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
      ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
      ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
      MenuPack_option_set_args(field->OpMenu,AP);
      MenuPack_attach_to_widget(field->OpMenu,field->RightContainerW);
      MenuPack_make_menu(field->OpMenu);
      ArgPack_delete(AP);
      field->OpW=MenuPack_get_top_level_manager(field->OpMenu);
      /* ADD FOCUS CATCHING STUFF */
      d2_Field_add_focus(field,field->OpW);
      XmAddTabGroup(field->OpW);

      d2_Field_shrink_option_menu(rei,field->OpMenu,field->OpW);
      
      Alxt_SetArg(field->ValueW,XmNleftWidget,(XtArgVal)field->OpW);
    }
  }
  else {   /* IF THE OP IS SHOWING GET RID OF IT */
    if (field->OpW!=NULL) 
      XtUnmanageChild(field->OpW);
  }
  rei->Modified=Bool_TRUE;
  d2_Refresh_tab_groups(rei);
}


/*--------------------------------------------------*/
MenuPack d2_Field_make_type_menu(field)
     REField field;
{
  MenuPack mp;
  RapPack rap;
  int i, l;
  char *name;

  mp=MenuPack_create_option(NULL,"field-type-menu","");
  l=Darray_len(FieldTypePresOrder_GR);
  RE_debug1("ft menu length =%d\n",l);
  for (i=0;i<l;i++) {
    name=(char*)Darray_get(FieldTypePresOrder_GR,(unsigned)i);
    rap=RapPack_create2(field,name);
    MenuPack_add_option(name,mp,
			(XtCallbackProc)d2_Field_select_FT_CB,
			(caddr_t)rap, NULL);
  }
  MenuPack_set_as_default(mp,field->FieldType);
  return(mp);
}

/*--------------------------------------------------*/
void d2_Field_select_FC_CB(w,rap,cadda)
     Widget w;
     RapPack rap;
     caddr_t cadda;
{
  ArgPack KeyArgs;
  RapPack rap2;
  REField field=(REField)RapPack_get(rap,0);
  char *ft;
  char *    class=(char*)RapPack_get(rap,1);
  char *    properClass=(char*)RapPack_get(rap,2);
  reid rei=field->rei;
  AlRFType Class;
  Bool OldState;
  KeyArgs=ArgPack_create();

  RE_debug1("class name=%s\n",class);
  Class=(AlRFType)AlRule_get_class_from_name(class);

  assert(field);
  assert(field->ClassMenu);
    /* maybe this should reset defaults instead of just returning */
  if (Class==field->Type) {
    /* little extra security here */
    MenuPack_set_as_default(field->ClassMenu,properClass);
    return;
  }
  XtUnmapWidget(field->LeftContainerW);
  XtUnmapWidget(field->RightContainerW);

    /* update the field information */
  if (field->FieldClass!=NULL)
    Memory_free(field->FieldClass);
  field->FieldClass=RapStr_duplicate(class);
  field->Type=Class;
  OldState=field->IsState;
  field->IsState=AlRule_is_state(Class);

  /*
   * if we have changed to a state then we must alter the field type
   * appropriately 
   */
  MenuPack_set_as_default(field->ClassMenu,properClass);

  d2_Field_layout_get_complex_key_args(field,KeyArgs);
  d2_Field_manage_key(field,KeyArgs);
  ArgPack_delete(KeyArgs);
  
  /* god what a sneaky trick */
  ft=AlRule_get_field_class_default_field_type(Class);
  if (ft==NULL)
    ft=AlFTreg_obj_to_string(DefaultFT_GR);
  rap2=RapPack_create2(field,ft);
  d2_Field_select_FT_CB(w,rap2,NULL);

  d2_Field_remake_field_size(field);

  rei->Modified=Bool_TRUE;
  XtMapWidget(field->LeftContainerW);
  XtMapWidget(field->RightContainerW);
}


/*--------------------------------------------------*/
MenuPack d2_Field_make_class_menu(field)
     REField field;
{
  MenuPack mmp, PSm, MPm;
  RapPack rap;
  unsigned i,l;
  char *name;
  Darray FCs=Darray_create();
  Darray PSs=Darray_create();
  Darray MPs=Darray_create();
  
  AlRule_get_field_class_names(FCs);
  AlRule_get_processing_state_names(PSs);
  AlRule_get_message_property_names(MPs);

  mmp=MenuPack_create_option(NULL,"field-class-menu","");
  l=Darray_len(FCs);
  for (i=0;i<l;i++) {
    name=Darray_get(FCs,i);
    rap=RapPack_create3(field,name,name);
    MenuPack_add_option(name,mmp,
			(XtCallbackProc)d2_Field_select_FC_CB,
			(caddr_t)rap,NULL);
  }

  PSm=MenuPack_create_cascade(NULL,NULL);
  l=Darray_len(PSs);
  for (i=0;i<l;i++) {
    name=Darray_get(PSs,i);
    rap=RapPack_create3(field,name,PROCESSING_STATE);
    MenuPack_add_option(name,PSm,
			(XtCallbackProc)d2_Field_select_FC_CB,
			(caddr_t)rap,NULL);
  }

  MPm=MenuPack_create_cascade(NULL,NULL);
  l=Darray_len(MPs);
  for (i=0;i<l;i++) {
    name=Darray_get(MPs,i);
    rap=RapPack_create3(field,name,MESSAGE_PROPERTY);
    MenuPack_add_option(name,MPm,
			(XtCallbackProc)d2_Field_select_FC_CB,
			(caddr_t)rap,NULL);
  }

  MenuPack_add_sub_menu(PROCESSING_STATE,mmp,PSm);
  MenuPack_add_sub_menu(MESSAGE_PROPERTY,mmp,MPm);

  MenuPack_set_as_default(mmp,field->FieldClass);

/*  RapDarray_print("Field Classes",FCs); */

  Darray_destroy(FCs);
  Darray_destroy(PSs);
  Darray_destroy(MPs);

  return(mmp);
}

/*--------------------------------------------------*/
NORET d2_Field_key_menu_CB(w,rap,cadda)
     Widget w;
     RapPack rap;
     caddr_t cadda;
{
  REField  field=(REField)RapPack_get(rap,0);
  char* state=(char*)RapPack_get(rap,1);
  AlRFType Class;
  char *ft;
  RapPack rap2;

  Class=(AlRFType)AlRule_get_class_from_name(state);

  /* maybe this should reset defaults instead of just returning */
  if (Class==field->Type) return;

    /* update the field information */
  if (field->FieldClass!=NULL)
    Memory_free(field->FieldClass);
  field->FieldClass=RapStr_duplicate(state);
  field->Type=Class;
  field->IsState=AlRule_is_state(Class);

  /* god what a sneaky trick */
  ft=AlRule_get_field_class_default_field_type(Class);
  if (ft==NULL)
    ft=AlFTreg_obj_to_string(DefaultFT_GR);
  rap2=RapPack_create2(field,ft);
  d2_Field_select_FT_CB(w,rap2,NULL);

  field->rei->Modified=Bool_TRUE;
  d2_Field_remake_field_size(field);
}


/*--------------------------------------------------*/
MenuPack d2_Field_make_key_menu(field)
     REField field;
{
  AlRFType class=field->Type;
  MenuPack mp;
  int i, l;
  Darray names=Darray_create();
  RapPack rap;
  char *name;

    /* !!! THIS KILL AND REMAKE SOLUTION IS PRETTY GROSS */
  if (field->KeyMenu!=NULL) {
    MenuPack_destroy(field->KeyMenu);
    field->KeyMenu=NULL;
  }

  mp=MenuPack_create_option(NULL,"field-key-menu","");
  if (AlRule_is_processing_state(class)) 
    AlRule_get_processing_state_names(names);
  else if (AlRule_is_message_property(class))
    AlRule_get_message_property_names(names);
  l=Darray_len(names);
  for (i=0;i<l;i++) {
    name=(char*)Darray_get(names,(unsigned)i);
    rap=RapPack_create2(field,name);
    MenuPack_add_option(name,mp,
			(XtCallbackProc)d2_Field_key_menu_CB,
			(caddr_t)rap, NULL);
  }
  return(mp);
}
/*--------------------------------------------------*/
NORET d2_Field_layout_get_simple_key_args(field,AP)
     REField field;
     ArgPack AP;
{
  ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal) XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal) XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNbottomAttachment, (XtArgVal)  XmATTACH_FORM );
}

/*--------------------------------------------------*/
NORET d2_Field_layout_get_complex_key_args(field,AP)
     REField field;
     ArgPack AP;
{
  ArgPack_add_arg(AP, XmNtopAttachment, (XtArgVal) XmATTACH_WIDGET );
  ArgPack_add_arg(AP, XmNtopWidget, (XtArgVal) field->ClassW );
  ArgPack_add_arg(AP, XmNleftAttachment, (XtArgVal) XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNrightAttachment, (XtArgVal)  XmATTACH_FORM );
  ArgPack_add_arg(AP, XmNbottomAttachment, (XtArgVal)  XmATTACH_FORM );
}

/*--------------------------------------------------*/
NORET   d2_Field_manage_key(field,Args)
     REField field;
     ArgPack Args;
{
  ArgPack AP;
  reid rei=field->rei;

  if (field->IsState==Bool_FALSE)  {
    if (field->KeyIsMenu==Bool_TRUE) {
      Widget tempW=field->OtherKeyW;
      if (field->KeyW!=NULL) {
	XtUnmanageChild(field->KeyW);
	XmRemoveTabGroup(field->KeyW);
      }
      field->OtherKeyW=field->KeyW;
      field->KeyW=tempW;
      field->KeyIsMenu=Bool_FALSE;
    }
    if (field->KeyW==NULL) {
      AP=ArgPack_duplicate_args(d2_field_edit);
      AP=ArgPack_copy_and_append(AP,Args);
      ArgPack_add_arg(AP, XmNmaxLength, (XtArgVal) field->MaxKeyLength );
      ArgPack_add_arg(AP, XmNcursorPosition,(XtArgVal)  strlen(field->Key));
      ArgPack_add_arg(AP, XmNvalue, (XtArgVal) field->Key);
      ArgPack_add_arg(AP, XmNresizeWidth, (XtArgVal) FALSE  );
      ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
      ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
      ArgPack_add_arg(AP,XmNfontList, (XtArgVal)  
		      AlFonts_get_specific_fonts(rei->OuterW, 
						 ALFONTS_TEXT_MASK));
      ArgPack_add_arg(AP, XmNcursorPosition,(XtArgVal) 
		      strlen(field->Key));
      field->KeyW=XtCreateManagedWidget("field-key",
					xmTextWidgetClass,
					field->LeftContainerW,
					ArgPack_the_args(AP),
					ArgPack_num_args(AP));
      MuSetSingleLineEmacsBindings(field->KeyW);
      ArgPack_delete(AP);
      
      XtAddCallback(field->KeyW,XmNvalueChangedCallback,
		    d2_KeyModify_CB,
		    field->rei);
      XtAddCallback(field->KeyW,XmNfocusCallback,
		    d2_Field_select_CB,
		    field);
      XtAddCallback(field->KeyW,XmNlosingFocusCallback,
		    ed_Field_key_justify_CB,
		    field);
    }
    else {
      if (Args!=NULL) {
	XtUnmanageChild(field->KeyW);
	XtSetValues(field->KeyW,
		    ArgPack_the_args(Args),
		    ArgPack_num_args(Args));
      }
      XtManageChild(field->KeyW);
      /* if we are swapping widgets with an old menu, that menu was part of */
      /* the tab group and when the groups get redone we will attempt to */
      /* remove that widgets tab group, so we make sure its still there. */
      /* Any key widget in the OtherKeyW slot must be untabbed and any key */
      /* restored from there must be tabbed */
      XmAddTabGroup(field->KeyW);
    }
  }
  /*
   * WE WANT IT TO BE A MENU */
  else {  
    if (field->KeyIsMenu==Bool_FALSE) {
      Widget tempW=field->OtherKeyW;
      if (field->KeyW!=NULL) {
	XtUnmanageChild(field->KeyW);
	XmRemoveTabGroup(field->KeyW);
      }
      field->OtherKeyW=field->KeyW;
      field->KeyW=tempW;
      field->KeyIsMenu=Bool_TRUE;
    }
    /* !!! BAD STUFF, should detect if this menu is O.K. and keeep it, */
    /* can't now because rule language doesn't support and easy way to */
    /* keep track of this info */
    if (field->KeyMenu!=NULL) {
      MenuPack_destroy(field->KeyMenu);
      field->KeyMenu=NULL;
    }
    if (field->KeyW!=NULL) {
      XtDestroyWidget(field->KeyW);
      field->KeyW=NULL;
    }

    field->KeyMenu=d2_Field_make_key_menu(field);
    AP=ArgPack_duplicate_args(d2_field_edit_menu);
    ArgPack_copy_and_append(AP,Args);
    ArgPack_add_arg(AP, XmNheight, (XtArgVal) rei->if_field_height );
    ArgPack_add_arg(AP, XmNmarginWidth,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNmarginHeight,  (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNshadowThickness, (XtArgVal) 0 );
    ArgPack_add_arg(AP, XmNhighlightThickness, (XtArgVal) 0 );
    MenuPack_option_set_args(field->KeyMenu,AP);
    MenuPack_attach_to_widget(field->KeyMenu,field->LeftContainerW);
    MenuPack_make_menu(field->KeyMenu);
    ArgPack_delete(AP);
    
    field->KeyW=MenuPack_get_top_level_manager(field->KeyMenu);
    XmAddTabGroup(field->KeyW);

    /* ADD FOCUS CATCHING STUFF */
    d2_Field_add_focus(field,field->KeyW);

    /* this will work because the name of the field class will be in this */
    /* menu because we know it is a state */
    MenuPack_set_as_default(field->KeyMenu,field->FieldClass);
    
    d2_Field_shrink_option_menu(rei,field->KeyMenu,field->KeyW);
  }
}


/*--------------------------------------------------*/
NORET d2_Field_add_focus(field,w)
     REField field;
     Widget w;
{
  reid rei=field->rei;
  static XtTranslations Translations=NULL;

  if (Translations==NULL) {
    XtAppAddActions(rei->AppContext,d2_FieldActions,d2_FieldActionsCount); 
    Translations=XtParseTranslationTable(d2_FieldFocusEvent);
  }
  
  Alxt_SetArg(w, XmNuserData,(XtArgVal) field);
  XtOverrideTranslations(w,Translations);
}

/*--------------------------------------------------*/
NORET d2_Field_select_E(w,xe,parms,np)
     Widget w;
     XEvent *xe;
     char** parms;
     int *np;
{
  REField field;
  reid rei;

  field=(REField)Alxt_get_widget_feature(w,XmNuserData);
  rei=field->rei;
  rei->SelectedType=RE_SELECT_FIELD;
  rei->Selected=field;
  d2_Buttons_update(rei);
}

/*--------------------------------------------------*/
NORET d2_Field_select_CB(w,ref,wd)
     Widget w;
     REField ref;
     caddr_t wd;
{
  reid rei;
  
  RE_debug1("selected field %s\n",ref->Key);
  rei=ref->rei;
  rei->Selected=(VOIDP)ref;
  rei->SelectedType=RE_SELECT_FIELD;
  d2_Buttons_update(rei);
}

/*--------------------------------------------------*/
NORET d2_Field_to_simple(field)
     REField field;
{
  if (field->VisibleMode==RE_MODE_SIMPLE) return;
  /* take care of the class and key widget */
  XtUnmanageChild(field->ClassW);
  Alxt_SetArg(field->KeyW,XmNtopAttachment,(XtArgVal) XmATTACH_FORM);

  /* take care of the type widget */
  XtUnmanageChild(field->TypeW);

  if (field->ShowOp==Bool_TRUE)
    Alxt_SetArg(field->OpW,XmNtopAttachment,(XtArgVal) XmATTACH_FORM);
  else {
    XtUnmanageChild(field->OpW);
    Alxt_SetArg(field->ValueW,XmNleftAttachment,(XtArgVal) XmATTACH_FORM);
  }
  Alxt_SetArg(field->ValueW,XmNtopAttachment,(XtArgVal) XmATTACH_FORM);

  Alxt_SetArg(field->ContainerW,XmNheight,(XtArgVal) 
	      field->rei->if_field_height);
  
  field->VisibleMode=RE_MODE_SIMPLE;
  d2_Field_remake_field_size(field);
  d2_Refresh_tab_groups(field->rei);
}


/*--------------------------------------------------*/
NORET d2_Field_shrink_option_menu(rei,menu,menuW)
     reid rei;
     MenuPack menu;
     Widget menuW;
{
  Widget button=XmOptionButtonGadget(menuW);
  Widget label=XmOptionLabelGadget(menuW);
  int button_w;
  
  Alxt_SetArg(menuW,XmNheight, (XtArgVal) rei->if_field_height );
  Alxt_SetArg(menuW,XmNmarginWidth, (XtArgVal) 0 );
  Alxt_SetArg(menuW,XmNmarginHeight, (XtArgVal) 0 );

  if (button!=NULL) {
    Alxt_SetArg(button,XmNtraversalOn, (XtArgVal) TRUE );
    Alxt_SetArg(button,XmNheight, (XtArgVal) rei->if_field_inner_height );
    button_w=(int)Alxt_get_widget_feature(button,XmNwidth);
  }
  
  if (button!=NULL)
    Alxt_SetArg(button,XmNshadowThickness,(XtArgVal) ShadowThickness_GR);
  if (label!=NULL)
    XtDestroyWidget(label);

  if (button!=NULL) {
    RE_debug1("setting to button_w of  %d\n", button_w );
    Alxt_SetArg(menuW,XmNwidth, (XtArgVal) button_w);
  }
}


/*--------------------------------------------------*/
NORET d2_Field_remake_field_size(field)
     REField field;
{
  reid rei=field->rei;
  int KeyWidth1, KeyWidth2;
  Widget button;

  if (field->KeyIsMenu==Bool_TRUE) {
    button=MenuPack_option_get_button(field->KeyMenu);
    KeyWidth1=(int)Alxt_get_widget_feature(button,XmNwidth);
  }
  else
    KeyWidth1=(int)Alxt_get_widget_feature(field->KeyW,XmNwidth);

  if (field->ClassW!=NULL && field->VisibleMode==RE_MODE_COMPLEX) {
    button=MenuPack_option_get_button(field->ClassMenu);
    KeyWidth2=(int)Alxt_get_widget_feature(button,XmNwidth);
  }
  else
    KeyWidth2=0;
  RE_debug2("KEY WIDTH=%d,%d\n",KeyWidth1,KeyWidth2);
  KeyWidth1=max(KeyWidth1,KeyWidth2);
  Alxt_SetArg(field->LeftContainerW,XmNwidth,(XtArgVal) KeyWidth1+
	      ShadowThickness_GR);
  if (field->KeyIsMenu==Bool_FALSE)
    Alxt_SetArg(field->KeyW,XmNwidth,(XtArgVal) KeyWidth1+
		ShadowThickness_GR);
  
  if (field->VisibleMode==RE_MODE_COMPLEX)
    Alxt_SetArg(field->ContainerW,XmNheight,(XtArgVal)
		(2*rei->if_field_height)+ShadowThickness_GR);
  else
    Alxt_SetArg(field->ContainerW,XmNheight,(XtArgVal) rei->if_field_height);
}

