#include "ed.h"
#include "d1.h"
#include "rl.h"
#include "ru.h"
#include "assert.h"
#include "ruleset.h"
#include "RSreg.h"
#include "al.h"
#include "rs.h"
#include "verbrgy.h"
#include "MsgType.h"
#include "MTreg.h"
#include "FieldCore.h"
#include "FieldType.h"
#include "useful.h"
#include "ArgPack.h"
#include "bool.h"
#include "rem.h"
#include "global.h"
#include "callback.h"
#include "ut.h"
/*--------------------------------------------------*/
void ed_Init(GR)
reid GR;
{
  GR->WidgetKillList_GR=Darray_create();
}

/*--------------------------------------------------*/
void ed_Done_CB(w,GR,caddb)
Widget w;
reid GR;
caddr_t caddb;
{
  Darray       AlActions;
  AlRuleMember AlMember;
  AlRule       Rule;

  AlActions=rl_TranslateActionsFromRE(GR->Actions_GR);
  AlMember=rl_TranslateFromRE(GR->TopLevelMember_GR);
  GR->Rule_GR=AlRule_create(AlMember,AlActions,0,0,(char*)NULL);
  assert(GR->Rule_GR);
  (GR->SaveFunction)(GR,GR->ClientData);
}

/*--------------------------------------------------*/
void ed_Abort_CB(w,GR,caddb)
Widget w;
reid GR;
caddr_t  caddb;
{
  printf("Rule Editor:modifications not saved\n");
/*  CB2_destroy_all(); */
  XtDestroyWidget(GR->ShellW_GR);
  (GR->ExitFunction)(GR,GR->ClientData);  
}  

/*--------------------------------------------------*/
void ed_AddVerb_CB(w,Obj2,cadda)
Widget w;
CBObj2 Obj2;
caddr_t cadda;
{
  reid GR=Obj2->one;
  char *VerbName=Obj2->two;
  unsigned i,nargs;
  REAction REac;
  Darray Args=Darray_create();
  AlVerb Verb;
  char *buff;

  ed_ClearWidgetKillList(GR);
  Verb=AlVerbReg_get_obj(VerbName);
  nargs=AlVerb_def_args(Verb);
  for (i=0;i<nargs;i++) {
    buff=safe_malloc(VALUE_LENGTH+1);
    buff[0]='\0';
    Darray_addh(Args,buff);
  }
  REac=rl_REAction_create(GR,VerbName,Args);
  assert(REac);
  Darray_addh(GR->Actions_GR,REac);
  d1_AddAction(GR,REac);
}

/*--------------------------------------------------*/
void ed_AddField_CB(w,GR,caddb)
Widget w;
reid   GR;
caddr_t  caddb;
{
  REMember REm;
  REField  REf;
  REMember TopMember, NewTopMember;
  unsigned i, l1;

  ed_ClearWidgetKillList(GR);
  /*
   * !!! This code should be replaces by a flagging this field as not being
   *  formally added to the rule because its not in a box.  For now though
   * we put it in a box on top, if none exists we create one.
   */
  if (GR->TopLevelMember_GR!=NULL) {
    if (GR->TopLevelMember_GR->Type!=ALRMT_ASSOC)  {
      NewTopMember=rl_REMember_create(ALRMT_ASSOC,
				      rl_REAssoc_create(ALRAT_AND),
				      NULL);
      GR->TopLevelMember_GR->father=NewTopMember;
      Darray_addh(NewTopMember->object.Assoc->Contents,GR->TopLevelMember_GR);
      GR->TopLevelMember_GR=NewTopMember;
    }
  }
  REf=rl_REField_create(GR,ALRFT_MSG,"","",NULL,NULL,REF_FROM_USER);
  REm=rl_REMember_create(ALRMT_FIELD,REf,GR->TopLevelMember_GR);
  if (GR->TopLevelMember_GR==NULL)
    GR->TopLevelMember_GR=REm;
  d1_If_AddField(GR,REm,REFT_NEW);
}
/*--------------------------------------------------*/
void ed_ClearWidgetKillList(GR)
reid GR;
{
  unsigned l1, i;
  /*
   *  destroy all widgets in kilkl list
   */
  l1=Darray_len(GR->WidgetKillList_GR);
  if (l1!=0)  {
    for (i=0;i<l1;i++)
      XtDestroyWidget(Darray_remh(GR->WidgetKillList_GR));
  }
}

