#include "xstuff.h"
#include "string.h"
#include <ctype.h>
#include "useful.h"
#include "assert.h"
#include "res.h"
#include "widgets.h"
#include "ArgPack.h"
#include "darray.h"
#include "FTreg.h"
#include "FieldType.h"
#include "verbs.h"
#include "verbrgy.h"
#include "verb.h"
#include "rule.h"
#include "ruleset.h"
#include "action.h"
#include "verbrgy.h"
#include "end.h"
#include "stddef.h"
#include "rl.h"
#include "ft.h"
#include "ru.h"
#include "rs.h"
#include "mt.h"
#include "ed.h"
#include "al.h"
#include "d1.h"
#include "opvalscan.h"
#include "rap.h"
#include "profile.h"
#include "RMFBuffer.h"
#include "biregistry.h"
#include "memory.h"

   /* other function declarations in rl.h should be here */
#ifdef __STDC__
Bool rl_FieldOp_make_correct_case(AlFieldType,char*);
#else
Bool rl_FieldOp_make_correct_case();
#endif

#define RapSStr_duplicate(x) RapStr_duplicate(x)

static AlRFType RegFC_data[]= {
 ALRFT_MSG,  /*-- Field Class Message */
 ALRFT_UP,   /*-- Field Class User Property */
 ALRFT_FI,   /*-- Field Class Folder-specific info */
};
#define FIELD_CLASS_CASCADER_STR "Change Field Class"
#define FIELD_CLASS_SUB_MENU_HEADER_STR "This field is from..."
static char *RegFC_data_strings[]={
  "the message",
  "the list of user properties",
  "the folder",
  NULL,
};
#define STATE_CASCADER_STR "or, it is about the message..."
#define STATE_SUB_MENU_HEADER_STR "Things Computed About the Message"
static AlRFType StateFT_data[]={
 ALRFT_SMF,  /*-- Field Type State, Moved From */
 ALRFT_SNTM, /*-- State, Number of Times Moved */
 ALRFT_SNRF, /*-- State, Number of Rules Fired */
 ALRFT_SNOF, /*-- State, Number Of Fields */
 ALRFT_SMLL, /*-- State, Message Line Length */
 ALRFT_SMCL, /*-- State, Message Character Length */
 ALRFT_SBLL, /*-- State, Body Line Length */
 ALRFT_SBCL, /*-- State, Body Character Length */
 ALRFT_SNUB, /*-- State, Number of Unprintables in Body */
 ALRFT_SFC, 
};

static char *StateFT_data_strings[]={
  "Moved From",
  "Number of Times Moved",
  "Number of Rules Fired On Message",
  "Number of Fields in Message",
  "Number of Lines in Message",
  "Number of Characters in Message",
  "Number of Lines in Body",
  "Number of Characters in Body",
  "Unprintables in Body",
  "Field Count",
  NULL,
};

static char *StateFC_default_FTs_data[]={
  "Same-Case-Text",
  "Integer",
  "Integer",
  "Integer",
  "Integer",
  "Integer",
  "Integer",
  "Integer",
  "Boolean",
  "Integer",
};

#define EXIST_OP_NAME "FIELD EXISTANCE"
#define EXIST_OP_INDICATOR "EXISTS"
#define AVAILABLE_OPS "AVAILABLE OPERATORS"
#define DELETE_STR "Remove This Field"

#define ACT_AVAILABLE "Available Actions"
#define ACT_OPTIONS "Options"
#define ACT_CHANGE_SMP "Change This Action"
#define ACT_DELETE_STR "Remove This Action"

char PredValueTranslations[] =
    "Ctrl<Key>F:		forward-character() \n\
     <Key>0xff53:		forward-character() \n\
     Ctrl<Key>B:		backward-character() \n\
     <Key>0xff51:		backward-character() \n\
     Meta<Key>F:		forward-word() \n\
     Meta<Key>B:		backward-word() \n\
     Meta<Key>]:		forward-paragraph() \n\
     Ctrl<Key>[:		backward-paragraph() \n\
     Ctrl<Key>A:		beginning-of-line() \n\
     Ctrl<Key>E:		end-of-line() \n\
     Ctrl<Key>N:		next-line() \n\
     <Key>0xff54:		next-line() \n\
     Ctrl<Key>P:		previous-line() \n\
     <Key>0xff52:		previous-line() \n\
     Ctrl<Key>V:		next-page() \n\
     Meta<Key>V:		previous-page() \n\
     Meta<Key>\\<:		beginning-of-file() \n\
     Meta<Key>\\>:		end-of-file() \n\
     Ctrl<Key>Z:		scroll-one-line-up() \n\
     Meta<Key>Z:		scroll-one-line-down() \n\
     Ctrl<Key>D:		delete-next-character() \n\
     Ctrl<Key>H:		delete-previous-character() \n\
     <Key>0xff7f:		delete-previous-character() \n\
     <Key>0xffff:		delete-previous-character() \n\
     <Key>0xff08:		delete-previous-character() \n\
     Meta<Key>D:		delete-next-word() \n\
     Meta<Key>H:		delete-previous-word() \n\
     Shift Meta<Key>D:		kill-word() \n\
     Shift Meta<Key>H:		backward-kill-word() \n\
     Ctrl<Key>W:		kill-selection() \n\
     Ctrl<Key>K:		kill-to-end-of-line() \n\
     Meta<Key>K:		kill-to-end-of-paragraph() \n\
     Ctrl<Key>Y:		unkill() \n\
     Meta<Key>Y:		stuff() \n\
     Ctrl<Key>J:		newline-and-indent() \n\
     <Key>0xff0a:		newline-and-indent() \n\
     Ctrl<Key>O:		newline-and-backup() \n\
     Ctrl<Key>M:		newline() \n\
     <Key>0xff0d:		newline() \n\
     Ctrl<Key>L:		redraw-display() \n\
     Meta<Key>I:		insert-file() \n\
     <FocusIn>:			focus-in() \n\
     <FocusOut>:		focus-out() \n\
     <Btn1Down>:		select-start() \n\
     Button1<PtrMoved>:		extend-adjust() \n\
     <Btn1Up>:			extend-end() \n\
     <Btn2Down>:		stuff() \n\
     <Btn3Down>:		extend-start() \n\
     Button3<PtrMoved>:		extend-adjust() \n\
     <Btn3Up>:			extend-end() \n\
     <Key>:			rl-insert-char() \n\
     Shift<Key>:		rl-insert-char()";

