#pragma once

//===========================================================================//
// File:	 Hash.h															 //
// Project:  gosGml														     //
// Contents:																 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 6/10/00   DP     Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//


//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//BIG FAT WARNING: at this point U can only be a char*, int, or unsigned int.                                                               //
//If you know of a better way to do this, I'm listening! These overloaded functions are not my ideal solution. Contact a-dplay@microsoft.com//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


unsigned long EHash(const unsigned char *name, int TableSize);
unsigned long EHash(unsigned int Z, int TableSize);

template<class T, class U> class NameValuePair
{
	public:
		NameValuePair(U iKey, T data, NameValuePair* next=0);
		NameValuePair(U iKey);
		~NameValuePair();
		NameValuePair(NameValuePair& Prot);
		NameValuePair& operator= (NameValuePair const &);
		KillTree();
		NameValuePair* Next;
		U IKey;
		T Data;
	private:
		void DelIKey(char* x);
		void DelIKey(int x);
		void DelIKey(DWORD x);
		void DelIKey(unsigned int x);
		void CpIkey(char* x);
		void CpIkey(int x);
		void CpIkey(DWORD x);
		void CpIkey(unsigned int x);
};

template<class T, class U> class Hash //U is the data type of the value you want to look up, T is the data type that you look U up with
{
	public:
		// http://www.utm.edu/research/primes/lists/small/1000.txt for a better list of small prime numbers
		Hash(int MaxNumItems); //23 59 101 179 317 443 709 983 4051 8081
		~Hash();
		void AddHash(NameValuePair<T,U>* Item);
		T FindHit(U Search);
		void Clear();
		void RemoveItem(NameValuePair<T,U>* Item); //not very efficient. avoid using this. Removes all items with matching IKey

	private:
		int TableSize;
		NameValuePair<T,U>** Items;
		Hash(); //call me not
		Hash(Hash&);//don't call this
		Hash& operator= (Hash const &); //don't call the assignment operator
		NameValuePair<T,U>* FindFreeSlot(unsigned long Key);
		unsigned long EHash(const unsigned char *name, int TableSize);
		unsigned long EHash(const char *name, int TableSize);
		unsigned long EHash(unsigned int Z, int TableSize);
		int ECmp(char*,char*);
		int ECmp(unsigned char*,unsigned char*);
		bool ECmp(int,int);
};



template<class T, class U> NameValuePair<T,U>::NameValuePair(U iKey, T data, NameValuePair* next)
:Next(next),IKey(iKey),Data(data)
{
}

template<class T, class U> NameValuePair<T,U>::NameValuePair(U iKey)
:Next(NULL),IKey(iKey)
{
}

template<class T, class U> NameValuePair<T,U>::~NameValuePair()
{
	if(Next) delete Next;
	DelIKey(IKey);
}

template<class T, class U> NameValuePair<T,U>& NameValuePair<T,U>::operator= (const NameValuePair& rhs)
{
	if(this == &rhs)
		return *this;
	if(this->IKey)
		DelIKey(this->IKey);
	if(this->Next)
		delete this->Next;

	if(rhs.IKey)
		CpIkey(rhs.IKey);
	Next=rhs.Next;
	Data=rhs.Data;

	return *this;
}

template<class T, class U> NameValuePair<T,U>::NameValuePair(NameValuePair& Prot)
{
	if(Prot.IKey)
	{
		IKey=new char[mstrlen(Prot.IKey)];
		mstrcpy(IKey,Prot.IKey);
	}
	Data=Prot.Data;
	Next=Prot.Next;
}

template<class T, class U> NameValuePair<T,U>::KillTree()
{
	if(Next) delete Next;
}

template<class T, class U> void NameValuePair<T,U>::DelIKey(char* x)
{
	x;
	delete[] IKey;
}

template<class T, class U> void NameValuePair<T,U>::DelIKey(int x)
{x;}

template<class T, class U> void NameValuePair<T,U>::DelIKey(DWORD x)
{x;}
 
template<class T, class U> void NameValuePair<T,U>::DelIKey(unsigned int x)
{x;}

template<class T, class U> void NameValuePair<T,U>::CpIkey(char* x)
{
	IKey=new char[mstrlen(x)+1];
	mstrcpy(IKey,x);
}

