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

#include "FTreg.h"
#include "string.h"
#include "memory.h"
#include "useful.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 comma_one_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 comma_contains(text,pattern)
const char *pattern, *text;
{
  Darray patternD=Darray_create();
  int i,l;
  RapList_parse_into_darray(patternD,pattern);
  l=Darray_len(patternD);
  for (i=0;i<l;i++) 
    if (comma_one_contains(text,Darray_get(patternD,i))) {
      RapList_destroy_darray_contents(patternD);
      Darray_destroy(patternD);
      return(1);
    }
  RapList_destroy_darray_contents(patternD);
  Darray_destroy(patternD);
  return(0);
}


/*--------------------------------------------------*/
static int comma_one_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 comma_contains_word(text,pattern)
const char *pattern, *text;
{
  Darray patternD=Darray_create();
  int i,l;
  RapList_parse_into_darray(patternD,pattern);
  l=Darray_len(patternD);
  for (i=0;i<l;i++) 
    if (comma_one_contains_word(text,Darray_get(patternD,i))) {
      RapList_destroy_darray_contents(patternD);
      Darray_destroy(patternD);
      return(1);
    }
  RapList_destroy_darray_contents(patternD);
  Darray_destroy(patternD);
  return(0);
}


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


/*--------------------------------------------------*/
static int comma_equal(text,pattern)
const char *pattern, *text;
{
  Darray patternD=Darray_create();
  int i,l;
  RapList_parse_into_darray(patternD,pattern);
  l=Darray_len(patternD);
  for (i=0;i<l;i++) 
    if (comma_one_equal(text,Darray_get(patternD,i))) {
      RapList_destroy_darray_contents(patternD);
      Darray_destroy(patternD);
      return(1);
    }
  RapList_destroy_darray_contents(patternD);
  Darray_destroy(patternD);
  return(0);
}


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

/*--------------------------------------------------*/
static int comma_less(text,pattern)
const char *pattern, *text;
{
  Darray patternD=Darray_create();
  int i,l;
  RapList_parse_into_darray(patternD,pattern);
  l=Darray_len(patternD);
  for (i=0;i<l;i++) 
    if (comma_one_less(text,Darray_get(patternD,i))) {
      RapList_destroy_darray_contents(patternD);
      Darray_destroy(patternD);
      return(1);
    }
  RapList_destroy_darray_contents(patternD);
  Darray_destroy(patternD);
  return(0);
}


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

/*--------------------------------------------------*/
static int comma_greater(text,pattern)
const char *pattern, *text;
{
  Darray patternD=Darray_create();
  int i,l;
  RapList_parse_into_darray(patternD,pattern);
  l=Darray_len(patternD);
  for (i=0;i<l;i++) 
    if (comma_one_greater(text,Darray_get(patternD,i))) {
      RapList_destroy_darray_contents(patternD);
      Darray_destroy(patternD);
      return(1);
    }
  RapList_destroy_darray_contents(patternD);
  Darray_destroy(patternD);
  return(0);
}


static NORET comma_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", comma_contains },

  { "matches  word", comma_contains_word },
  { "contains word", comma_contains_word },

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

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

  { "is greater than", comma_greater },
  { "greater than", comma_greater },
  { "greater", comma_greater },
  { ">",comma_greater },

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

static struct AlFieldTypeRegistry_str  comma_FTrec={
  "Case Sensitive with Commas as ORs",
  parser,
  un_parser,
  fieldOpList,
  NULL,
  NULL,
  comma_free,
};

struct AlFieldTypeRegistry_str  *comma_FTrecptr = &comma_FTrec;