/*--------------------------------------------------*/
void rl_Init(rei)
reid rei;
{
  REAssoc REa;
  char *name;
  unsigned i,j,l,l2;
  Bool exists;
  Darray ProfileFTOrder=Darray_create();
  Darray ProfileVerbOrder=Darray_create();
  Darray Found;
  RegFTs_GR=Darray_create();
  NameToFC_GR=Biregistry_create(Registry_strcmp,Registry_strhash,
				Registry_ptrcmp,Registry_ptrhash);
  i=0;
  while ((name=RegFC_data_strings[i])!=NULL) {
    Darray_addh(RegFTs_GR,name);
    Biregistry_add(NameToFC_GR,(VOIDP)name,(VOIDP)RegFC_data[i]);
    i++;
  }
  StateFTs_GR=Darray_create();
  StateFC_def_FTs_GR=Darray_create();
  i=0;
  while ((name=StateFT_data_strings[i])!=NULL) {
    Darray_addh(StateFTs_GR,name);
    Darray_addh(StateFC_def_FTs_GR,StateFC_default_FTs_data[i]);
    Biregistry_add(NameToFC_GR,(VOIDP)name,(VOIDP)StateFT_data[i]);
    i++;
  }

/*---- make the field type presentation order */  
  l2=Darray_len(FieldTypeNames_GR);
  FieldTypePresOrder_GR=Darray_create();
  if (AlProfile_has_value(ALPROF_FTORD)==Bool_FALSE) {
    RE_debug("ft no order\n");
    for (i=0;i<l2;i++)
      Darray_addh(FieldTypePresOrder_GR,
		  RapStr_duplicate(Darray_get(FieldTypeNames_GR,i)));
  }
  else {
    RE_debug("else\n");
               /* clear the foundverbs darray.  This darray has a bool_TRUE */
	       /* for every verb in verbanames that was listed in the verb */
	       /* pres order. it is thus the same size as the verbnames */
    Found=Darray_create();
    for (i=0;i<l2;i++) Darray_addh(Found,Bool_FALSE);
    rl_Parse_list_into_darray(ProfileFTOrder,
			      AlProfile_get_CP_val(ALPROF_FTORD));
    l=Darray_len(ProfileFTOrder);
    for (i=0;i<l;i++) {
      name=Darray_get(ProfileFTOrder,i);
      exists=Bool_FALSE;
      for (j=0;j<l2;j++) {
	if (strcasecmp(name,Darray_get(FieldTypeNames_GR,j))==0) {
	  exists=Bool_TRUE;
	  if (Bool_FALSE==(Bool)Darray_get(Found,j)) {
	    Darray_addh(FieldTypePresOrder_GR,
			RapStr_duplicate(Darray_get(FieldTypeNames_GR,j)));
	    Darray_set(Found,j,(VOIDP)Bool_TRUE);
	    RE_debug1("Found[%d] when parsing =Bool_TRUE\n",j);
	    break;
	  }
	}
      }
      if (exists==Bool_FALSE) {
	Al_warning1("ruleeditor: the field type %s appearing in the profile",
		    name);
	Al_warning("            component FieldTypePresentationOrder is not \
valid.");
      }
    }
    rl_Parse_list_into_darray_destroy(ProfileFTOrder);
    Darray_destroy(ProfileFTOrder);
    /* now we have to add any verbs that were not part of the verb pres */
    /* order to the presentation order. */
    for (i=0;i<l2;i++) {
      RE_debug2("Found[%d]=%s\n",i,
		(Bool_TRUE==(Bool)Darray_get(Found,i)) ? 
		"Bool_TRUE" :"Bool_FALSE");
      if (Bool_FALSE==(Bool)Darray_get(Found,i)) {
	RE_debug1("added field type %s.\n",Darray_get(FieldTypeNames_GR,i));
	Darray_addh(FieldTypePresOrder_GR,
		    RapStr_duplicate(Darray_get(FieldTypeNames_GR,i)));
      }
    }
    Darray_destroy(Found);
  }

  l2=Darray_len(VerbNames_GR);
  VerbPresOrder_GR=Darray_create();
  if (AlProfile_has_value(ALPROF_VERBORD)==Bool_FALSE) {
    for (i=0;i<l2;i++)
      Darray_addh(VerbPresOrder_GR,
		  RapStr_duplicate(Darray_get(VerbNames_GR,i)));
  }
  else {
    Found=Darray_create();
               /* clear the Found darray.  This darray has a bool_TRUE */
	       /* for every verb in verbanames that was listed in the verb */
	       /* pres order. it is thus the same size as the verbnames */
    rl_Parse_list_into_darray(ProfileVerbOrder,
			      AlProfile_get_CP_val(ALPROF_VERBORD));
    for (i=0;i<l2;i++) Darray_addh(Found,Bool_FALSE);
    l=Darray_len(ProfileVerbOrder);
    for (i=0;i<l;i++) {
      name=Darray_get(ProfileVerbOrder,i);
      exists=Bool_FALSE;
      for (j=0;j<l2;j++)
	if (strcasecmp(name,Darray_get(VerbNames_GR,j))==0) {
	  exists=Bool_TRUE;
	  if (Bool_FALSE==(Bool)Darray_get(Found,j)) {
	    Darray_addh(VerbPresOrder_GR,
			RapStr_duplicate(Darray_get(VerbNames_GR,j)));
	    Darray_set(Found,j,(VOIDP)Bool_TRUE);
	  }
	}
      if (exists==Bool_FALSE) {
	Al_warning1("ruleeditor: the verb %s appearing in the profile",
		    name);
	Al_warning("            component VerbPresentationOrder is not \
valid.");
      }
    }
    rl_Parse_list_into_darray_destroy(ProfileVerbOrder);
    Darray_destroy(ProfileVerbOrder);
    /* now we have to add any verbs that were not part of the verb pres */
    /* order to the presentation order. */
    for (i=0;i<l2;i++) {
      if (Bool_FALSE==(Bool)Darray_get(Found,i)){
	Darray_addh(VerbPresOrder_GR,
		    RapStr_duplicate(Darray_get(VerbNames_GR,i)));
      }
    }
    Darray_destroy(Found);
  }
  
  RE_debug1("rei->rule= 1(NULL)=%d\n",
	    ((rei->Rule==NULL) ? 1 : 2));
  
  if (rei->Rule!=NULL) {
    rei->TopLevelMember=rl_TranslateToRE(rei,AlRule_get_predicate(rei->Rule));
    rei->Actions=rl_TranslateActionsToRE(rei,AlRule_get_actions(rei->Rule));
  }
  else 
    Al_fatal_error("ruleeditor: requires a non-null rule.\n");
}
 
/*--------------------------------------------------*/
/* rl_destroy should destroy  (this is an incomplete list)  */
/*    FieldTypePresOder and use RapStr_destroy to kill each of its members. */
/*--------------------------------------------------*/

/*--------------------------------------------------*/
REMember rl_REMember_create(Type,object,father)
AlRMType Type;
VOIDP   object;
REMember  father;
{
  REAssoc REa;
  REField REf;
   
  REMember r;
  r=(REMember)Memory_allocate(sizeof(struct REMember_str));
  r->Type=Type;
  if (Type==ALRMT_ASSOC) {
    r->object.Assoc=(REAssoc)object;
    REa=(REAssoc)object;
    REa->container=r;
  }
  else if (Type==ALRMT_FIELD) {
    r->object.Field=(REField)object;
    REf=(REField)object;
    REf->container=r;
  }
  else 
    assert(0);
  r->father=father;
  if (father!=NULL) 
    Darray_addh(father->object.Assoc->Contents,r);
  return(r);
}

/*--------------------------------------------------*/
REMember rl_REMember_create_at_index(Type,object,father,index)
AlRMType Type;
VOIDP   object;
REMember  father;
int index;
{
  REAssoc REa;
  REField REf;
   
  REMember r;
  r=(REMember)Memory_allocate(sizeof(struct REMember_str));
  r->Type=Type;
  if (Type==ALRMT_ASSOC) {
    r->object.Assoc=(REAssoc)object;
    REa=(REAssoc)object;
    REa->container=r;
  }
  else if (Type==ALRMT_FIELD) {
    r->object.Field=(REField)object;
    REf=(REField)object;
    REf->container=r;
  }
  else 
    assert(0);
  r->father=father;
  if (father!=NULL) 
    rl_Darray_insert(father->object.Assoc->Contents,r,index);
  return(r);
}

/*--------------------------------------------------*/
REField rl_REField_create(rei,Type,Key,Value,FieldType,FieldOp,FW)
reid rei;
AlRFType Type;
char *Key, *Value, *FieldType, *FieldOp;
REFromWhere FW;
{
  REField f;
  char *string, *tempo;
  Darray FieldOps=Darray_create();
  Bool UsingDFO;
  unsigned vlength;

  f=(REField)Memory_allocate(sizeof(struct REField_str));
  f->rei=rei;
  f->Type=Type;
  f->FromWhere=FW;
  f->IsState=rl_IsState(Type);

  if (f->IsState==Bool_TRUE) {
    char *t;
    t=Biregistry_rev_get(NameToFC_GR,(VOIDP)Type);
    f->Key=Memory_allocate((f->MaxKeyLength=strlen(t)+1));
    strcpy(f->Key,t);
  }
  else {  /* right justifies the key and makes sure there is a colon at the */
          /* end of it. */
    char *tkey;
    int mod;
    mod=0;
    if (f->Type==ALRFT_MSG) {
      tkey=rl_Key_rj_and_add_colon(Key,KEY_LENGTH,&mod);
      f->MaxKeyLength=strlen(tkey)+KEY_LENGTH;
      f->Key=strcpy(Memory_allocate(f->MaxKeyLength+1),tkey);
      if (mod==1) Memory_free(tkey);
    }
    else {
      f->MaxKeyLength=strlen(Key)+KEY_LENGTH;
      f->Key=strcpy(Memory_allocate(f->MaxKeyLength+1),Key);
    }
  }
  if (FieldType==NULL) {
    f->FieldTypeObject=DefaultFT_GR;
    string=AlFTreg_obj_to_string(DefaultFT_GR);
    f->FieldType=strcpy(Memory_allocate(strlen(string)+1),string);
  }
  else {
    f->FieldTypeObject=AlFTreg_string_to_obj(FieldType);
    f->FieldType=strcpy(Memory_allocate(strlen(FieldType)+1),FieldType);
  }

  AlFieldType_get_field_op_list(f->FieldTypeObject,FieldOps);
  /* this serves as getting the default field operator for a field type */
  f->defaultFieldOp=RapStr_duplicate((char *)Darray_get(FieldOps,0));

  if (FieldOp==NULL || FieldOp[0]=='\0') {
    f->FieldOp=RapStr_duplicate(f->defaultFieldOp);
    UsingDFO=Bool_TRUE;
  }
  else {
    if (rl_Field_op_is_valid(f->FieldTypeObject,FieldOp)==Bool_FALSE) {
      char s[300];
      f->FieldOp=RapStr_duplicate(f->defaultFieldOp);
      sprintf(s,
	      "The field operator %s for field %s is invalid.\n\
            It is being replaced with the default operator %s.\n\
            The new field operator will not become permanent untill \n\
            the rule is saved.",
	      FieldOp, f->Key, f->FieldOp);
      repop_Query(f->ValueW,"Rule Editor",s,"O.K.");
      UsingDFO=Bool_TRUE;  /* usingDFO is ysed to select weather we display */
			   /* the field op on the screen or not. */
    }
    else {
      if (strcmp(f->defaultFieldOp,FieldOp)==0)
	UsingDFO=Bool_TRUE;
      else
	UsingDFO=Bool_FALSE;
      f->FieldOp=strcpy(Memory_allocate(strlen(FieldOp)+1),FieldOp);
    }
  }
  
  Darray_destroy(FieldOps);

  if (Value!=NULL)
    f->Value=strcpy(Memory_allocate(strlen(Value)+1),Value);
  else
    f->Value=NULL;

  if (UsingDFO==Bool_TRUE)
    tempo=NULL;
  else
    tempo=f->FieldOp;
  
  vlength=strlen(f->Value)+strlen(f->FieldOp)+VALUE_LENGTH+2;
  f->ValueBuffer=Memory_allocate(vlength);
  while (Alopvalmake(f->ValueBuffer,vlength,tempo,f->Value)==Bool_FALSE) {
    vlength=vlength+vlength;
    f->ValueBuffer=Memory_reallocate(f->ValueBuffer,vlength);
  }
  f->MaxValueBufferLength=vlength;
  
  f->AltsMenu=rl_MakeAltsMenu(f);
  f->FTMenu=rl_MakeFTMenu(rei,f);
  f->KeyW=NULL; 
  f->ValueW=NULL;
  f->AltsMenuW=NULL, f->FTMenuW=NULL; f->ContainerW=NULL;
  f->FTMenuLabelW=NULL;
  f->ExistanceOp=Bool_FALSE;  /* !!! has to be dynamic depending on inputs */
			      /* */
  f->ValueBufferSave=NULL;

  sprintf(f->MyAddress,"%x",f);
  f->predValTranslations=rl_REField_make_translation("<Leave>",
						     "rl_Monitor_field_value",
						     f->MyAddress);
  if (FW==REF_FROM_USER) 
    f->predKeyTranslations=rl_REField_make_translation("<Leave>",
						       "rl_Monitor_field_key",
						       f->MyAddress);
  else
    f->predKeyTranslations=NULL;
  RE_debug1("trans=%s\n",f->predValTranslations);
  rl_REField_register_address(f);
  f->ValueIsParsable=Bool_TRUE;
  return(f);
}


