#ifndef _VAR_STRING_HASH_H_
#define _VAR_STRING_HASH_H_ 1

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

class VarStrHashNode
{
friend class VarStrHash;
friend class VarStrHashIterator;

private:
	int              copyKeyFlag;
	char           * hashString;
	void           * hashData;
	VarStrHashNode * next;

	VarStrHashNode  ( char * HashString, void * HashData, int copyKey=1);
	~VarStrHashNode ( void );
};


class VarStrHash
{
friend class VarStrHashIterator;

private:
	int               tableSize;
	int               copyKeyFlag;
	VarStrHashNode ** nodes;
	
public:
	VarStrHash  (int copyKey = 1, int TableSize = 255 );
	~VarStrHash ( void );

	inline unsigned char stringHash ( char * hashString );

	inline void insert ( char * hashString, void * hashData );
	inline void remove ( char * hashString );
	inline void * find ( char * hashString );
};


class VarStrHashIterator
{
private:
	VarStrHash     * hashTbl;
	VarStrHashNode * node;
	int              idx;	

public:
	VarStrHashIterator( VarStrHash * HashTbl );	
	~VarStrHashIterator( void );
	
	inline void * first       ( void );
	inline void * operator ++ ( void );
	inline void * operator ++ ( int x );
	inline char * key         ( void );
	inline void * data        ( void );
};


inline VarStrHashNode::VarStrHashNode ( char * HashString, void * HashData, int copyKey )
	: next(NULL), copyKeyFlag(copyKey)
	{
	if(copyKeyFlag) hashString = strdup(HashString);
	else            hashString = HashString;
        hashData  = HashData;
	}


inline VarStrHashNode::~VarStrHashNode ( void )
	{
	if(copyKeyFlag) delete hashString;
        }


inline VarStrHash::VarStrHash  ( int copyKey, int TableSize ) 
	: copyKeyFlag(copyKey), tableSize (TableSize)
	{
	nodes = new VarStrHashNode * [tableSize];
	memset(nodes, 0, sizeof(VarStrHashNode *) * tableSize );
	}


inline VarStrHash::~VarStrHash ( void )
	{
	for(int i=0; i<tableSize; i++)
		{
		while(nodes[i]!=NULL)
			{
			VarStrHashNode * node = nodes[i];
			nodes[i] = node->next;
			delete node;
                        }
		}
	}

inline unsigned char VarStrHash::stringHash ( char * hashString )
	{
	unsigned char idx=0;
	unsigned int hash = 0, g;

	for (int i = 0; hashString[i] != '\0'; i++)
		{
		hash = (hash << 4) + hashString[i];
		if (g = hash & 0xf0000000)
			{
			hash ^= g >> 24;
			hash ^= g;
			}
		}
	return (hash % tableSize);
	}

inline void VarStrHash::insert (char * hashString, void * hashData )
	{
	unsigned char idx = stringHash(hashString);
	VarStrHashNode * prev    = NULL, * node = nodes[idx];
	VarStrHashNode * newNode = new VarStrHashNode(hashString, hashData, copyKeyFlag);

	while(node!=NULL && strcmp(node->hashString, hashString))
		{
		prev = node;
		node = prev->next;
		}
	if(node!=NULL)
		{
		newNode->next = node->next;
		delete node;
		}
	if(prev!=NULL) prev->next = newNode;
	else           nodes[idx] = newNode;
	}

inline void VarStrHash::remove ( char * hashString )
	{
	unsigned char idx = stringHash(hashString);
	VarStrHashNode * prev = NULL, * node = nodes[idx];
	while(node!=NULL && strcmp(node->hashString, hashString))
		{
		prev = node;
		node = prev->next;
		}
	if(node!=NULL)
		{
		if(prev!=NULL) prev->next = node->next;
		else           nodes[idx] = node->next;
		delete node;
		}
	}

inline void * VarStrHash::find ( char * hashString )
	{
	unsigned char idx = stringHash(hashString);
	VarStrHashNode * prev = NULL, * node = nodes[idx];
	while(node!=NULL && strcmp(node->hashString, hashString))
		{
		prev = node;
		node = prev->next;
		}
	return node!=NULL?node->hashData:NULL;
	}


inline VarStrHashIterator::VarStrHashIterator(VarStrHash * HashTbl)
	: hashTbl(HashTbl), idx(0), node(NULL)
	{
	}
	
inline VarStrHashIterator::~VarStrHashIterator( void ) 
	{
	}
	
inline void * VarStrHashIterator::first ( void )
	{
	if(hashTbl!=NULL)
		{
		for(idx = 0; idx<hashTbl->tableSize &&
		   (node = hashTbl->nodes[idx])==NULL; idx++);
		}
	else node = NULL;
	return (node!=NULL)?node->hashData:NULL;
	}
	
inline void * VarStrHashIterator::operator ++ ( void )
	{
	if(hashTbl!=NULL)
		{
		if(node==NULL) first();
		else if(node->next!=NULL) node = node->next;
		else 
			{
			node = NULL;
			do 	{
				idx++;
				} while(idx<hashTbl->tableSize && 
				       (node = hashTbl->nodes[idx])==NULL);
			}
		}
	else node = NULL;
	return (node!=NULL)?node->hashData:NULL;
	}
	
inline void * VarStrHashIterator::operator ++ ( int x )
	{
	if(hashTbl!=NULL && x==0)
		{
		if(node==NULL) first();
		else if(node->next!=NULL) node = node->next;
		else 
			{
			node = NULL;
			do 	{
				idx++;
				} while(idx<hashTbl->tableSize && 
				       (node = hashTbl->nodes[idx])==NULL);
			}
		}
	else node = NULL;
	return (node!=NULL)?node->hashData:NULL;
	}

inline char * VarStrHashIterator::key ( void )
	{
	return (node!=NULL)?node->hashString:NULL;
	}
	
inline void * VarStrHashIterator::data ( void )
	{
	return (node!=NULL)?node->hashData:NULL;
	}
	
#endif /* _VAR_STRING_HASH_H_ */
