// (c) 2000 by Zachary Booth Simpson
// This code may be freely used, modified, and distributed without any license
// as long as the original author is noted in the source file and all
// changes are made clear disclaimer using a "MODIFIED VERSION" disclaimer.
// There is NO warranty and the original author may not be held liable for any damages.
// http://www.totempole.net

/*
********************************** MODIFIED VERSION *************************************
Modification History:
01.03.2006 - Tamas Schlagl: Made it confortable with VC2005
********************************** MODIFIED VERSION *************************************
*/

#ifndef HASHTABLE_H
#define HASHTABLE_H

class HashTable {
  protected:
	// This implementes a hash-keyed associative array
	// in the same vain as a perl assoc. array

	int hasAnyChanged;
		// Has anything in here changed since the last time this was cleared
	__w64 int hashTableSize;
		// Number of pointers in the hash table
	__w64 int numRecords;
		// Actual active records in the table
	char **hashTable;
		// Array of key pointers, which are of the form:
		// 1 byte flags:
		#define aaDELETED (0x01)
		#define aaCHANGED (0x02)
		// followed by 0-terminated keyt string
		// followed by data

	__w64 int hash( char *key );
		// hashing function

	__w64 int set( char **_hashTable, __w64 int _hashTableSize, char *key, char *_recPtr );
		// Internal method to functionalize the during rebuild of tables
		// Returns 1 if the key is new, 0 if it is replacing an existing

  public:
	HashTable();
	~HashTable();

	__w64 int lookup( char *key );
		// Returns the index of key, or -1 if it wasn't found

	char *getKey( __w64 int i );
	char *getVal( __w64 int i );
		// Gets the i_th key/val in table. 
		// Useful when dumping the table contents

	char *get( char *key, __w64 int retEmptyString=0 );
		// Get the value associated with key.
		// if retEmptyString is true then a search that
		// fails will return an empty string ("") 
		// instead of NULL

	virtual void set( char *key, char *value, __w64 int len=-1 );
		// Sets the hash record key with value, overwriting
		// any existing value is there is one.  len is
		// the length of the value, or -1 if it is 
		// a null terminated string whose len should
		// be calculated.
		//
		// The buffer pointed to by value is always
		// copied into this buffer of len.
		//
		// Setting a key to NULL means you want to kill
		// the key.  Internally, it is marked as deleted.
		//
		// Returns the index of the array, althgouh this
		// is typically ignored.

	void clear();
		// kill everything, start fresh

	__w64 int size() { return hashTableSize; }

	void copyFrom( HashTable &table );
		// Copies all the items from table.
		// Does *NOT* clear first, if you want to
		// start off fresh, call clear() first

	// The hash table  keeps track of what has changed with a 
	// flag for each object.  This can be useful for loading and saving
	// differences, for example in the config system.
	int hasChanged();
	int hasChanged( __w64 int i );
	int hasChanged( char *key );
	void setChanged( __w64 int i );
	void setChanged( char *key );
	void clearChanged( __w64 int i );
	void clearChanged( char *key );
	void clearChangedAll();
};

struct IntTable : public HashTable {
	// This is a hashtable which stores ints as values
	// This prevents extraneous calls to atoi, for example

	__w64 int getInt( __w64 int index ) {
		char *ptr = getVal( index );
		if( ptr ) {
			return *((__w64 int *)ptr);
		}
		return 0;
	}

	__w64 int getInt( char *key ) {
		char *ptr = get( key );
		if( ptr ) {
			return *((__w64 int *)ptr);
		}
		return 0;
	}

//	add del
//	add setVal(i)

	void set( char *key, __w64 int value ) {
		HashTable::set( key, (char *)&value, sizeof(__w64 int) );
	}
};

struct BufferTable : public HashTable /*IntTable*/ {
	// This is used to hold memory buffers, indexed by name.
	// If the btOWN_MEMORY is set, then when you kill or
	// change a key's value, it will deallocate the memory

	int flags;
		#define btOWN_MEMORY (0x01)

	char *get( char *key, __w64 int retEmptyString=0 ) {
		// Returns the pointer to the buffer assigned as 
		// opposed to a pointer to the pointer to the buffer 
		// as would be the case if this we not overloaded
		// Ignore the retEmptyString, not used.
//		return (char *)getInt( key );
			char *ptr = HashTable::get( key );
			if( ptr )
				return *( ( char* *)ptr);
			return NULL;
	}

	virtual void set( char *key, char *value, __w64 int len=-1 ) {
		if( flags & btOWN_MEMORY ) {
//			char *old = (char *)getInt( key );
				char *ptr = HashTable::get( key );
				char *old = NULL;
				if( ptr )
					old = *((char* *)ptr);
				if( old ) {
					delete old;
				}
		}
//		IntTable::set( key, (int)value );
		HashTable::set( key, value, sizeof(char*) );

	}

	BufferTable( int _flags = btOWN_MEMORY ) {
		flags = _flags;
	}
};

#endif


