#pragma once

template<class T> class Vector;

void tsf_AddVar(const char *, Vector<signed int> *);
void tsf_AddVar(const char *, Vector<float> *);

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

// This code has been modified to be independent of other TGE code.

#ifndef _TVECTOR_H_
#define _TVECTOR_H_

#include <stdlib.h>

//-----------------------------------------------------------------------------
// Helper definitions for the vector class.

/// Size of memory blocks to allocate at a time for vectors.
#define VectorBlockSize 16

extern bool VectorResize(unsigned int *aSize, unsigned int *aCount, void **arrayPtr, unsigned int newCount, unsigned int elemSize);

// =============================================================================
/// A dynamic array class.
///
/// The vector grows as you insert or append
/// elements.  Insertion is fastest at the end of the array.  Resizing
/// of the array can be avoided by pre-allocating space using the
/// reserve() method.
///
/// <b>***WARNING***</b>
///
/// This template does not initialize, construct or destruct any of
/// it's elements.  This means don't use this template for elements
/// (classes) that need these operations.  This template is intended
/// to be used for simple structures that have no constructors or
/// destructors.
///
/// @nosubgrouping
template<class T>
class Vector
{
protected:
	unsigned int mElementCount;
	unsigned int mArraySize;
	T*  mArray;

	bool  resize(unsigned int);
public:
	Vector(const unsigned int initialSize = 0);
	Vector(const unsigned int initialSize, const char* fileName, const unsigned int lineNum);
	Vector(const char* fileName, const unsigned int lineNum);
	Vector(const Vector&);
	~Vector();

	/// @name STL interface
	/// @{

	typedef T        value_type;
	typedef T&       reference;
	typedef const T& const_reference;

	typedef T*       iterator;
	typedef const T* const_iterator;
	typedef signed int    difference_type;
	typedef unsigned int    size_type;

	Vector<T>& operator=(const Vector<T>& p);

	iterator       begin();
	const_iterator begin() const;
	iterator       end();
	const_iterator end() const;

	signed int size() const;
	bool empty() const;

	void insert(iterator, const T&);
	void erase(iterator);

	T&       front();
	const T& front() const;
	T&       back();
	const T& back() const;

	void push_front(const T&);
	void push_back(const T&);
	void pop_front();
	void pop_back();

	T& operator[](unsigned int);
	const T& operator[](unsigned int) const;

	T& operator[](signed int i)              { return operator[](i); }
	const T& operator[](signed int i ) const { return operator[](i); }

	void reserve(unsigned int);
	unsigned int capacity() const;

	/// @}

	/// @name Extended interface
	/// @{

	unsigned int  memSize() const;
	T*   address() const;
	unsigned int  setSize(unsigned int);
	void increment(unsigned int = 1);
	void decrement(unsigned int = 1);
	void insert(unsigned int);
	void erase(unsigned int);
	void erase_fast(unsigned int);
	void erase_fast(iterator);
	void clear();
	void compact();

	T& first();
	T& last();
	const T& first() const;
	const T& last() const;

	void set(void * addr, unsigned int sz);

	/// Merge another vector into this one.
	///
	/// @author BJW 8/20/97
	void merge(const Vector& p);

	/// @}
};

template<class T> inline Vector<T>::~Vector()
{
	free(mArray);
}

template<class T> inline Vector<T>::Vector(const unsigned int initialSize)
{
	mArray        = 0;
	mElementCount = 0;
	mArraySize    = 0;
	if(initialSize)
		reserve(initialSize);
}

template<class T> inline Vector<T>::Vector(const unsigned int initialSize,
                                           const char* fileName,
                                           const unsigned int   lineNum)
{
	fileName;
	lineNum;

	mArray        = 0;
	mElementCount = 0;
	mArraySize    = 0;
	if(initialSize)
		reserve(initialSize);
}

template<class T> inline Vector<T>::Vector(const char* fileName,
                                           const unsigned int   lineNum)
{
	fileName;
	lineNum;

	mArray        = 0;
	mElementCount = 0;
	mArraySize    = 0;
}

template<class T> inline Vector<T>::Vector(const Vector& p)
{
	mArray = 0;
	resize(p.mElementCount);
	if (p.mElementCount)
		memcpy(mArray,p.mArray,mElementCount * sizeof(value_type));
}

template<class T> inline unsigned int Vector<T>::memSize() const
{
	return capacity() * sizeof(T);
}

template<class T> inline T* Vector<T>::address() const
{
	return mArray;
}

template<class T> inline unsigned int Vector<T>::setSize(unsigned int size)
{
	if (size > mArraySize)
		resize(size);
	else
		mElementCount = size;
	return mElementCount;
}

template<class T> inline void Vector<T>::increment(unsigned int delta)
{
	if ((mElementCount += delta) > mArraySize)
		resize(mElementCount);
}