/*--------------------------------------------------*/
MenuPack rl_MakeAltsMenu(f)
REField f;
{
  MenuPack mp, sm;
  FieldRet FRet;
  unsigned i, l, j, l2;
  Darray FieldOps=Darray_create();
  Darray FieldOpFuncs=Darray_create();
  char *name, *fieldop;
  FieldOperatorProc *opProc;
  FTOpRet FTOR;
  Bool addit;

  mp=MenuPack_create(NULL,"Field Types");
  l=Darray_len(FieldTypePresOrder_GR);
  for (i=0;i<l;i++) {
    name=(char*)Darray_get(FieldTypePresOrder_GR,i);
    FRet=FieldRet_create(name,f);
    MenuPack_add_option(name,mp,
			(XtCallbackProc)rl_SelectFT_CB,
			(caddr_t)FRet);
  }
  MenuPack_add_option(EXIST_OP_NAME,mp,
		      (XtCallbackProc)rl_Existance_CB,
		      (caddr_t)f);
  sm=MenuPack_create(NULL,"OPERATORS");
  AlFieldType_get_field_op_list(f->FieldTypeObject,FieldOps);
  l=Darray_len(FieldOps);
  for (i=0;i<l;i++) {
    fieldop=(char *)Darray_get(FieldOps,i);
    opProc=AlFieldType_get_field_op_proc(f->FieldTypeObject,fieldop);
    l2=Darray_len(FieldOpFuncs);
    addit=Bool_TRUE;
    for (j=0;j<l2;j++) {
      if (opProc==(FieldOperatorProc*)Darray_get(FieldOpFuncs,j)) {
	addit=Bool_FALSE;
	break;
      }
    }
    if (addit==Bool_TRUE) {
      Darray_addl(FieldOpFuncs,opProc);
      FTOR=(FTOpRet)Memory_allocate(sizeof(struct FTOpRet_str));
      FTOR->fieldOp=fieldop;
      FTOR->Field=f;
      MenuPack_add_option(FTOR->fieldOp,sm,
			  (XtCallbackProc)rl_SelectFieldOp_CB,
			  (caddr_t)FTOR);
    }
  }
  Darray_destroy(FieldOpFuncs);
  Darray_destroy(FieldOps);
  MenuPack_add_sub_menu(AVAILABLE_OPS,mp,sm);
  return(mp);
}

/*--------------------------------------------------*/
NORET rl_Parse_list_into_darray(d,s)
Darray d;
char* s;
{
  unsigned low, high;
  char c;

  low=0;
  while (isspace(s[low]) && s[low]!='\0') low++;
  high=low;
  while (s[high]!='\0') {
    low=high;
    while (isspace(s[low]) && s[low]!='\0') low++;
    high=low;
    if (s[low]!='\0') {
      while (!(isspace(s[high])) && (s[high]!=',') && (s[high]!='\0')) high++;
      c=s[high];
      s[high]='\0';
      Darray_addh(d,RapStr_duplicate(&(s[low])));
      s[high]=c;
    }
    while (s[high]!=',' && s[high]!='\0') high++;
    if (s[high]==',') high++;
  }
}

/*--------------------------------------------------*/
NORET rl_Parse_list_into_darray_destroy(d)
Darray d;
{
  unsigned i,l;
  l=Darray_len(d);
  for(i=0;i<l;i++)
    RapStr_destroy(Darray_reml(d));
}

/*--------------------------------------------------*/
void rl_RedoValueString(Field,fieldOp)
REField Field;
char *fieldOp;
{
  unsigned vbl, vblNew, stringl;
  char *buff, *opbuff, *newbuff;
  XtTextBlock MyTextBlock;
  unsigned vlength;
  Bool quoted;

  if (Field->FieldOp!=NULL)
    safe_free(Field->FieldOp);
  Field->FieldOp=RapStr_duplicate(fieldOp);
  stringl=strlen(fieldOp);
  vbl=strlen(Field->ValueBuffer);
  buff=(char*)Memory_allocate(vbl+1);
  opbuff=(char*)Memory_allocate(vbl+1);
  newbuff=(char*)Memory_allocate(vbl+stringl+1);

  Alopvalscan2(Field->ValueBuffer,opbuff,buff,&quoted);

  if (quoted==Bool_TRUE) {
    RMFBuffer B=RMFBuffer_create("",20);
    RMFBuffer_append_char(B,'"');
    RMFBuffer_append(B,buff);
    RMFBuffer_append_char(B,'"');
    Memory_free(buff);
    buff=RMFBuffer_copy_of_buff(B);
    RMFBuffer_destroy(B);
  }
  vlength=strlen(buff)+strlen(fieldOp)+VALUE_LENGTH+2;
  newbuff=Memory_allocate(vlength);
  while (Alopvalmake(newbuff,vlength,fieldOp,buff)==Bool_FALSE) {
    vlength=vlength+vlength;
    newbuff=Memory_reallocate(newbuff,vlength);
  }
  safe_free(buff);
  safe_free(opbuff);

  vblNew=strlen(newbuff);
  MyTextBlock.firstPos=0;
  MyTextBlock.length=vblNew;
  MyTextBlock.ptr=newbuff;
  XtTextReplace(Field->ValueW,
		0,
		vbl,
		&MyTextBlock);
  
  Alxt_SetArg(Field->ValueW,XtNinsertPosition,vblNew);

  safe_free(newbuff);
}

/*
  SW=MenuPack_get_widget(Field->AltsMenu,Field->FieldOp);
  if (SW!=NULL)  {
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsetMark,(XtArgVal) FALSE);
    XtSetValues(SW,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
  else
    printf("warning: couldn't find field operator %s\n",Field->FieldOp);
*/

/*--------------------------------------------------*/
void rl_SelectFieldOp_CB(w,ftor_data,cadda)
     Widget w;
     caddr_t ftor_data;
     caddr_t cadda;
{
  REField Field;
  Widget SW;
  ArgPack AP;
  FTOpRet ftor;
  Bool b;
  
  ftor=(FTOpRet)ftor_data; 
  Field=ftor->Field;
  if (Bool_FALSE==(Bool)Alxt_set_menu_item_with_arg(Field->AltsMenu,
						    Field->FieldOp,
						    XtNsetMark,
						    (XtArgVal)FALSE))
    Al_warning2("ruleeditor: could not find field op %s for filed %s.",
		Field->FieldOp, Field->Key);
  
  rl_RedoValueString(Field,ftor->fieldOp);
  
  if (Bool_FALSE==(Bool)Alxt_set_menu_item_with_arg(Field->AltsMenu,
						    ftor->fieldOp,
						    XtNsetMark,
						    (XtArgVal)TRUE)) {
    if (rl_Field_op_is_valid(Field->FieldTypeObject,
			     ftor->fieldOp)==Bool_FALSE) 
      Al_fatal_error("ruleeditor: SelectFieldOp_CB: fatal error: should never occur.\n");
  }
}
  
/*--------------------------------------------------*/
MenuPack rl_MakeFTMenu(rei,f)
reid rei;
REField f;
{
  MenuPack mmp, mp, smp;
  FieldRet FRet;
  unsigned i;
  char *name;

  mmp=MenuPack_create(NULL,"Options");
  if (f->FromWhere==REF_FROM_USER) {
    mp=MenuPack_create(NULL,FIELD_CLASS_SUB_MENU_HEADER_STR);
    for (i=0;i<Darray_len(RegFTs_GR);i++) {
      name=Darray_get(RegFTs_GR,i);
      FRet=FieldRet_create(name,f);
      MenuPack_add_option(name,mp,
			  (XtCallbackProc)rl_RegSelectFC_CB,
			  (caddr_t)FRet);
    }
    smp=MenuPack_create(NULL,STATE_SUB_MENU_HEADER_STR);
    for (i=0;i<Darray_len(StateFTs_GR);i++) {
      name=Darray_get(StateFTs_GR,i);
      FRet=FieldRet_create(name,f);
      MenuPack_add_option(name,smp,
			  (XtCallbackProc)rl_StateSelectFC_CB,
			  (caddr_t)FRet);
    }
    MenuPack_add_sub_menu(STATE_CASCADER_STR,mp,smp);
  }
  else {
    mp=MenuPack_create(NULL,FIELD_CLASS_SUB_MENU_HEADER_STR);
    MenuPack_add_option(Biregistry_rev_get(NameToFC_GR,(VOIDP)f->Type),mp,NULL,NULL);
  }
  MenuPack_add_sub_menu(RapSStr_duplicate(FIELD_CLASS_CASCADER_STR),mmp,mp);
  MenuPack_add_option(DELETE_STR,mmp,
		      ed_Field_delete_CB,
		      (caddr_t)RapPack_create2((VOIDP)f,(VOIDP)rei));
  return(mmp);
}

