/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@falcon.mercer.peachnet.edu 
MUD++ development mailing list    mudpp-list@spice.com
------------------------------------------------------------------------------
indexable.h
*/

#ifndef INDEXABLE_H
#define INDEXABLE_H
#include "string.h"
#include "index.h"
#include "llist.h"


template< class T >
class Indexable
{
	private:
		Index index;
		T * obj;

	public:
		Indexable()
		: obj(0)
		{
		}

		Indexable( const Index & x, T * y )
		:	index(x), obj(y)
		{
		}

		virtual ~Indexable()
		{
			if( obj )
				delete obj;
		}

		T * peek() const { return obj; }
		T * getObj() const { return obj; }
		void setObj( T * pObj )
		{
			if( pObj != obj )
			{
				if( obj )
					delete obj;
				obj = pObj;
			}
 		}

		const Index	& getIndex() const { return index; } 
		void setIndex( const Index & x ) { index = x; } 
		const String getScope() const { return index.getScope(); }
		const String getKey() const { return index.getKey(); }
		void setScope( const String & x ) { index.setScope( x ); } 
		void setKey( const String & x ) { index.setKey( x ); } 
};


#define HASH_KEY	64

// An array of LList objects.
template< class T >
class IndexList
{
	private:
		// Don't remove spaces in template defs. C++ will barf if you
		// write LList<Indexable< T >>, and according to the spec its wrong.

		LList< Indexable< T > > table[ HASH_KEY ];
		int ihash;

	protected:

	public:
		IndexList()
		:	ihash(0)
		{
		}

		void addIndex( const Index &, T * );

		int getHashKey( const String & );
		int getHashKey( const char * );
		        
		T *lookup( const Index & );
		T *lookup( const String & );
		T *lookup( const char * );
        
		void removeIndex( const Index &  );
		void removeIndex( const String & );
		void removeIndex( const char * );

		// List like iteration interface
		void reset() const;
		void clr(); // Destroys all nodes within index
		void setScope( const String & );
		const IndexList & next() const;
		T * peek() const;
		const Index & getIndex();
};


template< class T >
int IndexList< T >::getHashKey( const String & str )
{
	int key = (int)str[0];

	if( str[0] )
		key += (int)str[1]; // be it null or not

	return key % HASH_KEY;
}


template< class T >
int IndexList< T >::getHashKey( const char * str )
{
	int key = (int)str[0];

	if( str[0] )
		key += (int)str[1]; // be it null or not

	return key % HASH_KEY;
}


template< class T >
void IndexList< T >::reset() const
{
	for( int i = 0; i < HASH_KEY; i++ )
	{
		table[ i ].reset();
		if( table[ i ].peek() )
		{
			// Override const member
			const_cast< IndexList< T > * >(this)->ihash = i;
			return;
		}
	}
}


template< class T >
void IndexList< T >::setScope( const String & x )
{
	ihash = 0;
	Indexable< T > *ptr;

	for( ihash = 0; ihash < HASH_KEY; ihash++ )
	{
		table[ ihash ].reset();
		while( ( ptr = table[ ihash ].peek() ) )
		{
			table[ ihash ].next();

			ptr->setScope( x );
		}
	}
}

template< class T >
const IndexList< T > & IndexList< T >::next() const
{
	int i;

	table[ ihash ].next();
	if( !table[ ihash ].peek() )
	{
		if( ihash < HASH_KEY - 1 )
		{
			for( i = ihash + 1; i < HASH_KEY; i++ )
			{
				table[ i ].reset();
				if( table[ i ].peek() )
				{
					const_cast< IndexList * >(this)->ihash = i;
					return *this;
				}
			}
		}
	}

	return *this;
}


template < class T >
T * IndexList< T >::peek() const
{
	Indexable< T > *x = table[ ihash ].peek();
	if( x )
		return x->peek();

	return 0;
}


template < class T >
const Index & IndexList< T >::getIndex()
{
	static Index empty;

	Indexable< T > *x = table[ ihash ].peek();
	if( x )
		return x->getIndex();
	return empty;
}


template < class T >
void IndexList< T >::clr()
{
	Indexable< T > *ptr;

	for( ihash = 0; ihash < HASH_KEY; ihash++ )
	{
		table[ ihash ].reset();
		while( ( ptr = table[ ihash ].remove() ) )
			delete ptr;
	}
}


// For now, the scope portion of the index isn't used
// inside the IndexList object since all objects in that
// list are of same scope. This can me changed easily.

template < class T >
T * IndexList< T >::lookup( const Index & x )
{
	return lookup( x.getKey() );
}


template < class T >
T * IndexList< T >::lookup( const String & x )
{
	return lookup( x.chars() );
}


// Dont want to change the internal state of container so create
// tlist to do iterating. 
template < class T >
T * IndexList< T >::lookup( const char * x )
{
	Indexable< T > *ptr;

	LList< Indexable< T > > tlist = table[ getHashKey( x ) ];
	tlist.reset();

	while( ( ptr = tlist.peek() ) )
	{
		tlist.next();

		if( ptr->getKey() == x )
		{
			return ptr->getObj(); 
		}
	}

	return 0;
}


template < class T >
void IndexList< T >::addIndex( const Index & x, T * y )
{
	Indexable< T > *ptr = new Indexable< T >( x, y );

	int i = getHashKey( ptr->getKey() );
	table[ i ].addTop( ptr );
}


template < class T >
void IndexList< T >::removeIndex( const Index & x )
{
	removeIndex( x.getKey().chars() );
}

template < class T >
void IndexList< T >::removeIndex( const String & x )
{
	removeIndex( x.chars() );
}

template < class T >
void IndexList< T >::removeIndex( const char * )
{
}

#endif