
// PointerArray.h

#ifndef PointerArrayHPP
#define PointerArrayHPP

#include <vector>

template<class genType>
class TPointerArray
{
	private:
		vector<genType *> PointerArray;
		vector<int>				IsFree;
		vector<long>			CustomType;
		vector<long>			CustomValue;
		
		long PointerArrayDefaultSize;
		long PointerArraySize;
		long NextToAdd;
		
	public:
		static const long kPointerArrayInitSize = 5;
		TPointerArray( long default_size = kPointerArrayInitSize );
		virtual ~TPointerArray();

		void resize( long newSize );
		void add( genType* item );
		void add( genType* item, long customType, long customValue );
		long remove( genType* item );
		
		long isEmpty();
		long isInArray( genType* item );
		genType* getFirst();
		genType* getLast();
		long getSize();
		long getCustomType( genType *item );
		long getCustomValue( genType *item );

		long deleteAndSetFree( genType *item );
		genType* findNextFree();
		genType* findByCustomType( long valueToFind ); 
		genType* findByCustomValue( long valueToFind ); 

		long findNextFreeIndex();
		long findIndexByCustomType( long valueToFind ); 
		long findIndexByCustomValue( long valueToFind ); 

		genType* getNthElement( long elementToFind );
		genType* find( genType* item ); // finds itself
		long findIndex( genType *item ); 
};

template<class genType>
TPointerArray<genType>::TPointerArray( long default_size )
{
	PointerArrayDefaultSize = default_size;
	PointerArraySize = PointerArrayDefaultSize;
	resize( PointerArraySize );
	NextToAdd = 0;
}

template<class genType>
TPointerArray<genType>::~TPointerArray()
{
  
	for (long i = 0; i < NextToAdd; i++) {
		if( PointerArray[i] ) {
			//if( genType != void ){
				delete PointerArray[i];
			//}
      PointerArray[i] = NULL;
		}
	}

	this->resize(0); // actually not needed
}

template<class genType>
long TPointerArray<genType>::remove( genType *item )
{	
	long elementIndex = findIndex( item );
	if ( elementIndex >= 0 ) {
		
		/*
		PointerArray.remove( elementIndex );
		IsFree.remove( elementIndex );
		CustomType.remove( elementIndex );
		CustomValue.remove( elementIndex );
		PointerArraySize--;
		*/
		
		PointerArray[elementIndex] = NULL;
		IsFree[elementIndex] = 1;
		CustomType[elementIndex] = -1;
		CustomValue[elementIndex] = -1;
		
		return elementIndex;
	}
	return -1; // it was not found
}

template<class genType>
void TPointerArray<genType>::resize( long newSize )
{	
	PointerArray.resize(newSize, NULL);
	IsFree.resize(newSize, -1);
	CustomType.resize(newSize, -1);
	CustomValue.resize(newSize, -1);

	PointerArraySize = newSize;
	if( newSize < NextToAdd ) {
		NextToAdd = newSize;
	}
}
 
template<class genType>
long TPointerArray<genType>::deleteAndSetFree( genType *item )
{
	long elementIndex = findIndex( item );
	if ( elementIndex >= 0 ) {
		if( PointerArray[elementIndex] ) {
			delete PointerArray[elementIndex];
      PointerArray[elementIndex] = NULL;
		} else {
      PointerArray[elementIndex] = NULL; // error here!
		}
		IsFree[elementIndex] = 1;
		CustomType[elementIndex] = -1;
		CustomValue[elementIndex] = -1;

		return elementIndex;
	}
	return -1; // it was not found
}

template<class genType>
genType* TPointerArray<genType>::findNextFree()
{
	for (long i = 0; i < NextToAdd; i++) {
		if( IsFree[i] ) {
			return PointerArray[i];
		}
	}
	return NULL; // it was not found
}

template<class genType>
long TPointerArray<genType>::findNextFreeIndex()
{
	for (long i = 0; i < NextToAdd; i++) {
		if( IsFree[i] ) {
			return i;
		}
	}
	return -1; // it was not found
}

template<class genType>
void TPointerArray<genType>::add( genType* item )
{
	TPointerArray<genType>::add( item, -1, -1 );
}