/*-----------------------*/
void rl_SelectFT_CB(w,FR,data)
Widget w;
FieldRet FR;
caddr_t data;
{
  Widget ShellW;
  char  *string;
  AlFieldType FT;
  Darray Ops=Darray_create();
  REField Field=FR->Field;
  reid rei=Field->rei;

  if (Field->IsState==Bool_TRUE) {
    printf("Rule Editor:can't alter the Field Type of a Message State\n");
    return;
  }

  if (Field->ExistanceOp==Bool_TRUE) 
    rl_Existance_reset_from(Field); 

  safe_free(Field->FieldType);
  Field->FieldType=strcpy(Memory_allocate(strlen(FR->name)+1),FR->name);
  FT=AlFTreg_string_to_obj(FR->name);
  Field->FieldTypeObject=FT;
  if ((AlFieldType_get_field_op_list(FT,Ops))==Bool_FALSE)
    Al_fatal_error("couldn;t get default field operator\n");
  string=(char *)Darray_get(Ops,(unsigned)0);
  Field->FieldOp=RapStr_duplicate(string);

  { /* this code makes sure that there is no extraneous field operator in */
    /* the field when we switch to a new field type. */
    unsigned vbl,vlength;
    char *vbuff, *obuff;
    XtTextBlock MyTextBlock;
    RMFBuffer B;
    Bool quoted;

    vbl=strlen(Field->ValueBuffer);
    vbuff=Memory_allocate(vbl+1);
    obuff=Memory_allocate(vbl+1);
    Alopvalscan2(Field->ValueBuffer,obuff,vbuff,&quoted);
    
    if (quoted==Bool_TRUE) {
      B=RMFBuffer_create("",20);
      RMFBuffer_append_char(B,'"');
      RMFBuffer_append(B,vbuff);
      RMFBuffer_append_char(B,'"');
    }
    else 
      B=RMFBuffer_create(vbuff,20);

    MyTextBlock.firstPos=0;
    MyTextBlock.length=RMFBuffer_length_of_string(B);
    MyTextBlock.ptr=RMFBuffer_copy_of_buff(B);
    XtTextReplace(Field->ValueW,
		  0,
		  strlen(Field->ValueBuffer),
		  &MyTextBlock,
		  FALSE);
    
    safe_free(vbuff);
    safe_free(obuff);
    RMFBuffer_destroy(B);
  }

  ShellW=MenuPack_get_top_level_shellW(Field->AltsMenu);
  XtUnmanageChild(ShellW);
  Darray_addh(rei->WidgetKillList,ShellW);
  MenuPack_destroy(Field->AltsMenu);
  Field->AltsMenu=rl_MakeAltsMenu(Field);

  MenuPack_attach_to_widget(Field->AltsMenu,Field->AltsMenuAttachW);
  MenuPack_make_menu(Field->AltsMenu);
  Alxt_set_menu_item_with_arg(Field->AltsMenu,Field->FieldType,
			      XtNsetMark,(XtArgVal)TRUE);
  Alxt_set_menu_item_with_arg(Field->AltsMenu,Field->FieldOp,
			      XtNsetMark,(XtArgVal)TRUE);
}


/*-----------------------*/
FieldRet FieldRet_create(name,f)
char *name;
REField f;
{
  FieldRet r;
  r=(FieldRet)Memory_allocate(sizeof(struct FieldRet_str));
  r->name=Memory_allocate(strlen(name)+2);
  strcpy(r->name,name);
  r->Field=f;
  return(r);
}


/*--------------------------------------------------*/
REAssoc rl_REAssoc_create(rei,Type)
reid rei;
AlRAType Type;
{
  REAssoc r;
  r=(REAssoc)Memory_allocate(sizeof(struct REAssoc_str));
  r->rei=rei;
  r->Type=Type;  /* !!! need error checking here */
  r->Menu=rl_REAssoc_MakeMenu(r);
  r->Contents=Darray_create();
  r->ContainerW=NULL;
  r->LabelW=NULL;
  return(r);
}

/*--------------------------------------------------*/
MenuPack rl_REAssoc_MakeMenu(r)
REAssoc r;
{
  MenuPack mp=MenuPack_create(NULL,"Options");
  return(mp);
}

/*--------------------------------------------------*/
REArgument rl_REArgument_create(rei,ArgString,ac)
reid rei;
REAction ac;
char *ArgString;
{
  REArgument r;
  r=(REArgument)Memory_allocate(sizeof(struct REArgument_str));
  if (ArgString!=NULL) {
    r->InitialArgLength=strlen(ArgString);
    r->MaxArgLength=r->InitialArgLength+ARGUMENT_LENGTH;
    r->Arg=strcpy(Memory_allocate(r->MaxArgLength+1),
		  ArgString);
  }
  else {
    r->InitialArgLength=0;
    r->MaxArgLength=r->InitialArgLength+ARGUMENT_LENGTH;
    r->Arg=(char*)Memory_allocate(r->MaxArgLength+1);
    r->Arg[0]='\0';
  }
  r->MenuW=NULL;
  r->ArgW=NULL;
  r->Menu=rl_REAction_MakeMenu(rei,ac,r);
  return(r);
}

/*--------------------------------------------------*/
/* pass in Arguments as NULL to have the action filled with the default */
/* numbver of blank arguments */
/*----------------------------------------*/
REAction rl_REAction_create(rei,VerbName,Arguments)
reid rei;
char *VerbName;
Darray Arguments;
{
  REAction r;
  unsigned i,l;
  char *Argument;
  r=(REAction)Memory_allocate(sizeof(struct REAction_str));
  r->VerbName=strcpy(Memory_allocate(strlen(VerbName)+1),VerbName);
  r->Verb=AlVerbReg_get_obj(VerbName);
  r->Arguments=Darray_create();
  if (Arguments!=NULL) {
    l=Darray_len(Arguments);
    if ((l>AlVerb_max_args(r->Verb)) || (l<AlVerb_min_args(r->Verb)))
      Al_fatal_error1("ruleeditor: too many arguments to the verb %s.",
		      r->VerbName);
    for (i=0;i<l;i++) {
      Argument=Darray_get(Arguments,i);
      Darray_addh(r->Arguments,rl_REArgument_create(rei,Argument,r));
    }
  }
  else {
    l=AlVerb_def_args(r->Verb);
    for (i=0;i<l;i++)
      Darray_addh(r->Arguments,rl_REArgument_create(rei,(char*)NULL,r));
  }

  r->MenuW=NULL; r->VerbW=NULL;
  r->ContainerW=NULL;
  r->Menu=rl_REAction_create_verbs_menu(rei,r);
  return(r);
}

/*--------------------------------------------------*/
MenuPack rl_REAction_create_verbs_menu(rei,r)
reid rei;
REAction r;
{
  MenuPack mp, verbsmp;
  int i,l;
  char *name;
  mp=MenuPack_create(NULL, ACT_OPTIONS);
  verbsmp=MenuPack_create(NULL, ACT_AVAILABLE);
  l=Darray_len(VerbPresOrder_GR);
  for (i=0;i<l;i++) {
    name=Darray_get(VerbPresOrder_GR,i);
    MenuPack_add_option(name,verbsmp,ed_ChangeVerb_CB,
			(char *)RapPack_create3((VOIDP)rei,
						(VOIDP)name,
						(VOIDP)r));
  }
  MenuPack_add_sub_menu(ACT_CHANGE_SMP,mp,verbsmp);
  MenuPack_add_option(ACT_DELETE_STR,mp,ed_Action_delete_CB,
		      (char *)RapPack_create2((VOIDP)rei,
					      (VOIDP)r));
  return(mp); 
}
/*--------------------------------------------------*/
MenuPack rl_REAction_MakeMenu(rei,r,arg)
     reid rei;
     REAction r;
     REArgument arg;
{
  RapPack p;
  MenuPack mp=MenuPack_create(NULL, "Options");

  p=RapPack_create3((VOIDP)rei,
		    (VOIDP)arg,
		    (VOIDP)r);
  MenuPack_add_option(ARGUMENT_ADD_FUNCTION_MENU_NAME,mp,
		      ed_AddArg_CB,(char *)p);
  MenuPack_add_option(ARGUMENT_DEL_FUNCTION_MENU_NAME,mp,
		      ed_DeleteArg_CB,(char *)p);
  return(mp);
}

/*--------------------------------------------------*/
REMember rl_TranslateToRE(rei,RM)
reid rei;
AlRuleMember RM;
{
  REMember ret;
  if (AlRuleMember_get_type(RM)==ALRMT_ASSOC)
    ret=rl_TranslateAssocToRE(rei,RM,NULL);
  else {
     /* if the top member is a fiel, make it an and box */
    REMember rem;
    REAssoc rea;
    rea=rl_REAssoc_create(rei,ALRAT_AND);
    rem=rl_REMember_create(ALRMT_ASSOC,rea,NULL);
    ret=rl_TranslateFieldToRE(rei,RM,rem);
  }
  return(ret);
}

