#include "Structures.h"
#include <regex.h>
#pragma implementation

long hps=0;
h_pair::h_pair(String* in, Value* val, h_pair* nxt){
  index = in;
  data = val;
  next = nxt;
}
h_pair::~h_pair(){
  delete index;
  data->release();
}

StringValHash::StringValHash(){
  int i;
  for (i=0 ; i<HASH_WIDTH ; i++)
    htable[i] = (h_pair*) NULL;
}

StringValHash::~StringValHash(){
  h_pair* hl, *next;
  int i;
  for (i = 0 ; i<HASH_WIDTH ; i++)
    for (hl = htable[i] ; hl ; hl=next)
      {next=hl->next;
       delete hl;}
}

#define HASH(a) ((*(a)) ? (((a)[0] ^ ~(a)[1]) & 3) : 0)

Value* StringValHash::lookup (String* instring){
  char* searchstr;
  int l, i;
  h_pair* hl;
  l = instring->length();
  searchstr = (char*)instring->chars();
  i = HASH(searchstr);
  for (hl = htable [ HASH(searchstr) ] ;
       hl && (hl->index->length() <= l) ; hl=hl->next)
    {if (! fcompare (*instring, *(hl->index)))
     return (hl->data);}
  return NULL;
}

int StringValHash::add (Value* inval, String* key){
  h_pair* *temp;
  h_pair *newnode;
  char* searchstr;
  int l;
  l = key->length();
  searchstr = (char*)key->chars();
  for (temp = &(htable [HASH(searchstr)]);
       *temp && ((*temp)->index->length() <= l);
       temp = &((*temp)->next))
    if (!fcompare (*((*temp)->index) , *key))
      {(*temp)->data->release();
       (*temp)->data = inval->grab();
       return 1;}
  newnode = new h_pair (new String (*key), inval->grab(), *temp);
  (*temp) = newnode;
  return 0;
}

int StringValHash::remove (String* sym){
  h_pair **temp, *next;
  char* searchstr;
  int l;
  searchstr = (char*)sym->chars();
  l = sym->length();
  for (temp = &(htable [HASH(searchstr)]) ;
       *temp && ((*temp)->index->length() <= l) ;
       temp = &((*temp)->next))
    if (!fcompare (*((*temp)->index) , *sym))
      {next = ((*temp)->next);
       delete (*temp);
       *temp = next;
       return 1;}
  return 0;
}

Value* StringValHash::list_vars(){
  int i;
  h_pair* ht = NULL;
  Value* retval = NULL;
  Val_List* outlist = NULL;
  for (i=0 ; i<HASH_WIDTH ; i++)
    for (ht = htable[i] ; ht ; ht=ht->next)
      {outlist = new Val_List ((new Value (new String (*ht->index), SYM)),
			       outlist);}
  retval = new Value (outlist);
  return retval;
};

void StringValHash::dump_to_stdout(){
  int i;
  h_pair* ht = NULL;
  Value* tempval;
  for (i=0 ; i<HASH_WIDTH ; i++)
    for (ht = htable[i] ; ht ; ht=ht->next)
      {cout << *(ht->index) << "\n";
       tempval = ht->data->copy();
       tempval->print_val();
       delete tempval;
       cout << "\n/\n";}
}

char* StringValHash::pack_syms(char* buf){
  int i;
  h_pair* h;
  for (i=0 ; i<HASH_WIDTH ; i++)
    for (h = htable[i] ; h ; h=h->next)
      {strcpy (buf , (char*)h->index->chars());
       buf += h->index->length() + 1;
       buf =  h->data->pack_value(buf);}
  *buf = '\0';
  return (buf+1);
}

/************************************************************
******** SymVal_List functions: ****************************
************************************************************/

SymVal_List::SymVal_List(){
  pair_list = NULL;
}

SymVal_List::~SymVal_List(){
  struct svl_rep* temp;
  while (pair_list)
    pop();
}

void SymVal_List::push (String* s, Value* v){ 
  struct svl_rep* temp;
  temp = new struct svl_rep;
  temp->symbol = new String (*s);
  temp->val = v->grab();
  temp->next = pair_list;
  pair_list = temp;
}

void SymVal_List::pop (){
  struct svl_rep* temp;
  if (pair_list)
    {temp = pair_list->next;
     pair_list->val->release();
     delete pair_list->symbol;
     delete pair_list;
     pair_list = temp;}
}

Value* SymVal_List::peek (){
  if (pair_list)
    return pair_list->val;
  return NULL;
}

String* SymVal_List::peek_symbol (){
  if (pair_list)
    return pair_list->symbol;
  return NULL;
}

Value* SymVal_List::lookup (String* s){
  struct svl_rep* temp, *prev;
  int i;
  for (i=0, temp=pair_list ; temp ; prev = temp, temp=temp->next, i++)
    if (*s == *(temp->symbol))
      return temp->val;
  return NULL;
}

int SymVal_List::assign (String* s, Value* v){
  struct svl_rep* temp;
  for (temp=pair_list ; temp ; temp=temp->next)
    if (*s == *(temp->symbol))
      {temp->val->release();
       temp->val = v->grab();
       return 1;}
  return 0;
}

/************************************************************
******** ReStringList functions: ****************************
************************************************************/

ReList::ReList(String* s, Regex* r, String* d, ReList* n){
  index = s;
  condensed = r;
  data = d;
  next = n;
}
ReList::~ReList(){
  delete index;
  delete condensed;
  delete data;
}