template<class genType>
void TPointerArray<genType>::add( genType* item, long customType, long customValue )
{
	long idx;

	/* // usually new sockets have same address than old
	idx = findIndex( item ); // will not find after NextToAdd
	if( idx >= 0 ) {
		idx = -1; // already added error
	}
	*/ 

	idx = findNextFreeIndex(); // will not find after NextToAdd
	if( idx >= 0 ) {
			PointerArray[idx] = item;	// reuse cleared places
			IsFree[idx] = 0;
			CustomType[idx] = customType;
			CustomValue[idx] = customValue;
			idx++;
	} else {
		if (NextToAdd >= PointerArraySize) {
			// make new bigger prt array, copy old pointers to new array and then delete old
			PointerArraySize += PointerArrayDefaultSize;
			resize( PointerArraySize );
		}
		PointerArray[NextToAdd] = item;
		IsFree[NextToAdd] = 0;
		CustomType[NextToAdd] = customType;
		CustomValue[NextToAdd] = customValue;
		NextToAdd++;
	}
}

template<class genType>
long TPointerArray<genType>::getCustomType( genType *item )
{
	long elementIndex = this->findIndex( item );
	if( elementIndex < 0 ) {
		return -2; // -2 = not found
	}
	
	return CustomType[elementIndex];
}

template<class genType>
long TPointerArray<genType>::getCustomValue( genType *item )
{
	long elementIndex = this->findIndex( item );
	if( elementIndex < 0 ) {
		return -2; // -2 = not found
	}
	
	return CustomValue[elementIndex];
}


template<class genType>
genType *TPointerArray<genType>::find( genType *item ) // finds itself(?), check if exists in list
{
	for (long i = 0; i < NextToAdd; i++) {
		if( PointerArray[i] == item ) {
			return PointerArray[i];
		}
	}
	return NULL;
}

template<class genType>
long TPointerArray<genType>::findIndex( genType *item )
{
	for (long i = 0; i < NextToAdd; i++) {
		if( PointerArray[i] == item ) {
			return i;
		}
	}
	return -1; // it was not found
}
 
template<class genType>
genType *TPointerArray<genType>::findByCustomType( long valueToFind )
{
	for (long i = 0; i < NextToAdd; i++) {
		if( CustomType[i] == valueToFind ) {
			return PointerArray[i];	
		}
	}
	return NULL; // elementToFind was not found
}

template<class genType>
genType *TPointerArray<genType>::findByCustomValue( long valueToFind )
{
	for (long i = 0; i < NextToAdd; i++) {
		if( CustomValue[i] == valueToFind ) {
			return PointerArray[i];	
		}
	}
	return NULL; // elementToFind was not found
}

template<class genType>
long TPointerArray<genType>::findIndexByCustomType( long valueToFind )
{
	for (long i = 0; i < NextToAdd; i++) {
		if( CustomType[i] == valueToFind ) {
			return i;
		}
	}
	return -1; // elementToFind was not found
}

template<class genType>
long TPointerArray<genType>::findIndexByCustomValue( long valueToFind )
{
	for (long i = 0; i < NextToAdd; i++) {
		if( CustomValue[i] == valueToFind ) {
			return i;
		}
	}
	return -1; // elementToFind was not found
}


template<class genType>
long TPointerArray<genType>::isEmpty()
{
	return NextToAdd == 0;
}

template<class genType>
long TPointerArray<genType>::isInArray( genType* item )
{
	return ( this->find( item ) != NULL );
}


template<class genType>
genType* TPointerArray<genType>::getFirst()
{
	if (getSize() == 0)  {
		return NULL;
	}
	return PointerArray[0];
}

template<class genType>
genType* TPointerArray<genType>::getLast()
{
	if (getSize() == 0) {
		return NULL;
	}
	return PointerArray[NextToAdd - 1];
}

template<class genType>
long TPointerArray<genType>::getSize()
{
	return NextToAdd;
}

template<class genType>
genType* TPointerArray<genType>::getNthElement( long elementToFind )
{ // this uses 1-based index, NOT 0-based index !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	if( elementToFind < 1 ) {
		return NULL;
	}
	if( elementToFind > getSize() ) {
		return NULL;
	}
	
	return PointerArray[elementToFind - 1];	
}

#endif