#include <stddef.h>
#include <assert.h>
#include <ctype.h>

#include "FTreg.h"
#include "string.h"
#include "memory.h"

static char *parser(str)
const char *str;
{
  char *temp_buffer;
  int str_len;

  assert(str != (const char *)NULL);
  str_len = strlen(str);

  temp_buffer = (char *)Memory_allocate(str_len+1);
  strcpy(temp_buffer, str);
  return temp_buffer;
}

static const char *un_parser(s)
const char *s;
{
  return s;
}

/* ### ### replace with DFA or Boyer-Moore code for efficency ### ### */

static int string_contains(text,pattern)
const char *pattern, *text;
{
  int i, last_index, length_of_pattern;

  assert(pattern != (const char *)NULL && text != (const char *)NULL);

  length_of_pattern = strlen(pattern);
  last_index = strlen(text) - length_of_pattern + 1;

  if (last_index > 0) {
    for (i=0; i < last_index; i++) {
      if (strncmp(pattern, &(text[i]), length_of_pattern) == 0) {
	return 1;
      }
    }
  }

  /* pattern too long or pattern not found */
  return 0;
}

static int string_contains_word(text,pattern)
const char *pattern, *text;
{
  int i, last_index, length_of_pattern;

  assert(pattern != (const char *)NULL && text != (const char *)NULL);

  length_of_pattern = strlen(pattern);
  last_index = strlen(text) - length_of_pattern + 1;

  if (last_index > 0) {
    for (i=0; i < last_index; i++) {
      if (((i=0) || !isalpha(text[i-1])) &&
	  ((i = last_index) || !isalpha(text[i+length_of_pattern])) &&
	  (strncmp(pattern, &(text[i]), length_of_pattern) == 0)) {
	return 1;
      }
    }
  }

  /* pattern too long or pattern not found */
  return 0;
}


static int string_equal(value, pattern)
const char *value, *pattern;
{
  return (strcmp(pattern, value) == 0);
}

static int string_less(value, pattern)
const char *value, *pattern;
{
  return (strcmp(pattern, value) < 0);
}

static int string_greater(value, pattern)
const char *value, *pattern;
{
  return (strcmp(pattern, value) > 0);
}

static NORET string_free(data)
char *data;
{
  Memory_free((VOIDP)data);
}

/*  The name of the first item in each group below will appear in the */
 /*  ruleeditor menu.  All the other items are equivalent ways to name that */
 /*  field operator. */
static FieldOpArg fieldOpList[]={
  { "contains", string_contains },

  { "matches word", string_contains_word },
  { "contains word", string_contains_word },

  { "exactly matches",string_equal },
  { "is equal to",string_equal },
  { "equal",string_equal },
  { "equals",string_equal },
  { "=",string_equal },

  { "is less than", string_less },
  { "less",string_less },
  { "less than", string_less },
  { "<",string_less },

  { "is greater than", string_greater },
  { "greater", string_greater },
  { "greater_than", string_greater },
  { ">",string_greater },

  { (char *)NULL, (FieldOperatorProc *)NULL }
};

static struct AlFieldTypeRegistry_str  string_FTrec={
  "Case Sensitive Text",
  parser,
  un_parser,
  fieldOpList,
  NULL,
  NULL,
  string_free,
};

struct AlFieldTypeRegistry_str  *string_FTrecptr = &string_FTrec;