#define HASH_RE(a) ((a) ? ((a) & 3) : 0)

ReStringHash::ReStringHash(){
  int i;
  for (i=0 ; i<HASH_WIDTH ; i++)
     rtable[i] = NULL;
}

ReStringHash::~ReStringHash(){
  ReList* ptr;
  int i;
  for (i=0 ; i<HASH_WIDTH ; i++)
    while (rtable[i])
      {ptr=rtable[i]->next;
       delete rtable[i];
       rtable[i]=ptr;}
}

#define WILD_CARD(a) (buf[0] == '.' || buf[0] == '[' || buf[0] == '(' ||  \
		      buf[0] == '+' || buf[0] == '*' || buf[0] == ']' ||  \
		      buf[0] == '\\' || buf[0] == '?')

int valid_regexp (String* key){
  int i, l, bct=0, pct=0, esc=0;
  char* buf;
  l = key->length();   buf = (char*)key->chars();
  for (i=0 ; i<l ; i++)
    {switch (buf[i])
     {case '\\':  esc++;  break;
     case '[':  if (!(esc % 2)) {bct++;}  esc=0;  break;
     case ']':  if (!(esc % 2)) {bct--;}  esc=0;  break;
     case '(':  if (!(esc % 2))    {pct++;}  esc=0;  break;
     case ')':  if (!(esc % 2))    {pct--;} esc=0;  break;
     default:   esc=0; break;}}
  return (!bct && !pct);
}  
     
int ok_regexp (String* key){
  int i, l, bct=0, pct=0, esc=0;
  char* buf;
  l = key->length();   buf = (char*)key->chars();
  if (!l || WILD_CARD(buf[0]) ||
      (l > 1 && (buf[1] == '*' || buf[1] == '?')))
    return 0;
  return valid_regexp (key);
}

Regex* ReStringHash::add(String* key, String* indata){
  ReList* temp;
  int h;
  if (! ok_regexp (key))
    {delete key;
     delete indata;
     return NULL;}
  h = HASH_RE (key->chars()[0]);
  temp = new ReList (key, new Regex(key->chars(),0,key->length()),
		     indata, rtable[h]);
  rtable [h] = temp;
  return temp->condensed;
}

String* ReStringHash::lookup (String* pattern){
  ReList* traverser;
  for (traverser = rtable [HASH_RE (pattern->chars()[0])]
       ; traverser ; traverser = traverser->next)
    if (pattern->matches(*traverser->condensed))
      {return traverser->data;}
  return NULL;
}

Val_List* ReStringHash::lookup_all (String* pattern){
  Val_List* retval=NULL;
  ReList* traverser;
  int h;
  h = HASH_RE (pattern->chars()[0]);
  for (traverser = rtable [h]
       ; traverser ; traverser = traverser->next)
    if (pattern->matches(*traverser->condensed))
      {retval = new Val_List (new Value (new String (*traverser->data), SYM),
			      retval);}
  return retval;
}

int ReStringHash::remove (String* pattern){
  ReList** traverser, *temp;
  traverser = &rtable [HASH_RE (pattern->chars()[0])];
  for ( ; *traverser ; traverser = &((*traverser)->next))
    if (pattern->matches(*(*traverser)->condensed))
      {temp = (*traverser)->next;
       delete (*traverser);
       *traverser = temp;
       return 1;}
  return 0;
}

int ReStringHash::purge (){
  ReList *temp;
  int i;
  for (i = 0 ; i<HASH_WIDTH ; i++)
    {while (rtable [i])
       {temp = rtable[i];
	rtable[i] = rtable[i] -> next;
	delete temp;}}
  return 1;
}

char* ReStringHash::pack_cmds(char* buf){
  ReList* temp, *rlist;
  int i;
  for (i=0 ; i<HASH_WIDTH ; i++)
    {rlist = rtable [i];
     for (temp = rlist ; temp ; temp=temp->next)
       {strcpy (buf , (char*)temp->index->chars());
	buf += temp->index->length() + 1;
	strcpy (buf , (char*)temp->data->chars());
	buf += temp->data->length() + 1;}}
  *buf = '\0';
  return ++buf;
}

char* ReStringHash::unpack(char* buf){
  String *tempstring, *tempstring2;
  while (*buf)
    {tempstring = new String (buf);
     buf += tempstring->length() + 1;
     tempstring2 = new String (buf);
     buf += tempstring2->length() + 1;
     add (tempstring , tempstring2);}
  return buf+1;
}

Value* ReStringHash::list_cmds(){
  ReList *rl, *rlist;
  int i;
  Val_List* biglist=NULL, *outlist;
  for (i=0 ; i<HASH_WIDTH ; i++)
    {rlist = rtable [i];
     for (rl = rlist ; rl ; rl = rl->next)
       {outlist=NULL;
	outlist = new Val_List ((new Value (new String (*rl->data), SYM)),
				outlist);
	outlist = new Val_List ((new Value (new String (*rl->index))),
				outlist);
	biglist = new Val_List ((new Value (outlist)), biglist);}}
  return new Value (biglist);
}

void ReStringHash::dump_to_stdout(){
  ReList *rl;
  int i;
  for (i=0 ; i<HASH_WIDTH ; i++)
    for (rl = rtable[i] ; rl ; rl = rl->next)
      {cout << *(rl->index) << "\n";
       cout << *(rl->data) << "\n";}
}