template<class T, class U> void NameValuePair<T,U>::CpIkey(int x)
{IKey=x;}

template<class T, class U> void NameValuePair<T,U>::CpIkey(DWORD x)
{IKey=x;}

template<class T, class U> void NameValuePair<T,U>::CpIkey(unsigned int x)
{IKey=x;}

template<class T, class U> Hash<T,U>::Hash(int MaxNumItems)
:TableSize(MaxNumItems)
{
	Items=new NameValuePair<T,U>*[TableSize];
	memset(Items,0,TableSize<<2);
}

template<class T, class U> Hash<T,U>::~Hash()
{
	Clear();
	delete[] Items;
}

template<class T, class U> void Hash<T,U>::AddHash(NameValuePair<T,U>* Item)
{
	unsigned long Key=EHash((U)Item->IKey, TableSize);
	NameValuePair<T,U>* Slot=FindFreeSlot(Key);
	*Slot=*Item;
}

template<class T, class U> T Hash<T,U>::FindHit(U Search)
{
	unsigned long Key=EHash((U)Search, TableSize);
	NameValuePair<T,U>* NVPP=Items[Key];
	if(!NVPP) return 0;
	do
	{
		if(ECmp(NVPP->IKey,Search))
			NVPP=NVPP->Next;
		else
			return NVPP->Data;
	}
	while(NVPP);
	return 0;
}

template<class T, class U> void Hash<T,U>::Clear()
{
	for(int i=0;i<TableSize;i++)
		if(Items[i])
		{
			delete Items[i];
			Items[i]=0;
		}
}

template<class T, class U> NameValuePair<T,U>* Hash<T,U>::FindFreeSlot(unsigned long Key)
{
	NameValuePair<T,U>* NVPP=Items[Key];
	if(!NVPP)
	{
		Items[Key]=new NameValuePair<T,U>(NULL);
		return Items[Key];
	}
	while(NVPP->IKey!=NULL)
	{
		if(NVPP->Next==NULL)
			NVPP->Next=new NameValuePair<T,U>(NULL);
		NVPP=NVPP->Next;
	}
	return NVPP;
}

template<class T, class U> void Hash<T,U>::RemoveItem(NameValuePair<T,U>* Item) 
{
	unsigned long Key=EHash((unsigned char*)Item->IKey, TableSize);
	NameValuePair<T,U>* NVPP=Items[Key];
	NameValuePair<T,U>* NVPP2=NVPP;
	NameValuePair<T,U>* Victim;
	while(NVPP)
	{
		if(ECmp(NVPP->IKey,Item->IKey))
		{
			NVPP2=NVPP;
			NVPP=NVPP->Next;
		}
		else
		{
			Victim=NVPP;
			NVPP=NVPP->Next;
			if(NVPP==Items[Key])
				Items[Key]=NVPP;
			else
				NVPP2->Next=NVPP;
			delete Victim;
		}
	}
}

#pragma warning( disable: 4706 )
template<class T, class U> unsigned long Hash<T,U>::EHash(const unsigned char *name, int TableSize)
{//ElfHash
    unsigned long   h = 0, g;
    while ( *name )
    {
        h = ( h << 4 ) + *name++;
        if ( g = h & 0xF0000000 )
            h ^= g >> 24;
        h &= ~g;
    }
    return h%TableSize;
}

template<class T, class U> unsigned long Hash<T,U>::EHash(const char *name, int TableSize)
{//ElfHash
    unsigned long   h = 0, g;
    while ( *name )
    {
        h = ( h << 4 ) + *name++;
        if ( g = h & 0xF0000000 )
            h ^= g >> 24;
        h &= ~g;
    }
    return h%TableSize;
}

template<class T, class U> unsigned long Hash<T,U>::EHash(unsigned int Z, int TableSize)
{
    return Z%TableSize;
}
#pragma warning( default: 4706 )


template<class T, class U> int Hash<T,U>::ECmp(char* a,char* b)
{
	return mstrcmp(a,b);
}

template<class T, class U> int Hash<T,U>::ECmp(unsigned char* a,unsigned char* b)
{
	return mstrcmp(a,b);
}

template<class T, class U> bool Hash<T,U>::ECmp(int a,int b)
{
	return a!=b;
}
