#include "ruleprint.h"

static int Alruleprint_field PROTOTYPE((char *, int, Bool, AlRuleField, int));
static int Alruleprint_assoc PROTOTYPE((char *, int, Bool, AlRuleAssoc, 
					int, int));
static int Alruleprint_member PROTOTYPE((char *, int, Bool, AlRuleMember, int));
static int Alruleprint_action PROTOTYPE((char *, int, AlAction, int));
static int Alruleprint_actions PROTOTYPE((char *, int, Darray, int));
extern int Alruleprint PROTOTYPE((char *, int, Bool, AlRule));

static int Alruleprint_field(buffer, buflen, print_type, field, indent)
     char *buffer;
     int buflen;
     Bool print_type;
     AlRuleField field;
     int indent;
{
  static char *temp_buf;
  const char *cp;
  int char_count = 0;
  AlFieldCore fc;
  AlRAType ft;
  int i;

  temp_buf = (char *)Memory_allocate(1000);

  for (i = 0; i < indent; ++i)
    temp_buf[char_count++] = ' ';
  temp_buf[char_count] = '\0';

  fc = AlRuleField_get_fc(field);
  ft = AlRuleField_get_type(field);
  
  if (AlRule_is_state(ft)==Bool_TRUE)
    cp=AlRule_get_name_from_class(ft);
  else
    cp=AlFieldCore_get_key(fc);
  strcpy((temp_buf + char_count), cp);
  char_count += strlen(cp);
  temp_buf[char_count] = ' ';
  char_count++;

  cp = AlRuleField_get_op_name(field);
  strcpy((temp_buf + char_count), cp);
  char_count += strlen(cp);
  temp_buf[char_count] = ' ';
  char_count++;

  cp = AlRuleField_get_strvalue(field);
  strcpy((temp_buf + char_count), cp);
  char_count += strlen(cp);
  temp_buf[char_count] = ' ';
  char_count++;

  if (print_type != Bool_FALSE) {
    temp_buf[char_count++] = ' ';
    temp_buf[char_count++] = ' ';
    temp_buf[char_count++] = '[';
    cp = AlFieldCore_get_field_type_name(fc);
    strcpy((temp_buf + char_count), cp);
    char_count += strlen(cp);
    temp_buf[char_count++] = ',';
    cp = AlRule_get_name_from_class(ft);
    strcpy((temp_buf + char_count), cp);
    char_count += strlen(cp);
    temp_buf[char_count++] = ']';
  }

  temp_buf[char_count++] = '\n';
  temp_buf[char_count] = '\0';

  if (char_count > buflen - 1) {
    Memory_free(temp_buf);
    return -1;
  } else {
    strcpy(buffer, temp_buf);
    Memory_free(temp_buf);
    return char_count;
  }
}

static int Alruleprint_assoc(buffer, buflen, print_type, assoc, indent, first)
     char *buffer;
     int buflen;
     Bool print_type;
     AlRuleAssoc assoc;
     int indent;
     int first;  /* indent, for first indent only */
{
  static char *temp_buf;
  const char *cp;
  int char_count = 0;
  int i, j;
  Darray contents;
  int num_contents;
  AlRAType atype;

  temp_buf = (char *)Memory_allocate(1000);
  temp_buf[char_count] = '\0';

  contents = Darray_create();
  (NORET)AlRuleAssoc_get_contents(assoc, contents);
  num_contents = Darray_len(contents);

  if (num_contents == 0) {
    Memory_free(temp_buf);
    return 0;
  }
  
  atype =  AlRuleAssoc_get_type(assoc);
  for (i = 0; i < num_contents; ++i) {
    if (i != 0 || atype == ALRAT_NOT) {
      for (j = 0; j < indent; ++j)
	temp_buf[char_count++] = ' ';
      temp_buf[char_count] = '\0';
      cp = AlRuleAssoc_atype(AlRuleAssoc_get_type(assoc));
      strcpy((temp_buf + char_count), cp);
      char_count += strlen(cp);
      temp_buf[char_count++] = '\n';
      temp_buf[char_count] = '\0';
    }
    char_count += Alruleprint_member((temp_buf + char_count),
				     1000 - char_count, 
				     print_type, 
				     (AlRuleMember)Darray_get(contents,
							      (unsigned) i),
				     ((i == 0) 
				      ? (first + 2)
				      : (indent + 2)));
  }
  Darray_destroy(contents);
  if (char_count > buflen - 1) {
    Memory_free(temp_buf);
    return -1;
  } else {
    strcpy(buffer, temp_buf);
    Memory_free(temp_buf);
    return char_count;
  }
}      