/*--------------------------------------------------*/
REMember rl_TranslateFieldToRE(rei,RM,father)
reid rei;
AlRuleMember RM;
REMember  father;
{
  AlRuleField RF=AlRuleMember_get_field(RM);
  REMember REm;
  REField  REf;
  AlRFType Type;
  char *Key, *Value, *FieldType, *FieldOp;
  AlFieldCore FC;

  Type=AlRuleField_get_type(RF);
  FC=AlRuleField_get_fc(RF);
  Key=AlFieldCore_get_key(FC);
  Value=AlRuleField_get_strvalue(RF);
  FieldOp=AlRuleField_get_op_name(RF);
  FieldType=AlFieldCore_get_field_type_name(FC);
  REf=rl_REField_create(rei,
			Type,Key,Value,FieldType,
			FieldOp,REF_FROM_TEMPLATE);
  REm=rl_REMember_create(ALRMT_FIELD,REf,father);
  assert(REm);
  REf->container=REm;
  return(REm);
}

/*--------------------------------------------------*/
REMember rl_TranslateAssocToRE(rei,RM,father)
reid rei;
AlRuleMember RM;
REMember father;
{
  REAssoc REa;
  REMember REm;
  AlRuleAssoc RA=AlRuleMember_get_assoc(RM);
  AlRuleMember TempRM;
  unsigned i;
  Darray Contents=Darray_create();

  AlRAType Type;
  Type=AlRuleAssoc_get_type(RA);
  REa=rl_REAssoc_create(rei,Type);
  REm=rl_REMember_create(ALRMT_ASSOC,REa,father);
  assert(REm);
  REa->container=REm;
  AlRuleAssoc_get_contents(RA,Contents);
  for (i=0;i<Darray_len(Contents);i++) {
    TempRM=(AlRuleMember)Darray_get(Contents,i);
    if (AlRuleMember_get_type(TempRM)==ALRMT_ASSOC)
      rl_TranslateAssocToRE(rei,TempRM,REm);
    else
      rl_TranslateFieldToRE(rei,TempRM,REm);
  }
  return(REm);
}

/*--------------------------------------------------*/
Darray rl_TranslateActionsToRE(rei,Actions)
reid rei;
Darray Actions;
{
  AlAction action;
  AlVerb Verb;
  char const *VerbName;
  Darray Arguments;
  unsigned i;

  for (i=0;i<Darray_len(Actions);i++) {
    action=(AlAction)Darray_get(Actions,i);
    Verb=AlAction_verb(action);
    VerbName=AlVerbReg_get_name(Verb);
    Arguments=AlAction_args(action);
    Darray_addh(rei->Actions,(VOIDP)rl_REAction_create(rei,
						       (char *)VerbName,
						       Arguments));
  }

  return(rei->Actions);
}

/*--------------------------------------------------*/
Darray rl_TranslateActionsFromRE(rei,REacs)
reid rei;
Darray REacs;
{
  Darray AlActions=Darray_create();
  AlAction Action;
  REAction reaction;
  Darray Arguments;
  REArgument REarg;
  unsigned i, j;
  for (i=0;i<Darray_len(REacs);i++) {
    Arguments=Darray_create();
    reaction=(REAction)Darray_get(REacs,i);
    for (j=0;j<Darray_len(reaction->Arguments);j++)  {
      REarg=(REArgument)Darray_get(reaction->Arguments,j);
      Darray_addh(Arguments,REarg->Arg);
    }
    Action=AlAction_create(reaction->Verb,Arguments);
    Darray_addh(AlActions,Action);
    Darray_destroy(Arguments);
  }
  return(AlActions);
}

/*--------------------------------------------------*/
AlRuleMember rl_TranslateFromRE(rei,rem)
reid rei;
REMember rem;
{
  AlRuleMember ret;
  if (rem->Type==ALRMT_FIELD)
    ret=rl_TranslateFieldFromRE(rei,rem,NULL);
  else if (rem->Type==ALRMT_ASSOC)
    ret=rl_TranslateAssocFromRE(rei,rem,NULL);
  else
    Al_fatal_error("bad REMember type in fiel rl.c : ^^^2\n");

  return(ret);
}

/*--------------------------------------------------*/
AlRuleMember rl_TranslateFieldFromRE(rei,REm,father)
reid rei;
REMember REm;
AlRuleMember father;
{
  REField REf=REm->object.Field;
  AlRuleMember Member;
  unsigned vbl;
  char *vbuff, *obuff;

  vbl=strlen(REf->ValueBuffer);
  vbuff=Memory_allocate(vbl+1);
  obuff=Memory_allocate(vbl+1);
  Alopvalscan(REf->ValueBuffer,obuff,vbuff);
 if ((RapStr_is_empty(obuff)==Bool_TRUE) && 
      (vbuff[0]!='\0')) {
    safe_free(obuff);
    obuff=RapStr_duplicate(REf->FieldOp);
  }
  
  /* this whole interface needs to be changed */
  if (REf->ExistanceOp==Bool_TRUE) {
    Member=AlRuleMember_mcreate_field(ALRFT_MSG,
				      REf->Key,
				      "Any-Case-Text",
				      "",
				      "%contains");
    if (Member==NULL)
      Al_fatal_error("rl_TranslateFieldFromRE: existance operation could \
not be saved. Sorry.");
  }
  else if (((vbuff[0]=='\0') || (RapStr_is_empty(REf->Key))) &&
	   (RapStr_is_empty(obuff)==Bool_TRUE)) {
    Member=AlRuleMember_mcreate_field_no_parse(REf->Type,
					       REf->Key,
					       REf->FieldType,
					       vbuff,
					       obuff);
    if (Member==NULL)
      Al_fatal_error("rl_TranslateFieldFromRE: could not create a field \
member.");
  }
  else {
    if (strcasecmp(obuff,REf->FieldOp)!=0) {  /* user has typed new one in */
      if (rl_Field_op_is_valid(REf->FieldTypeObject,obuff)==Bool_TRUE) {
	Widget SW;
	rl_FieldOp_make_correct_case(REf->FieldTypeObject,obuff);
	                                     /* !!! add code here to change */
					     /* the users text if the op had */
					     /* to be changed. */
	if ((SW=MenuPack_get_widget(REf->AltsMenu,REf->FieldOp))!=NULL)
	  Alxt_SetArg(SW,XtNsetMark,(XtArgVal) FALSE);
	if (REf->FieldOp!=NULL)
	  safe_free(REf->FieldOp);
	REf->FieldOp=strcpy(Memory_allocate(strlen(obuff)+1),obuff);
	/* if these are ==NULL you should add the button to the menu */
	if ((SW=MenuPack_get_widget(REf->AltsMenu,obuff))!=NULL)
	  Alxt_SetArg(SW,XtNsetMark,(XtArgVal) TRUE);
      }
      else {
	char s[300];
	sprintf(s,
		"The field operator %s in the field %s is invalid.\n\
The field will be saved using the %s field operator.",
		obuff, REf->Key,REf->FieldOp);
	repop_Query(REf->ValueW,"Rule Editor",s,"O.K.");
	safe_free(obuff);
	obuff=RapStr_duplicate(REf->defaultFieldOp);
      }
    }
    Member=AlRuleMember_mcreate_field(REf->Type,
				      REf->Key,
				      REf->FieldType,
				      vbuff,
				      obuff);
    if (Member==NULL) { 
      char s[300];
      sprintf(s,
      "The %s field could not be saved because its value is not of type %s.\n\
RUNRULES WILL IGNORE THIS FIELD.",		
	      REf->Key,  REf->FieldType);
      repop_Query(REf->ValueW,"Rule Editor",s,"O.K.");
      Member=AlRuleMember_mcreate_field_no_parse(REf->Type,
						 REf->Key,
						 REf->FieldType,
						 vbuff,
						 obuff);
      if (Member==NULL)
	Al_fatal_error("rl_TranslateFieldFromRE: could not create a field member.");
    }
  }
  safe_free(vbuff);
  safe_free(obuff);
  if (father!=NULL) {
    if (AlRuleMember_get_type(father)!=ALRMT_ASSOC)
      Al_fatal_error("parsong error in TranslateFieldFromRE, file rl.c ^^^3\n");
    AlRuleAssoc_make_member_of(AlRuleMember_get_assoc(father),Member);
  }
  return(Member);
}

/*--------------------------------------------------*/
AlRuleMember rl_TranslateAssocFromRE(rei,REm,father)
reid rei;
REMember REm;
AlRuleMember father;
{
  REAssoc REa=REm->object.Assoc;
  AlRuleMember Member;
  REMember TempREm;
  unsigned i;
  Member=AlRuleMember_mcreate_assoc(REa->Type);
  if (father!=NULL) {
    if (AlRuleMember_get_type(father)!=ALRMT_ASSOC)
      Al_fatal_error("parsong error in TranslateFieldFromRE, file rl.c ^^^4\n");
    AlRuleAssoc_make_member_of(AlRuleMember_get_assoc(father),Member);
  }    
  
  for (i=0;i<Darray_len(REa->Contents);i++) {
    TempREm=(REMember)Darray_get(REa->Contents,i);
    if (TempREm->Type==ALRMT_FIELD)
      rl_TranslateFieldFromRE(rei,TempREm,Member);
    else if (REm->Type==ALRMT_ASSOC)
      rl_TranslateAssocFromRE(rei,TempREm,Member);
    else
      Al_fatal_error("bad REMember type in fiel rl.c : ^^^5\n");
  }
  return(Member);

}

/*--------------------------------------------------*/
Bool rl_Field_op_is_valid(FT,op)
AlFieldType FT;
char* op;
{
  Darray FieldOps=Darray_create();
  unsigned i,l;
  AlFieldType_get_field_op_list(FT,FieldOps);
  l=Darray_len(FieldOps);
  for (i=0;i<l;i++) 
    if (strcasecmp((char*)Darray_get(FieldOps,i),op)==0)
      return(Bool_TRUE);
  return(Bool_FALSE);
}