/*--------------------------------------------------*/
void ed_AddMT_CB(w,Obj2,cadda)
Widget w;
CBObj2 Obj2;
caddr_t cadda;
{
  reid GR=Obj2->one;
  char *MTN=Obj2->two;
  AlMsgType MT;
  Darray Keys=Darray_create();
  AlFieldCore FC;
  AlFieldType FT;
  unsigned i,l;
  REMember REm;
  REField  REf;
  REMember TopMember, NewTopMember; 
  char *FTN, *Key;

  MT=AlMTreg_get_obj_with_name(MTN);
  if (MT==NULL) {
    Al_warning1("Trying to add Message Type: %s which doesn't exist\n",MTN);
    Al_warning("  Probably because of nonexistant message type directory");
    Al_warning("  or bad path name in lens profile");
  }
  else {
    AlMsgType_all_fields(MT,Keys);
    l=Darray_len(Keys);
    for (i=0;i<l;i++) {
      FC=Darray_get(Keys,i);
      assert(FC);
      Key=AlFieldCore_get_key(FC);
      if (ed_FieldExists(GR,Key)==Bool_FALSE) {
	FTN=AlFieldCore_get_field_type_name(FC);
	if (GR->TopLevelMember_GR!=NULL) {
	  if (GR->TopLevelMember_GR->Type!=ALRMT_ASSOC)  {
	    NewTopMember=rl_REMember_create(ALRMT_ASSOC,
					    rl_REAssoc_create(ALRAT_AND),
					    NULL);
	    GR->TopLevelMember_GR->father=NewTopMember;
	    Darray_addh(NewTopMember->object.Assoc->Contents,
			GR->TopLevelMember_GR);
	    GR->TopLevelMember_GR=NewTopMember;
	  }
	}
	REf=rl_REField_create(GR,
			      ALRFT_MSG,
			      AlFieldCore_get_key(FC),
			      "",
			      FTN,
			      NULL,
			      REF_FROM_TEMPLATE);
	REm=rl_REMember_create(ALRMT_FIELD,REf,GR->TopLevelMember_GR);
	if (GR->TopLevelMember_GR==NULL)
	  GR->TopLevelMember_GR=REm;
	d1_If_AddField(GR,REm,REFT_TEMPLATE);
      }
    }
  }
} 

/*--------------------------------------------------*/
Bool ed_FieldExists(GR,Key)
reid GR;
char *Key;
{
  unsigned i, l1;
  REField f;
  l1=Darray_len(GR->If_Contents_GR);
  for (i=0;i<l1;i++)  {
    f=Darray_get(GR->If_Contents_GR,i);
    if (strcmp(Key,f->Key)==0)
      return(Bool_TRUE);
  }
  return(Bool_FALSE);
}

/*--------------------------------------------------*/
void ed_Field_delete_CB(w,Obj2,cadda)
Widget w;
CBObj2 Obj2;
caddr_t cadda;
{
  reid GR=Obj2->one;
  REField f=Obj2->two;
  REField Current, Previous, Next;
  Widget PrevW, NextW, CurrW;
  unsigned i, l1, l2;
  Bool Found=Bool_FALSE;
  ArgPack AP;
  REField tf;
  Darray D=Darray_create();

  assert(f);
  l1=Darray_len(GR->If_Contents_GR);
  for (i=0;i<l1;i++) {
    if ((Current=Darray_get(GR->If_Contents_GR,i))==f) {
      if (i==0)
	PrevW=NULL;
      else {
	Previous=Darray_get(GR->If_Contents_GR,i-1);
	PrevW=Previous->ContainerW;
      }
      if ((i+1)>=l1)
	NextW=NULL;
      else {
	Next=Darray_get(GR->If_Contents_GR,i+1);
	NextW=Next->ContainerW;
      }
      Found=Bool_TRUE;
      break;
    }
  }
  if (Found==Bool_FALSE)
    Al_fatal_error((const char *)"ed_Field_delete_CB:couldn't find field");
  if (NextW!=NULL) {
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)PrevW);
    XtSetValues(NextW,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)NULL);
  XtSetValues(f->ContainerW,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);
  XtUnmanageChild(f->ContainerW);
  Darray_addh(GR->WidgetKillList_GR,f->ContainerW);
  ed_Field_remove(GR,f);
}

