#ifndef _HASHT_H_INCLUDED_
#define _HASHT_H_INCLUDED_
///////////////////////////////////////////////////////////////////////////////
//                                                         
// HashT.h
// -------
// Hash template class definition and implementation
//
// Design and Implementation by Bjoern Lemke               
//
// (C)opyright 2000-2021 Bjoern Lemke
//
// TEMPLATE CLASS
//
// Class: HashT
//
// Description: Template Class for Hash Sets
//
// Status: CLEAN
//
///////////////////////////////////////////////////////////////////////////////

template<class T>
class HashT {
    
 public: 
    HashT(int size, int range);
    HashT(const HashT<T>& hs);
    ~HashT();
    bool isEmpty() const;
    void Empty();
    int numEntry() const;
    int Size() const;
    bool Insert(const T& he);
    bool Remove(const T& he);
    T* Find(const T& he) const;
    T* First() const;
    T* Next() const;
    int getPos() const;
    
    HashT<T>& operator = (const HashT<T>& s);
    
 private:

    int _size;
    int _range;
    T** _hashArray;
    int _idx;
};

template<class T> HashT<T>::HashT(int size, int range)
{
    _range = range;
    _size=size;
    _hashArray = new T*[_size];
    for ( int i=0; i<_size; i++)
	_hashArray[i]=0;
}

template<class T> HashT<T>::HashT(const HashT& hs)
{
    _size = hs._size;
    _range = hs._range;
    _hashArray = new T*[_size];
    for ( int i=0; i<_size; i++)
    {
	if ( hs._hashArray[i] )
	{
	    _hashArray[i] = new T();
	    *_hashArray[i] = *hs._hashArray[i];
	}
	else
	{
	    _hashArray[i] = 0;
	}
    }
}

template<class T> HashT<T>::~HashT()
{
    for ( int i=0; i<_size; i++)
    {
	if ( _hashArray[i] )
	    delete _hashArray[i];
    }
    delete _hashArray;
}

template<class T> int HashT<T>::numEntry() const
{
    int numEntry=0;
    for ( int i=0; i<_size; i++)
    {
	if ( _hashArray[i] )
	{
	    numEntry++;
	}
    }
    return numEntry;
}

template<class T> void HashT<T>::Empty()
{
    for ( int i=0; i<_size; i++)
    {
	if ( _hashArray[i] )
	{
	    delete _hashArray[i];
	    _hashArray[i]=0;
	}
    }
}

template<class T> int HashT<T>::Size() const
{
    return _size;
}

template<class T> bool HashT<T>::Insert(const T& he)
{
    // template class must implement getHashPos method
    int h = he.getHashPos(_size);
    int r = 0;
    while ( _hashArray[h] != 0 && r < _range)
    {
	if ( *_hashArray[h] == he )
	    return false;
	// cout << "Tracing hash .." << endl;
	h = ( h + 1 ) % _size;
	r++;
    }
    if ( r >= _range )
	return false;
    
    _hashArray[h] = new T(he);
    return true;

}

template<class T> bool HashT<T>::Remove(const T& he)
{
    // template class must implement getHashPos method
    int h = he.getHashPos(_size);
    int r = 0;
    while ( r < _range )
    {
	if ( _hashArray[h] != 0 )
	{
	    if ( *_hashArray[h] == he )
	    {
		delete _hashArray[h];
		_hashArray[h]=0;
		return true;
	    }
	}
	h = ( h + 1 ) % _size;
	r++;
    }

    return false;
}

template<class T> T* HashT<T>::Find(const T& he) const
{
    // template class must implement getHashPos method
    int h = he.getHashPos(_size);
    int r = 0;
    while ( _hashArray[h] != 0 && r < _range)
    {
	if ( *_hashArray[h] == he )
	    return _hashArray[h];
	h = ( h + 1 ) % _size;
	r++;
    }
    return 0;
}

template<class T> T* HashT<T>::First() const
{
    ((HashT<T>*)this)->_idx = 0;
    
    while ( _hashArray[_idx] == 0 && _idx < _size)
	((HashT<T>*)this)->_idx++;

    if ( _idx < _size )
	return _hashArray[_idx];
    else
	return 0;
}    

template<class T> T* HashT<T>::Next() const
{
    ((HashT<T>*)this)->_idx++;
    
    while ( _hashArray[_idx] == 0 && _idx < _size)
	((HashT<T>*)this)->_idx++;

    if ( _idx < _size )
	return _hashArray[_idx];
    else
	return 0;
}

template<class T> int HashT<T>::getPos() const
{
    return _idx;
}

template<class T> HashT<T>& HashT<T>::operator=(const HashT<T>& hs)
{
    Empty();
    return (*this);    
}

#endif
