#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));

#define Alruleprint_type_to_str(ft) \
       ((ft == ALRFT_MSG) ? "Field-From-Message" \
         : ((ft == ALRFT_UP) ? "User-Property" \
	     : ((ft == ALRFT_FI) ? "Folder-Specific-Field" \
		 : "Message-State-Field")))

#define Alruleprint_get_key(ft, fc) \
     ((ft == ALRFT_MSG) ? AlFieldCore_get_key(fc) \
      : ((ft == ALRFT_UP) ? AlFieldCore_get_key(fc) \
	 : ((ft == ALRFT_FI) ? AlFieldCore_get_key(fc) \
	    : ((ft == ALRFT_SMF) ? "Moved-From:" \
	       : ((ft == ALRFT_SNTM) ? "Number-of-Times-Moved:" \
		  : ((ft == ALRFT_SNRF) ? "Number-of-Rules-Fired:" \
		     : ((ft == ALRFT_SNOF) ? "Number-Of-Fields:" \
			 : ((ft == ALRFT_SMLL) ? "Message-Line-Length:" \
			    : ((ft == ALRFT_SMCL) \
			       ? "Message-Character-Length:" \
			       : ((ft == ALRFT_SBLL) \
				  ? "Message-Body-Line-Length:" \
				  : ((ft == ALRFT_SBCL) \
				     ? "Message-Body-Character-Length:" \
				     : ((ft == ALRFT_SNUB) \
					? "Number-of-Unprintables-in-Body:" \
					: ((ft == ALRFT_SFC) \
					   ? "Field Count:" \
					   : "{Unknown}")))))))))))))


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);

  cp = Alruleprint_get_key(ft, 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 = Alruleprint_type_to_str(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;

  strcpy(buffer, " IF");
  char_count = 3;
  char_count += Alruleprint_member(buffer + char_count,
				   buflen - char_count,
				   print_type,
				   AlRule_get_predicate(rule),
				   0);
  strcpy(buffer + char_count, " THEN");
  char_count += 5;
  char_count += Alruleprint_actions(buffer + char_count, 
				    buflen - char_count,
				    AlRule_get_actions(rule),
				    2);
  return char_count;
}