template<class T> inline void Vector<T>::decrement(unsigned int delta)
{
	if (mElementCount > delta)
		mElementCount -= delta;
	else
		mElementCount = 0;
}

template<class T> inline void Vector<T>::insert(unsigned int index)
{
	// Assert: index >= 0 && index < mElementCount
	increment();
	memmove(&mArray[index + 1],
	                &mArray[index],
	                (mElementCount - index - 1) * sizeof(value_type));
}

template<class T> inline void Vector<T>::erase(unsigned int index)
{
	// Assert: index >= 0 && index < mElementCount
	memmove(&mArray[index],
	                &mArray[index + 1],
	                (mElementCount - index - 1) * sizeof(value_type));
	decrement();
}

template<class T> inline void Vector<T>::erase_fast(unsigned int index)
{
	// CAUTION: this operator does NOT maintain list order
	// Copy the last element into the deleted 'hole' and decrement the
	//   size of the vector.
	// Assert: index >= 0 && index < mElementCount
	if (index < (mElementCount - 1))
		memmove(&mArray[index], &mArray[mElementCount - 1], sizeof(value_type));
	decrement();
}

template<class T> inline T& Vector<T>::first()
{
	return mArray[0];
}

template<class T> inline const T& Vector<T>::first() const
{
	return mArray[0];
}

template<class T> inline T& Vector<T>::last()
{
	return mArray[mElementCount - 1];
}

template<class T> inline const T& Vector<T>::last() const
{
	return mArray[mElementCount - 1];
}

template<class T> inline void Vector<T>::clear()
{
	mElementCount = 0;
}

template<class T> inline void Vector<T>::compact()
{
	resize(mElementCount);
}


//-----------------------------------------------------------------------------

template<class T> inline Vector<T>& Vector<T>::operator=(const Vector<T>& p)
{
	resize(p.mElementCount);
	if (p.mElementCount)
		memcpy(mArray,p.mArray,mElementCount * sizeof(value_type));

	return *this;
}

template<class T> inline typename Vector<T>::iterator Vector<T>::begin()
{
	return mArray;
}

template<class T> inline typename Vector<T>::const_iterator Vector<T>::begin() const
{
	return mArray;
}

template<class T> inline typename Vector<T>::iterator Vector<T>::end()
{
	return mArray + mElementCount;
}

template<class T> inline typename Vector<T>::const_iterator Vector<T>::end() const
{
	return mArray + mElementCount;
}

template<class T> inline signed int Vector<T>::size() const
{
	return (signed int)mElementCount;
}

template<class T> inline bool Vector<T>::empty() const
{
	return (mElementCount == 0);
}

template<class T> inline void Vector<T>::insert(iterator p,const T& x)
{
	unsigned int index = (unsigned int) (p - mArray);
	insert(index);
	mArray[index] = x;
}

template<class T> inline void Vector<T>::erase(iterator q)
{
	erase((unsigned int)(q - mArray));
}

template<class T> inline void Vector<T>::erase_fast(iterator q)
{
	erase_fast((unsigned int)(q - mArray));
}

template<class T> inline T& Vector<T>::front()
{
	return *begin();
}

template<class T> inline const T& Vector<T>::front() const
{
	return *begin();
}

template<class T> inline T& Vector<T>::back()
{
	return *end();
}

template<class T> inline const T& Vector<T>::back() const
{
	return *end();
}

template<class T> inline void Vector<T>::push_front(const T& x)
{
	insert(0);
	mArray[0] = x;
}

template<class T> inline void Vector<T>::push_back(const T& x)
{
	increment();
	mArray[mElementCount - 1] = x;
}

template<class T> inline void Vector<T>::pop_front()
{
	erase((unsigned int)(0));
}

template<class T> inline void Vector<T>::pop_back()
{
	decrement();
}

template<class T> inline T& Vector<T>::operator[](unsigned int index)
{
	//AssertFatal((index < mElementCount), "Index too large.");
	return mArray[index];
}

template<class T> inline const T& Vector<T>::operator[](unsigned int index) const
{
	//AssertFatal((index < mElementCount), "Index too large.");
	return mArray[index];
}

template<class T> inline void Vector<T>::reserve(unsigned int size)
{
	if (size > mArraySize) {
		unsigned int ec = mElementCount;
		if (resize(size))
			mElementCount = ec;
	}
}

template<class T> inline unsigned int Vector<T>::capacity() const
{
	return mArraySize;
}

template<class T> inline void Vector<T>::set(void * addr, unsigned int sz)
{
	setSize(sz);
	if (addr)
		memcpy(address(),addr,sz*sizeof(T));
}

//-----------------------------------------------------------------------------