static int Alruleprint_member(buffer, buflen, print_type, member, indent)
     char *buffer;
     int buflen;
     Bool print_type;
     AlRuleMember member;
     int indent;
{
  /* none of these switch arms are supposed to fall through  */
  switch (AlRuleMember_get_type(member)) {
  case ALRMT_ASSOC:
    return Alruleprint_assoc(buffer, buflen, print_type, 
			     AlRuleMember_get_assoc(member),
			     3, indent);
  case ALRMT_FIELD:
    return Alruleprint_field(buffer, buflen, print_type, 
			     AlRuleMember_get_field(member),
			     indent + 3);
  default: 
    return(0);
  }
}

static int Alruleprint_action(buffer, buflen, action, indent)
     char *buffer;
     int buflen;
     AlAction action;
     int indent;
{
  int i,j;
  char *temp_buf;
  int char_count = 0;
  Darray args;
  int num_args;
  const char *cp;

  temp_buf = (char *)Memory_allocate(1000);

  for (j = 0; j < indent; ++j)
    temp_buf[char_count++] = ' ';
  temp_buf[char_count] = '\0';

  cp = AlVerbReg_get_name(AlAction_verb(action));
  strcpy((temp_buf + char_count), cp);
  char_count += strlen(cp);
  
  args = AlAction_args(action);
  num_args = Darray_len(args);
  for (i = 0; i < num_args; ++i) {
    temp_buf[char_count++] = ' ';
    temp_buf[char_count++] = '"';
    cp = (const char *)Darray_get(args, (unsigned) i);
    strcpy((temp_buf + char_count), cp);
    char_count += strlen(cp);
    temp_buf[char_count++] = '"';
  }
  temp_buf[char_count++] = '\n';
  temp_buf[char_count] = '\0';


  if (char_count > buflen - 1) {
    Memory_free(temp_buf);
    return -1;
  } else {
    strcpy(buffer, temp_buf);
    Memory_free(temp_buf);
    return char_count;
  }
}

static int Alruleprint_actions(buffer, buflen, actions, indent)
     char *buffer;
     int buflen;
     Darray actions;
     int indent;
{
  int i;
  char *temp_buf;
  int char_count = 0;
  int num_actions;

  temp_buf = (char *)Memory_allocate(1000);
  temp_buf[char_count] = '\0';

  num_actions = Darray_len(actions);
  for (i = 0; i < num_actions; ++i) {
    char_count += Alruleprint_action(temp_buf + char_count, 
				     1000 - char_count,
				     (AlAction)Darray_get(actions,
							  (unsigned) i),
				     ((i == 0) ? indent : (indent + 5)));
  }
  if (char_count > buflen - 1) {
    Memory_free(temp_buf);
    return -1;
  } else {
    strcpy(buffer, temp_buf);
    Memory_free(temp_buf);
    return char_count;
  }
}

int Alruleprint(buffer, buflen, print_type, rule)
     char *buffer;
     int buflen;
     Bool print_type;
     AlRule rule;
{
  int char_count = 0;
  int incr_char_count = 0;
  int retcode = 0;

  strcpy(buffer, " IF");
  char_count = 3;
  incr_char_count = Alruleprint_member(buffer + char_count,
				       buflen - char_count,
				       print_type,
				       AlRule_get_predicate(rule),
				       0);
  if (incr_char_count < 0)
    retcode = -1;
  else
    char_count += incr_char_count;
  strcpy(buffer + char_count, " THEN");
  char_count += 5;
  incr_char_count = Alruleprint_actions(buffer + char_count, 
				        buflen - char_count,
				        AlRule_get_actions(rule),
				        2);
  if (incr_char_count < 0)
    retcode = -1;
  else
    char_count += incr_char_count;

  if (retcode == -1)
    return(-1);
  else
    return char_count;
}
