//-----------------------------------------------------------------------------
//
//  $Logfile:: /Quake 2 Engine/Sin/code/game/datamap.h                        $
// $Revision:: 2                                                              $
//   $Author:: Jimdose                                                        $
//     $Date:: 8/31/98 5:40p                                                  $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/datamap.h                             $
//
// 2     8/31/98 5:40p Jimdose
// Created file.  Still need to test it.
//
// 1     8/31/98 5:40p Jimdose
//
// DESCRIPTION:
// Template class for mapping values of one data type to another.
//

#ifndef __DATAMAP_H__
#define __DATAMAP_H__

#include "g_local.h"
#include <stdlib.h>

template< class Key, class Value >
class DataMap
{
private:
	Key**       keyarray;
	Value**     valuearray;
	int numobjects;
	int maxobjects;

public:
	DataMap();
	DataMap( DataMap<Key, Value>& map );
	~DataMap<Key, Value>();
	void        FreeObjectList( void );
	void        ClearObjectList( void );
	int     NumObjects( void );
	void        Resize( int maxelements );
	Value&  operator[]( Key key );
	int     SetValue( Key key, Value obj );
	void        SetValueAt( int index, Value& obj );
	int     AddKey( Key& key );
	int     AddKeyPair( Key& key, Value& value );
	int     FindKey( Key& key );
	void        KeyInList( Key& key );
	Value&  ValueAt( int index );
	Key&        KeyAt( int index );
	void        RemoveKeyAt( int index );
	void        RemoveKey( Key& key );
};

template< class Key, class Value>DataMap<Key, Value>::DataMap()
{
	keyarray = NULL;
	valuearray = NULL;
	numobjects = 0;
	maxobjects = 0;
}

template< class Key, class Value>DataMap<Key, Value>::DataMap( DataMap<Key, Value>& map )
{
	numobjects = 0;
	maxobjects = 0;
	keyarray = NULL;
	valuearray = NULL;

	Resize( map.maxobjects );
	for( i = 0; i < map.numobjects; i++ )
	{
		AddKeyPair( map.KeyAt( i ), map.ValueAt( i ) );
	}
}

template< class Key, class Value>
DataMap<Key, Value>::~DataMap<Key, Value>()
{
	FreeObjectList();
}

template< class Key, class Value>
void DataMap<Key, Value>::FreeObjectList( void )
{
	if( keyarray )
	{
		ClearObjectList();

		delete[] keyarray;
		delete[] valuearray;
	}

	keyarray = NULL;
	valuearray = NULL;
	numobjects = 0;
	maxobjects = 0;
}

template< class Key, class Value>
void DataMap<Key, Value>::ClearObjectList( void )
{
	// only delete the list if we have objects in it
	if( keyarray && numobjects )
	{
		for( i = 0; i < numobjects; i++ )
		{
			delete keyarray[ i ];
			delete valuearray[ i ];
		}

		memset( keyarray, 0, maxobjects * sizeof( Key* ) );
		memset( valuearray, 0, maxobjects * sizeof( Value* ) );

		numobjects = 0;
	}
}

template< class Key, class Value>
int DataMap<Key, Value>::NumObjects( void )
{
	return numobjects;
}

template< class Key, class Value>
void DataMap<Key, Value>::Resize( int maxelements )
{
	Key*    keytemp;
	Value*  valuetemp;

	assert( maxelements > 0 );

	if( maxelements <= 0 )
	{
		FreeObjectList();
		return;
	}

	if( !keyarray )
	{
		maxobjects = maxelements;

		keyarray = new Key[ maxobjects ];
		memset( keyarray, 0, maxobjects * sizeof( Key* ) );

		valuearray = new Value[ maxobjects ];
		memset( valuearray, 0, maxobjects * sizeof( Value* ) );
	}
	else
	{
		keytemp     = keyarray;
		valuetemp   = valuearray;

		maxobjects  = maxelements;
		if( maxobjects < numobjects )
		{
			maxobjects = numobjects;
		}

		keyarray        = new Key[ maxobjects ];
		valuearray  = new Value[ maxobjects ];

		memcpy( keyarray, keytemp, sizeof( Key* ) * maxobjects );
		memcpy( valuearray, valuetemp, sizeof( Value* ) * maxobjects );

		delete[] keytemp;
		delete[] valuetemp;
	}
}