template<class T> inline bool Vector<T>::resize(unsigned int ecount)
{
	return VectorResize(&mArraySize, &mElementCount, (void**) &mArray, ecount, sizeof(T));
}

// BJW 8/20/97
// code to merge a vector into this one
template<class T> inline void Vector<T>::merge(const Vector& p)
{
	if (p.size()) {
		signed int oldsize = size();
		resize(oldsize + p.size());
		memcpy( &mArray[oldsize], p.address(), p.size() * sizeof(T) );
	}
}

//-----------------------------------------------------------------------------
/// Template for vectors of pointers.
template <class T>
class VectorPtr : public Vector<void*>
{
	/// @deprecated Disallowed.
	VectorPtr(const VectorPtr&);  // Disallowed

public:
	VectorPtr();
	VectorPtr(const char* fileName, const unsigned int lineNum);

	/// @name STL interface
	/// @{

	typedef T        value_type;
	typedef T&       reference;
	typedef const T& const_reference;

	typedef T*       iterator;
	typedef const T* const_iterator;
	typedef unsigned int      difference_type;
	typedef unsigned int      size_type;

	iterator       begin();
	const_iterator begin() const;
	iterator       end();
	const_iterator end() const;

	void insert(iterator,const T&);
	void erase(iterator);

	T&       front();
	const T& front() const;
	T&       back();
	const T& back() const;
	void   push_front(const T&);
	void   push_back(const T&);

	T&       operator[](unsigned int);
	const T& operator[](unsigned int) const;

	/// @}

	/// @name Extended interface
	/// @{

	typedef Vector<void*> Parent;
	T&       first();
	T&       last();
	const T& first() const;
	const T& last() const;
	void erase_fast(unsigned int);
	void erase_fast(iterator);

	/// @}
};


//-----------------------------------------------------------------------------
template<class T> inline VectorPtr<T>::VectorPtr()
{
	//
}

template<class T> inline VectorPtr<T>::VectorPtr(const char* fileName,
                                                 const unsigned int   lineNum)
   : Vector<void*>(fileName, lineNum)
{
	//
}

template<class T> inline T& VectorPtr<T>::first()
{
	return (T&)Parent::first();
}

template<class T> inline const T& VectorPtr<T>::first() const
{
	return (const T)Parent::first();
}

template<class T> inline T& VectorPtr<T>::last()
{
	return (T&)Parent::last();
}

template<class T> inline const T& VectorPtr<T>::last() const
{
	return (const T&)Parent::last();
}

template<class T> inline typename VectorPtr<T>::iterator VectorPtr<T>::begin()
{
	return (iterator)Parent::begin();
}

template<class T> inline typename VectorPtr<T>::const_iterator VectorPtr<T>::begin() const
{
	return (const_iterator)Parent::begin();
}

template<class T> inline typename VectorPtr<T>::iterator VectorPtr<T>::end()
{
	return (iterator)Parent::end();
}

template<class T> inline typename VectorPtr<T>::const_iterator VectorPtr<T>::end() const
{
	return (const_iterator)Parent::end();
}

template<class T> inline void VectorPtr<T>::insert(iterator i,const T& x)
{
	Parent::insert( (Parent::iterator)i, (Parent::reference)x );
}

template<class T> inline void VectorPtr<T>::erase(iterator i)
{
	Parent::erase( (Parent::iterator)i );
}

template<class T> inline void VectorPtr<T>::erase_fast(unsigned int index)
{
	// CAUTION: this operator does maintain list order
	// Copy the last element into the deleted 'hole' and decrement the
	//   size of the vector.
	// Assert: index >= 0 && index < mElementCount
	if (index < (mElementCount - 1))
		mArray[index] = mArray[mElementCount - 1];
	decrement();
}

template<class T> inline void VectorPtr<T>::erase_fast(iterator i)
{
	erase_fast((unsigned int)(i - iterator(mArray)));
}

template<class T> inline T& VectorPtr<T>::front()
{
	return *begin();
}

template<class T> inline const T& VectorPtr<T>::front() const
{
	return *begin();
}

template<class T> inline T& VectorPtr<T>::back()
{
	return *end();
}

template<class T> inline const T& VectorPtr<T>::back() const
{
	return *end();
}

template<class T> inline void VectorPtr<T>::push_front(const T& x)
{
	Parent::push_front((Parent::const_reference)x);
}

template<class T> inline void VectorPtr<T>::push_back(const T& x)
{
	Parent::push_back((Parent::const_reference)x);
}

template<class T> inline T& VectorPtr<T>::operator[](unsigned int index)
{
	return (T&)Parent::operator[](index);
}

template<class T> inline const T& VectorPtr<T>::operator[](unsigned int index) const
{
	return (const T&)Parent::operator[](index);
}

#endif //_TVECTOR_H_