/*--------------------------------------------------*/
REField rl_REField_duplicate(rei,REf)
reid rei;
REField REf;
{
  REField f;
  f=rl_REField_create(rei,
		      REf->Type,
		      REf->Key,
		      REf->Value,
		      REf->FieldType,
		      REf->FieldOp,
		      REf->FromWhere);
  return(f);
}

/*--------------------------------------------------*/
void rl_RegSelectFC_CB(w,FR,cadda)
Widget w;
FieldRet FR;
caddr_t cadda;
{
  ArgPack AP;
  Widget SW;
  AlRFType ft;
  char *name;
  XtTextBlock MyTextBlock; 

  ft=(AlRFType)Biregistry_get(NameToFC_GR,FR->name);

  name=Biregistry_rev_get(NameToFC_GR,(VOIDP)FR->Field->Type);
  SW=MenuPack_get_widget(FR->Field->FTMenu,name);
  if (SW!=NULL) {
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsetMark, (XtArgVal) FALSE);
    XtSetValues(SW,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNsetMark, (XtArgVal) TRUE);
  XtSetValues(w,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  if (FR->Field->IsState==Bool_TRUE) {
    MyTextBlock.firstPos=0;
    MyTextBlock.length=0;
    MyTextBlock.ptr="";
    XtTextReplace(FR->Field->KeyW,
		  0,
		  strlen(FR->Field->Key),
		  &MyTextBlock,
		  FALSE);


    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsensitive, (XtArgVal) TRUE);
    ArgPack_add_arg(AP,XtNtextOptions, (XtArgVal) resizeHeight | 
		    editable );
    XtSetValues(FR->Field->KeyW,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }

  FR->Field->Type=ft;
  FR->Field->IsState=Bool_FALSE;
  rl_MenuSensitiveAll(FR->Field->AltsMenu,FieldTypeNames_GR);
  AlUI_DetachCursor(FR->Field->KeyW);
  AlUI_AttachCursor(FR->Field->KeyW,RE_EDIT_CURSOR);
}

/*--------------------------------------------------*/
void rl_StateSelectFC_CB(w,FR,cadda)
Widget w;
FieldRet FR;
caddr_t cadda;
{
  ArgPack AP;
  Widget SW;
  XtTextBlock MyTextBlock;  
  AlRFType ft;
  char *name;
  reid rei=FR->Field->rei;
  ft=(AlRFType)Biregistry_get(NameToFC_GR,FR->name);

  name=Biregistry_rev_get(NameToFC_GR,(VOIDP)FR->Field->Type);
  SW=MenuPack_get_widget(FR->Field->FTMenu,name);
  if (SW!=NULL) {
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsetMark, (XtArgVal) FALSE);
    XtSetValues(SW,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }

  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNsetMark, (XtArgVal) TRUE);
  XtSetValues(w,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  FR->Field->Type=ft;
  FR->Field->IsState=Bool_TRUE;

  MyTextBlock.firstPos=0;
  MyTextBlock.length=strlen(FR->name);
  MyTextBlock.ptr=(char *)FR->name;
  XtTextReplace(FR->Field->KeyW,
		0,
		strlen(FR->Field->Key),
		&MyTextBlock,
		FALSE);

  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNsensitive, (XtArgVal) FALSE);
  ArgPack_add_arg(AP,XtNtextOptions, (XtArgVal) resizeHeight );
  XtSetValues(FR->Field->KeyW,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  /*
   * change the Field Types Menu
   */
  {
    char *s1,*s2, *string;
    AlFieldType FT;
    Darray Ops=Darray_create();
    unsigned i, l;

    /* find the right field type for this msg state */
    s2=NULL;
    l=Darray_len(StateFTs_GR);
    for (i=0;i<l;i++) {
      s1=Darray_get(StateFTs_GR,i);
      if (strcmp(s1,FR->name)==0)
	s2=Darray_get(StateFC_def_FTs_GR,i);
    }
    /* set up the Field to reflect the changes */
    if (s2!=NULL) {
      safe_free(FR->Field->FieldType);
      FR->Field->FieldType=strcpy(Memory_allocate(strlen(s2)+1),s2);
      FT=AlFTreg_string_to_obj(s2);
      FR->Field->FieldTypeObject=FT;
      if ((AlFieldType_get_field_op_list(FT,Ops))==Bool_FALSE)
	Al_fatal_error("couldn;t get default field operator\n");
      string=Darray_get(Ops,(unsigned)0);
      FR->Field->FieldOp=strcpy(Memory_allocate(strlen(string)+1),string);
      
      /* redo the alts menu. This code is taken from the rl_selectFT_CB() */
      /* function and should probably be consolidated into one function. */
      {
	Widget ShellW, SW;
	ArgPack AP;
	REField Field=FR->Field;

	ShellW=MenuPack_get_top_level_shellW(Field->AltsMenu);
	XtUnmanageChild(ShellW);
	Darray_addh(rei->WidgetKillList,ShellW);
	MenuPack_destroy(Field->AltsMenu);
	Field->AltsMenu=rl_MakeAltsMenu(Field);

	MenuPack_attach_to_widget(Field->AltsMenu,Field->AltsMenuAttachW);
	MenuPack_make_menu(Field->AltsMenu);

	/* mark the field type in the menu */
	SW=MenuPack_get_widget(Field->AltsMenu,Field->FieldType);
	if (SW!=NULL)  {
	  AP=ArgPack_create();
	  ArgPack_add_arg(AP,XtNsetMark,(XtArgVal) TRUE);
	  XtSetValues(SW,ArgPack_the_args(AP),ArgPack_num_args(AP));
	  ArgPack_delete(AP);
	}
	else
	  printf("warning: couldn't find field type %s\n",Field->FieldType);

	/* mark the field operator in the menu */
	SW=MenuPack_get_widget(Field->AltsMenu,Field->FieldOp);
	if (SW!=NULL)  {
	  AP=ArgPack_create();
	  ArgPack_add_arg(AP,XtNsetMark,(XtArgVal) TRUE);
	  XtSetValues(SW,ArgPack_the_args(AP),ArgPack_num_args(AP));
	  ArgPack_delete(AP);
	}
	else
	  printf("ruleeditor: state_selectFC: warning: couldn't find field operator %s\n",Field->FieldOp);

	/* update the value to reflect the new field operator */
	rl_RedoValueString(Field,Field->FieldOp);
      }
      
      /* make the field type selection menu insenstitive. */
      rl_MenuInsensitiveAll(FR->Field->AltsMenu,FieldTypeNames_GR);
      AlUI_AttachCursor(FR->Field->KeyW,RE_GLOBAL_CURSOR);
    }
  }
}


/*--------------------------------------------------*/
void rl_MenuSensitiveOnly(mp,Names,name)
     /* This function should be rewritten so that it does not need to 
      * input the list f options in the menu.  This will involve extending
      * the menupack object with a MenuPack_get_all_options() function.
      */
MenuPack mp; 
Darray Names;
char *name;
{
  int k,l1;
  Widget w1,w2;
  char  *b1;
  ArgPack AP;

  l1=Darray_len(Names);
  w1=MenuPack_get_widget(mp,name);
  if (w1==NULL) {
    Al_warning1("rl_MenuSelectOnly:Field Type name %s not found\n",name);
    Al_warning( "                 :operation not completed");
    return;
  }
  for (k=0;k<l1;k++) {
    b1=Darray_get(Names,k);
    w2=MenuPack_get_widget(mp,b1);
    if (w2==NULL) {
      Al_warning1("rl_MenuSelectOnly:Field Type name %s not found\n",name);
      Al_warning( "                 :operation not completed");
      return;
    }
    if (w2!=w1) {
      AP=ArgPack_create();
      ArgPack_add_arg(AP,XtNsensitive, (XtArgVal) FALSE );
      XtSetValues(w2, ArgPack_the_args(AP), ArgPack_num_args(AP));
      ArgPack_delete(AP);
    }
  }
}

/*--------------------------------------------------*/
void rl_MenuSensitiveAll(mp,Names)
MenuPack mp;
Darray Names;
{
  int i,l;
  Widget w1;
  char *s1;
  ArgPack AP;
  l=Darray_len(Names);
  for (i=0;i<l;i++) {
    s1=Darray_get(Names,i);
    w1=MenuPack_get_widget(mp,s1);
    if (w1==NULL) {
      Al_warning1("rl_MenuSensitiveAll:Field Type name %s not found\n",s1);
      Al_warning( "                   :operation not completed");
      return;
    }
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsensitive, (XtArgVal) TRUE );
    XtSetValues(w1, ArgPack_the_args(AP), ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
}

/*--------------------------------------------------*/
void rl_MenuInsensitiveAll(mp,Names)
MenuPack mp;
Darray Names;
{
  int i,l;
  Widget w1;
  char *s1;
  ArgPack AP;
  l=Darray_len(Names);
  for (i=0;i<l;i++) {
    s1=Darray_get(Names,i);
    w1=MenuPack_get_widget(mp,s1);
    if (w1==NULL) {
      Al_warning1("rl_MenuInsensitiveAll:Field Type name %s not found\n",s1);
      Al_warning( "                   :operation not completed");
      return;
    }
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNsensitive, (XtArgVal) FALSE );
    XtSetValues(w1, ArgPack_the_args(AP), ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
}

/*--------------------------------------------------*/
Bool rl_IsState(ft)
AlRFType ft;
{
  char *name;
  unsigned i,l;
  l=Darray_len(StateFTs_GR);
  for (i=0;i<l;i++) {
    name=Darray_get(StateFTs_GR,i);
    if (ft==(AlRFType)Biregistry_get(NameToFC_GR,(VOIDP)name))
      return(Bool_TRUE);
  }
  return(Bool_FALSE);
}

/*======================================================================*/
/*     The Darray functions                                             */
/*======================================================================*/

/*--------------------------------------------------*/
Darray rl_Darray_remove_ptr(d,p)
Darray d;
VOIDP p;
{
  int i,l,source,dest;
  l=Darray_len(d);
  for (i=0;i<l;i++) 
    if ((VOIDP)Darray_get(d,i)==p) break;
  if (i==l)
    return(d);
  for (dest=i,source=i+1;source<l;dest++,source++)
    Darray_set(d,dest,Darray_get(d,source));
  Darray_remh(d);
  return(d);
}

/*--------------------------------------------------*/
Darray rl_Darray_insert(d,p,index)
Darray d;
VOIDP p;
int index;
{
  int i,l,source,dest;
  l=Darray_len(d);
  assert(index<l);
  if (index+1==l || l==0) {
    Darray_addh(d,p);
    return(d);
  }
  else {
    Darray_addh(d,Darray_get(d,l-1));
    for (dest=l-1,source=l-2;
	 source>=index && source>=0;
	 source--, dest--) 
      Darray_set(d,dest,Darray_get(d,source));
    Darray_set(d,index,p);
    return(d);
  }
}



/*======================================================================*/

/*--------------------------------------------------*/
NORET rl_Existance_CB(w,cadda,caddb)
Widget w;
caddr_t cadda, caddb;
{
  REField REf;
  XtTextBlock MyTextBlock;  
  unsigned l;
  RE_debug("existance_cb\n");

  REf=(REField)cadda;
  if (REf->ExistanceOp==Bool_TRUE) return;


  Alxt_set_menu_item_with_arg(REf->AltsMenu,REf->FieldType,
			      XtNsetMark,(XtArgVal)FALSE);
  Alxt_set_menu_item_with_arg(REf->AltsMenu,EXIST_OP_NAME,
			      XtNsetMark,(XtArgVal)TRUE);
  
  Alxt_set_menu_item_with_arg(REf->AltsMenu,AVAILABLE_OPS,
			      XtNsensitive,(XtArgVal)FALSE);
  if (REf->FieldType!=NULL)
    safe_free(REf->FieldType); 
  REf->FieldType=RapStr_duplicate(EXIST_OP_NAME);
  l=strlen(EXIST_OP_INDICATOR);
  MyTextBlock.firstPos=0;
  MyTextBlock.length=l;
  MyTextBlock.ptr=(char *)RapStr_duplicate(EXIST_OP_INDICATOR);
  XtTextReplace(REf->ValueW,
		0,
		strlen(REf->ValueBuffer),
		&MyTextBlock,
		FALSE);

  Alxt_SetArg(REf->ValueW,XtNborderWidth,(XtArgVal) 0);
  Alxt_SetArg(REf->ValueW,XtNeditType,(XtArgVal) XttextRead);
  Alxt_SetArg(REf->ValueW,XtNtextOptions,
	      (XtArgVal) resizeHeight | resizeWidth);
  Alxt_SetArg(REf->ValueW,XtNsensitive,(XtArgVal) FALSE);
  Alxt_SetArg(REf->ValueW,XtNinsertPosition,(XtArgVal)999);

  Alxt_set_menu_item_with_arg(REf->FTMenu,FIELD_CLASS_CASCADER_STR,
			      XtNsensitive, (XtArgVal) FALSE);

  REf->ExistanceOp=Bool_TRUE;
}
/*--------------------------------------------------*/
NORET rl_Existance_reset_from(REf)
     REField REf;
{
  XtTextBlock MyTextBlock;  
  unsigned l;
  
  if (REf->ExistanceOp==Bool_FALSE) return;
  l=0;
  MyTextBlock.firstPos=0;
  MyTextBlock.length=l;
  MyTextBlock.ptr="";
  XtTextReplace(REf->ValueW,
		0,
		strlen(REf->ValueBuffer),
		&MyTextBlock,
		FALSE);

  Alxt_set_menu_item_with_arg(REf->AltsMenu,AVAILABLE_OPS,
			      XtNsensitive,(XtArgVal)TRUE);
  Alxt_SetArg(REf->ValueW,XtNeditType,(XtArgVal) XttextEdit);
  Alxt_SetArg(REf->ValueW,XtNtextOptions,
	      (XtArgVal) resizeHeight | resizeWidth | editable);
  Alxt_SetArg(REf->ValueW,XtNsensitive,(XtArgVal) TRUE);
  Alxt_SetArg(REf->ValueW,XtNinsertPosition,(XtArgVal)1);
  Alxt_SetArg(REf->ValueW,XtNborderWidth,(XtArgVal) 1);

  Alxt_set_menu_item_with_arg(REf->FTMenu,FIELD_CLASS_CASCADER_STR,
			      XtNsensitive, (XtArgVal) TRUE);

  REf->ExistanceOp=Bool_FALSE;
}

/*--------------------------------------------------*/
char* rl_REField_make_translation(event,function,args)
char *event,*function,*args;
{
  RMFBuffer Buff;
  char *ret;
  Buff=RMFBuffer_create(event,20);
  RMFBuffer_append(Buff,":");
  RMFBuffer_append(Buff,function);
  RMFBuffer_append(Buff,"(");
  RMFBuffer_append(Buff,args);
  RMFBuffer_append(Buff,")");
  ret=RMFBuffer_copy_of_buff(Buff);
  RMFBuffer_destroy(Buff);
  return(ret);
}

/*--------------------------------------------------*/
char* rl_REField_augment_translations(t,event,function,args)
char *t,*event,*function,*args;
{
  RMFBuffer Buff;
  char *ret;
  Buff=RMFBuffer_create(t,20);
  RMFBuffer_append_char(Buff,'\n');
  RMFBuffer_append(Buff,event);
  RMFBuffer_append(Buff,":");
  RMFBuffer_append(Buff,function);
  RMFBuffer_append(Buff,"(");
  RMFBuffer_append(Buff,args);
  RMFBuffer_append(Buff,")");
  ret=RMFBuffer_copy_of_buff(Buff);
  RMFBuffer_destroy(Buff);
  return(ret);
}


static Biregistry REFieldAddresses;
/*--------------------------------------------------*/
NORET rl_REField_register_address(f)
REField f;
{
  static Bool Inited=Bool_FALSE;
  if (Inited==Bool_FALSE) {
    REFieldAddresses=Biregistry_create(Registry_ptrcmp,
				       Registry_ptrhash,
				       Registry_strcmp,
				       Registry_strhash);
    Inited=Bool_TRUE;
  }
  if (Biregistry_add(REFieldAddresses,(VOIDP)f,
		     (VOIDP)f->MyAddress)==Bool_FALSE)
    Al_fatal_error1("REField_register_address: could not register %s.",
		    f->MyAddress);
}

/*--------------------------------------------------*/
REField rl_REField_get_field_from_address(ad)
char* ad;
{
  REField ret;
  if ((ret=(REField)Biregistry_rev_get(REFieldAddresses,(CONSTVOIDP)ad))==NULL)
    Al_fatal_error1("REField_get_field_from_address: could not get %s.",
		    ad);
  return(ret);
}

/*--------------------------------------------------*/
NORET rl_REField_remove_address(REf)
REField REf;
{
  if (Biregistry_rev_remove(REFieldAddresses,
			 (CONSTVOIDP)REf->MyAddress)==Bool_FALSE)
    Al_fatal_error1("REField_remove_address: could not remove %s.",
		    REf->MyAddress);
}
    
/*--------------------------------------------------*/
void rl_Modified_rule(w,Xe,parms,NParms)
Widget w;
XEvent* Xe;
String* parms;
Cardinal* NParms;
{
  reid rei;
  int a=atoi(parms[0]);
  rei=(reid)a;
  rei->Modified=Bool_TRUE;
}

/*--------------------------------------------------*/
void rl_Monitor_field_value(w,Xe,parms,NParms)
Widget w;
XEvent* Xe;
String* parms;
Cardinal* NParms;
{
  REField REf;

  REf=rl_REField_get_field_from_address(parms[0]);

  rl_Parse_field_and_update(REf);
}

/*--------------------------------------------------*/
void rl_Monitor_field_key(w,Xe,parms,NParms)
Widget w;
XEvent* Xe;
String* parms;
Cardinal* NParms;
{
  REField REf;
  char *k;
  int mod;

  REf=rl_REField_get_field_from_address(parms[0]);

  if (REf->Type==ALRFT_MSG) {
    mod=0;
    k=rl_Key_rj_and_add_colon(REf->Key,KEY_LENGTH,&mod);
    RE_debug1("k=%s\n",k);
    if (mod==1) {
      XtTextBlock MyTextBlock;  
      unsigned l,j;
      l=strlen(k);
      j=strlen(REf->Key);
      MyTextBlock.firstPos=0;
      MyTextBlock.length=l;
      MyTextBlock.ptr=k;
      Alxt_SetArg(REf->KeyW,XtNinsertPosition,(XtArgVal)l);
      XtTextReplace(REf->KeyW,
		    0,
		    j,
		    &MyTextBlock,
		    TRUE);
      Memory_free(k);
    }
  }
}

/*--------------------------------------------------*/
void rl_Parse_field_and_update(REf)
REField REf;
{
  unsigned vbl;
  AlFieldCore FC;
  char *vbuff, *obuff;
  static Registry FieldCores;
  static Bool Inited=Bool_FALSE;
  reid rei;
  
  rei=REf->rei;
  
  if (Inited==Bool_FALSE) {
    FieldCores=Registry_create(Registry_ptrcmp,
			       Registry_ptrhash);
    Inited=Bool_TRUE;
  }

  vbl=strlen(REf->ValueBuffer);
  vbuff=Memory_allocate(vbl+1);
  obuff=Memory_allocate(vbl+1);
  Alopvalscan(REf->ValueBuffer,obuff,vbuff);
  if (obuff[0]!='\0' && 
      strcasecmp(obuff,REf->FieldOp)!=0) {  /* user has typed new one in */
    if (rl_Field_op_is_valid(REf->FieldTypeObject,obuff)==Bool_TRUE) {
      Widget SW;
      rl_FieldOp_make_correct_case(REf->FieldTypeObject,obuff);
                                            /* !!! add code here to change */
					    /* the users field op if case */
					    /* had to be changed. */
      if ((SW=MenuPack_get_widget(REf->AltsMenu,REf->FieldOp))!=NULL)
	Alxt_SetArg(SW,XtNsetMark,(XtArgVal) FALSE);
      if (REf->FieldOp!=NULL)
	safe_free(REf->FieldOp);
      REf->FieldOp=strcpy(Memory_allocate(strlen(obuff)+1),obuff);
      /* if these are ==NULL you should add the button to the menu */
      if ((SW=MenuPack_get_widget(REf->AltsMenu,obuff))!=NULL)
	Alxt_SetArg(SW,XtNsetMark,(XtArgVal) TRUE);
    }
    else {
      char s[300];
      sprintf(s,
"The field operator %s specified in the field %s is invalid.\n\
The field will be saved using the default field operator %s.",
	      obuff, REf->Key,REf->FieldOp);
      repop_Query(REf->ValueW,"Rule Editor",s,"O.K.");
    }
  }
  
  if ((FC=(AlFieldCore)Registry_get(FieldCores,REf->FieldTypeObject))==NULL) {
    FC=AlFieldCore_create_with_obj(REf->FieldTypeObject);
    Registry_add(FieldCores,(VOIDP)REf->FieldTypeObject,(VOIDP)FC);
  }
  if (AlFieldCore_parse(FC,(const char*)vbuff)==Bool_FALSE) {
    if (REf->ValueIsParsable==Bool_TRUE) {
      Alxt_SetArg(REf->ValueW,XtNborderPixmap,(XtArgVal) 
		  rl_get_pixmap(rei,DASHED_LINE));
      RE_debug1("field does not parse: %s.\n",REf->Key);
      REf->ValueIsParsable=Bool_FALSE;
    }
  }
  else if (REf->ValueIsParsable==Bool_FALSE) {
    Alxt_SetArg(REf->ValueW,XtNborderPixmap,(XtArgVal) 
		rl_get_pixmap(rei,SOLID_LINE));
    REf->ValueIsParsable=Bool_TRUE;
  }
  safe_free(obuff);
  safe_free(vbuff);
}

/*--------------------------------------------------*/
/* look into weather it is possible to reuse these pixmaps */
/*----------------------------------------*/
Pixmap rl_get_pixmap(rei,which)
reid rei;
unsigned which;
{
  static Pixmap MenuPM=NULL;
  Screen *screen;
  Display *display;
  int ScreenNumber;
  char *bits;
  unsigned width, height;

  switch (which) { 
  case SOLID_LINE:
    bits=solidline_bits;
    width=solidline_width;
    height=solidline_height;
    break;
  case DASHED_LINE:
    bits=dashedline_bits;
    width=dashedline_width;
    height=dashedline_height;
    break;  
  }
  display=XtDisplay(rei->ShellW);
  screen=XtScreen(rei->ShellW);
  ScreenNumber=XDefaultScreen(display);
  MenuPM=XCreatePixmapFromBitmapData(display,
				     RootWindowOfScreen(screen),
				     bits,
				     width,
				     height,
				     XBlackPixel(display,ScreenNumber),
				     XWhitePixel(display,ScreenNumber),
				     DefaultDepthOfScreen(screen));
  return(MenuPM);
}

/*--------------------------------------------------*/
/* signals a bool_TRUE when we have to correct a case error */
/*----------------------------------------*/
Bool rl_FieldOp_make_correct_case(ft,fo)
AlFieldType ft;
char *fo;
{
  Darray oplist=Darray_create();
  unsigned i,l;
  char *op;

  AlFieldType_get_field_op_list(ft,oplist);
  l=Darray_len(oplist);
  for (i=0;i<l;i++) {
    op=Darray_get(oplist,i);
    if (strcasecmp(op,fo)==0) {
      if (strcmp(op,fo)!=0) {
	strcpy(fo,op);
	return(Bool_TRUE);
      }
      return(Bool_FALSE);
    }
  }
}

/*--------------------------------------------------*/
/*----------------------------------------*/
char *rl_Key_rj_and_add_colon(Key,SIZE,mod)
char *Key;
int SIZE;
int *mod;
{
  int l;
  char *r;
  Bool Alt;
  l=strlen(Key)-1;
  if (l==(-1))
    return(Key);
  Alt=Bool_FALSE;
  while (Key[l]==' ' && l>0 ) { Alt=Bool_TRUE; l--; }
  if (Alt==Bool_FALSE) {
    if (Key[l]==':')  
      return(Key);
    else {
      *mod=1;
      if (l+3>SIZE)  /* loose memory allocated by parser for Key field */
	r=Memory_allocate(l+4);
      else
	r=Memory_allocate(SIZE+1);
      strcpy(r,Key);
      r[l+1]=':';
      r[l+2]='\0';
      r[l+3]='\0';
    }
    return(r);
  }
  else {
    *mod=1;
    if (l+3>SIZE)  /* loose memory allocated by parser for Key field */
      r=Memory_allocate(l+4);
    else
      r=Memory_allocate(SIZE+1);
    if (l<0)
      r[0]='\0';
    else  {
      strcpy(r,Key);
      r[l+1]='\0';
      if (r[l]!=':') {
	r[l+1]=':';
	r[l+2]='\0';
	r[l+3]='\0';
      } 
    }
    return(r);
  }
}

/*--------------------------------------------------*/
NORET rl_REMember_destroy(rem)
REMember rem;
{
  RE_debug1("rl: destroying a %s\n", (char*)((rem->Type==ALRMT_ASSOC) ?
					     "ASSOC" :
					     "FIELD"));
}

/*--------------------------------------------------*/
Widget rl_Get_widget_from_member(rem)
REMember rem;
{
  if (rem==NULL) 
    return(NULL);
  else if (rem->Type==ALRMT_ASSOC)
    return(rem->object.Assoc->ContainerW);
  else
    return(rem->object.Field->ContainerW);
}


/*--------------------------------------------------*/
NORET  rl_Get_surrounding_widgets(rei,rem,
				  PrevW,NextW,ParentW)
reid rei;
REMember rem;
Widget *PrevW, *NextW, *ParentW;
{
  REMember Prev, Next, Parent;

  rl_Get_surrounding_members(rei,rem,&Prev,&Next,&Parent);
  if (Prev==NULL) {
    if (Parent!=NULL)
      *PrevW=Parent->object.Assoc->LabelW;
    else
      *PrevW=NULL;
  }
  else
    *PrevW=rl_Get_widget_from_member(Prev);
  *NextW=rl_Get_widget_from_member(Next);
  *ParentW=rl_Get_widget_from_member(Parent);
  if (*ParentW==NULL) *ParentW=rei->IfW;
}

/*--------------------------------------------------*/
NORET rl_Get_surrounding_members(rei,rem,Prev,Next,Parent)
reid rei;
REMember rem, *Prev, *Next, *Parent;
{
  REMember Prem=rem->father;
  REField Cref;

  if (Prem==NULL) {
    *Prev=NULL;
    *Next=NULL;
    *Parent=NULL;
    return;
  }
  else if (Prem->Type!=ALRMT_ASSOC) 
    Al_fatal_error("rl_Get_surrounding_members: bad rule language.\n");
  else {
    int i,l;
    REAssoc Prea=Prem->object.Assoc;
    REMember Crem;
    l=Darray_len(Prea->Contents);
    for (i=0;i<l;i++) {
      Crem=(REMember)Darray_get(Prea->Contents,i);
      if (Crem==rem) {
	if (i==0)
	  *Prev=NULL;
	else
	  *Prev=(REMember)Darray_get(Prea->Contents,i-1);

	if ((i+1)>=l)
	  *Next=NULL;
	else 
	  *Next=(REMember)Darray_get(Prea->Contents,i+1);

	*Parent=Prem;
	break;
      }
    }
  }
}

/*--------------------------------------------------*/
int rl_REMember_get_index(rem)
REMember rem;
{
  REMember Prem=rem->father;
  REAssoc rea;
  int i,j;

  if (Prem==NULL)
    return(-1);
  else {
    assert(Prem->Type==ALRMT_ASSOC);
    rea=Prem->object.Assoc;
    i=0;
    while ((REMember)Darray_get(rea->Contents,i)!=rem) i++;
    if (i==Darray_len(rea->Contents)) 
      Al_fatal_error("rl_REMember_get_index: parent not owner of member!!\n");
    return(i);
  }
}