template< class Key, class Value>
inline Value& DataMap<Key, Value>::operator[]( Key key )
{
	int index;

	index = FindKey( key );
	if( index == -1 )
	{
		index = AddKey( key );
	}

	assert( ( index >= 0 ) && ( index < numobjects ) );
	assert( valuearray );

	return *valuearray[ index ];
}

template< class Key, class Value>
inline int DataMap<Key, Value>::SetValue( Key key, Value value )
{
	int index;

	index = FindKey( key );
	if( index == -1 )
	{
		index = AddKey( key );
	}

	assert( ( index >= 0 ) && ( index < numobjects ) );
	assert( valuearray );

	*valuearray[ index ] = value;

	return index;
}

template< class Key, class Value>
void DataMap<Key, Value>::SetValueAt( int index, Value& obj )
{
	if( ( index < 0 ) || ( index >= numobjects ) )
	{
		gi.error( "DataMap::SetValueAt : index out of range" );
	}

	assert( valuearray );

	*valuearray[ index ] = obj;
}

template< class Key, class Value>
int DataMap<Key, Value>::AddKey( Key& key )
{
	int index;

	if( !keyarray )
	{
		Resize( 10 );
	}

	if( numobjects == maxobjects )
	{
		Resize( maxobjects * 2 );
	}

	index = numobjects;
	numobjects++;

	keyarray[ index ]       = new Key;
	valuearray[ index ] = new Value;
	*keyarray[ index ]  = key;

	return index;
}

template< class Key, class Value>
int DataMap<Key, Value>::AddKeyPair( Key& key, Value& value )
{
	int index;

	if( !keyarray )
	{
		Resize( 10 );
	}

	if( numobjects == maxobjects )
	{
		Resize( maxobjects * 2 );
	}

	index = numobjects;
	numobjects++;

	keyarray[ index ]       = new Key;
	valuearray[ index ] = new Value;
	*keyarray[ index ]  = key;
	*valuearray[ index ]    = value;

	return index;
}

template< class Key, class Value>
int DataMap<Key, Value>::FindKey( Key& key )
{
	int i;

	for( i = 0; i < numobjects; i++ )
	{
		if( *keyarray[ i ] == key )
		{
			return i;
		}
	}

	return -1;
}

template< class Key, class Value>
void DataMap<Key, Value>::KeyInList( Key& key )
{
	if( FindKey( key ) == -1 )
	{
		return false;
	}

	return true;
}

template< class Key, class Value>
Value& DataMap<Key, Value>::ValueAt( int index )
{
	if( ( index < 0 ) || ( index >= numobjects ) )
	{
		gi.error( "DataMap::ValueAt : index out of range" );
	}

	return *valuearray[ index ];
}

template< class Key, class Value>
Key& DataMap<Key, Value>::KeyAt( int index )
{
	if( ( index < 0 ) || ( index >= numobjects ) )
	{
		gi.error( "DataMap::KeyAt : index out of range" );
	}

	return *keyarray[ index ];
}

template< class Key, class Value>
void DataMap<Key, Value>::RemoveKeyAt( int index )
{
	int i;

	if( !keyarray )
	{
		gi.dprintf( "DataMap::RemoveKeyAt : Empty list" );
		return;
	}

	if( ( index < 0 ) || ( index >= numobjects ) )
	{
		gi.error( "DataMap::RemoveKeyAt : index out of range" );
		return;
	}

	delete keyarray[ index ];
	delete valuearray[ index ];

	for( i = index; i < numobjects; i++ )
	{
		keyarray[ i ]   = keyarray[ i + 1 ];
		valuearray[ i ] = valuearray[ i + 1 ];
	}

	numobjects--;
	keyarray[ numobjects ] = NULL;
	valuearray[ numobjects ] = NULL;
}

template< class Key, class Value>
void DataMap<Key, Value>::RemoveKey( Key& key )
{
	int index;

	index = FindKey( key );
	if( index == -1 )
	{
		gi.dprintf( "DataMap::RemoveKey : Object not in list" );
		return;
	}

	RemoveKeyAt( index );
}

#endif /* datamap.h */