/*--------------------------------------------------*/
void ed_Field_remove(GR,f)
reid GR;
REField f;
{
  REMember REmf, REm=f->container;
  unsigned i,l1,l2;
  Darray D=Darray_create();
  REField tf;

  GR->If_Contents_GR=Darray_remove_ptr(GR->If_Contents_GR,f);
  
  REmf=REm->father;
  if (REmf!=NULL) {
    if (REmf->Type==ALRMT_ASSOC) {
      REmf->object.Assoc->Contents=
	Darray_remove_ptr(REmf->object.Assoc->Contents,REm);
    }
  }
  else if (GR->TopLevelMember_GR==REm) {
    GR->TopLevelMember_GR=NULL;
  }
  else
    FEnd("Weird error in ed.c ^^^100\n");
}

/*--------------------------------------------------*/
void ed_Action_delete_CB(w,Obj2,cadda)
Widget w;
CBObj2 Obj2;
caddr_t cadda;
{
  reid GR=Obj2->one;
  REAction REac=Obj2->two;
  REAction Prev, Next, Curr;
  Widget Prev1, Prev2, Next1, Next2, Curr1, Curr2;
  ArgPack AP;
  unsigned i, l1, l2, l3, l4;
  REArgument REarg;
  Bool Found=Bool_FALSE;
  Darray D=Darray_create();
  REAction ta;
  
  l1=Darray_len(GR->Then_Contents_GR);
  for (i=0;i<l1;i++) {
    if ((Curr=(REAction)Darray_get(GR->Then_Contents_GR,i))==REac) {
      if (i==0) {
	Prev1=NULL;
	Prev2=NULL;
      }
      else {
	Prev=(REAction)Darray_get(GR->Then_Contents_GR,i-1);
	l2=Darray_len(Prev->Arguments);
	if (l2==0) {
	  Prev1=Prev->ContainerW;
	  Prev2=Prev->ArgsContainerBuffW;
	}
	if (l2==1) {
	  Prev1=Prev->ContainerW;
	  REarg=Darray_get(Prev->Arguments,0);
	  Prev2=REarg->ContainerW;
	}
	else {
	  REarg=(REArgument)Darray_get(Prev->Arguments,l2-1);
	  Prev1=REarg->ContainerBuffW;
	  Prev2=REarg->ContainerW;
	}
      }
      if (i==(l1-1)) {
	Next1=NULL;
	Next2=NULL;
      }
      else {
	Next=(REAction)Darray_get(GR->Then_Contents_GR,i+1);
	Next1=Next->ContainerW;
	l2=Darray_len(Next->Arguments);
	if (l2==0) 
	  Next2=Next->ArgsContainerBuffW;
	else {
	  REarg=(REArgument)Darray_get(Next->Arguments,0);
	  Next2=REarg->ContainerW;
	}
      }
      Found=Bool_TRUE;
      break;
    }
  }
  Curr1=Curr->ContainerW;
  if ((l3=Darray_len(Curr->Arguments))==0)
    Curr2=Curr->ArgsContainerBuffW;
  else {
    REarg=(REArgument)Darray_get(Curr->Arguments,0);
    Curr2=REarg->ContainerW;
  }
  if (Found==Bool_FALSE)
    Al_fatal_error((const char *)"ed_Action_delete_CB:couldn't find field");
  if (Next1!=NULL) {
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)Prev1);
    XtSetValues(Next1,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
    AP=ArgPack_create();
    ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)Prev2);
    XtSetValues(Next2,ArgPack_the_args(AP),ArgPack_num_args(AP));
    ArgPack_delete(AP);
  }
  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)NULL);
  XtSetValues(Curr1,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);
  AP=ArgPack_create();
  ArgPack_add_arg(AP,XtNfromVert,(XtArgVal)NULL);
  XtSetValues(Curr2,ArgPack_the_args(AP),ArgPack_num_args(AP));
  ArgPack_delete(AP);

  XtUnmanageChild(Curr1);
  Darray_addh(GR->WidgetKillList_GR,Curr1);
  XtUnmanageChild(Curr2);
  Darray_addh(GR->WidgetKillList_GR,Curr2);

  if (l3>1) {
    for (i=1;i<l3;i++)  {
      REarg=(REArgument)Darray_get(Curr->Arguments,i);
      XtUnmanageChild(REarg->ContainerW);
      Darray_addh(GR->WidgetKillList_GR,REarg->ContainerW);
      XtUnmanageChild(REarg->ContainerBuffW);
      Darray_addh(GR->WidgetKillList_GR,REarg->ContainerBuffW);
    }
  }
  GR->Then_Contents_GR=Darray_remove_ptr(GR->Then_Contents_GR,REac);
  GR->Actions_GR=Darray_remove_ptr(GR->Actions_GR,REac);
}
