/*
 * Copyright (c) 1998 Sasha Vasko <sashav@sprintmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/*#define DO_CLOCKING      */

#define TRUE 1
#define FALSE

#include "../configure.h"

#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#include "../include/aftersteplib.h"
#include "../include/parser.h"

#ifdef DEBUG_PARSER
#define LOG1(a)       fprintf( stderr, a );
#define LOG2(a,b)    fprintf( stderr, a, b );
#define LOG3(a,b,c)    fprintf( stderr, a, b, c );
#define LOG4(a,b,c,d)    fprintf( stderr, a, b, c, d );
#else
#define LOG1(a)
#define LOG2(a,b)
#define LOG3(a,b,c)
#define LOG4(a,b,c,d)
#endif

HashValue
GetHashValue (char *text, int hash_size)
{
  register int i;
  HashValue hash_value = 0;
  for (i = 0; i < ((sizeof (HashValue) - sizeof (char)) << 3); i++)
    {
      if (text[i] == '\0' || isspace (text[i]))
	break;
      hash_value += (((HashValue) (tolower (text[i]))) << i);
    }
  return hash_value % hash_size;
}

void
InitHash (SyntaxDef * syntax)
{
  register int i;

  if (syntax->term_hash_size <= 0)
    syntax->term_hash_size = TERM_HASH_SIZE;
  if (syntax->term_hash == NULL)
    syntax->term_hash = (TermDef **) safemalloc (sizeof (TermDef *) * (syntax->term_hash_size));

  for (i = 0; i < syntax->term_hash_size; i++)
    syntax->term_hash[i] = NULL;
}

void
BuildHash (SyntaxDef * syntax)
{
  HashValue hash_value;
  TermDef *current;
  int i;
  for (i = 0; syntax->terms[i].keyword; i++)
    syntax->terms[i].brother = NULL;

  for (i = 0; syntax->terms[i].keyword; i++)
    {
      hash_value = GetHashValue (syntax->terms[i].keyword, syntax->term_hash_size);
      if (syntax->term_hash[hash_value])
	{
	  for (current = syntax->term_hash[hash_value];
	       current->brother;
	       current = current->brother);
	  current->brother = &(syntax->terms[i]);
	}
      else
	syntax->term_hash[hash_value] = &(syntax->terms[i]);
    }
}

TermDef *
FindTerm (SyntaxDef * syntax, int type, int id)
{
  register int i;
  if (syntax)
    for (i = 0; syntax->terms[i].keyword; i++)
      if (type == TT_ANY || type == syntax->terms[i].type)
	if (id == ID_ANY || id == syntax->terms[i].id)
	  return &(syntax->terms[i]);

  return NULL;
}

/* this one will identify Term using Hash table
   it will seT :
   - current_term to the term found
   Returns : NULL if no terms found, otherwise same as current_term.
 */
TermDef *
FindStatementTerm (char *tline, SyntaxDef * syntax)
{
  HashValue hash_value;
  TermDef *pterm;

  hash_value = GetHashValue (tline, syntax->term_hash_size);
  for (pterm = syntax->term_hash[hash_value]; pterm; pterm = pterm->brother)
    if (mystrncasecmp (tline, pterm->keyword, pterm->keyword_len) == 0)
      return pterm;
  return NULL;
}
