/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2006 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef _GEDYNAMICARRAY_H_
#define _GEDYNAMICARRAY_H_

#include "c4d.h"
#include "ge_math.h"
#include "c4d_memory.h"

#if defined __LINUX || defined __MAC
	// Default placement versions of operator new.
	inline void* operator new(size_t, void* __p) { return __p; }
	inline void* operator new[](size_t, void* __p) { return __p; }
	
	// Default placement versions of operator delete.
	inline void  operator delete  (void*, void*) { }
	inline void  operator delete[](void*, void*) { }
#else
	#include <new.h>
#endif

#include <string.h>

#define DATYPE_CHAR			-1
#define DATYPE_UCHAR		-2
#define DATYPE_WORD			-3
#define DATYPE_UWORD		-4
#define DATYPE_LONG			-5
#define DATYPE_ULONG		-6
#define DATYPE_REAL			-7
#define DATYPE_LREAL		-8
#define DATYPE_BOOL			-9
#define DATYPE_TIME			-10
#define DATYPE_VECTOR		-11
#define DATYPE_LVECTOR	-12
#define DATYPE_MATRIX		-13
#define DATYPE_LMATRIX	-14
#define DATYPE_STRING		-15
#define DATYPE_FILENAME -16
#define DATYPE_LLONG		-17

//dynamic array template
template<class TYPE> class GeDynamicArray
{
protected:
	TYPE*									ptr;
	TYPE*									l_ptr;

	LONG									l_cnt;
	LONG									totcnt;
	LONG									blocksize;
public:
	GeDynamicArray();
	GeDynamicArray(LONG size);
	GeDynamicArray(LONG size, LONG block);
	~GeDynamicArray(void);

	typedef void	GeDynamicArrayCallback(LONG index, TYPE *value, void *data);
	LONG	count;

	TYPE*					Release(void);
	void					Free(void);
	GeDynamicArray<TYPE> &operator =(GeDynamicArray<TYPE> &t);
	GeDynamicArray<TYPE> &operator =(TYPE *t);
	GeDynamicArray<TYPE> &operator =(const TYPE *t);
	friend	Bool operator !(const GeDynamicArray<TYPE> &t) { return t.count == 0; }
	operator TYPE * ()											{	return l_ptr;	}
	TYPE & operator[]	( LONG i )						{	return l_ptr[i];	}
#ifndef __LINUX
	TYPE & operator[] ( int i )							{	return operator[]((LONG) i);	}
#endif
	TYPE & operator[] ( unsigned i )				{	return operator[]((LONG) i);	}
	TYPE * const *operator &()							{	return &l_ptr;	}
	LONG					GetCount(void)						{ return count; }
	void					SetBlockSize(LONG size);
	LONG					GetBlockSize(void)				{ return blocksize; }
	Bool					Read(HyperFile *hf, GeDynamicArray<LONG> &typelist);
	Bool					Write(HyperFile *hf, GeDynamicArray<LONG> &typelist);
	void					DoToAll(GeDynamicArrayCallback *callback, void *data);
	void					DoToSome(GeDynamicArrayCallback *callback, void *data, LONG do_start, LONG do_end);
	void					DoToSearch(GeDynamicArrayCallback *callback, void *data, TYPE p);
	//Sets the size without actually resizing the data (be careful)
	void					SetDummySize(LONG size)		{ count = totcnt = size; }
	Bool					ReScopeNC(LONG cnt);
	Bool					ReScope(LONG cnt);
	Bool					ReSizeNC(LONG cnt);
	Bool					ReSize(LONG cnt);
	Bool					ReSize(LONG c_from, LONG c_to);
	inline void		Fill(LONG c_from, LONG c_to, TYPE t);
	inline void		Fill(TYPE t);
	Bool					Insert(TYPE p, LONG index);
	Bool					Insert(const TYPE *p, LONG index, LONG cnt);
	Bool					MergeIn(GeDynamicArray<TYPE>&p,LONG index);
	Bool					InsertSpace(LONG index, LONG ammount, Bool clear = TRUE, Bool makenew = TRUE);
	inline Bool		Push(TYPE p);
	Bool					Remove(LONG index, LONG ammount = 1);
	inline void		RemoveAll(TYPE p);
	void					Pop(void);
	inline LONG		Find(TYPE p);
	inline LONG		Find(TYPE p, LONG index);
	void					Shift(LONG index, LONG cnt);
	void					ShiftBlock(LONG b_from, LONG b_to, LONG ammount);
};

template<class TYPE> GeDynamicArray<TYPE>::GeDynamicArray(void)
{
	ptr = NULL;
	blocksize = 4;
	Free();
}

template<class TYPE> GeDynamicArray<TYPE>::GeDynamicArray(LONG size) 
{
	ptr = NULL;
	blocksize = 4;
	Free();
	ReScope(size); 
}

template<class TYPE> GeDynamicArray<TYPE>::GeDynamicArray(LONG size, LONG block) 
{ 
	ptr = NULL;
	blocksize = block; 
	Free();
	ReScope(size); 
}

template<class TYPE> GeDynamicArray<TYPE>::~GeDynamicArray(void)
{
	Free();
}

template<class TYPE> TYPE* GeDynamicArray<TYPE>::Release(void)
{ 
	memmove(ptr,l_ptr,sizeof(TYPE)*count);
	blocksize = 1;
	LONG cnt = count;
	count += l_cnt;
	l_ptr = ptr;
	l_cnt = 0;
	ReSizeNC(cnt);
	TYPE	*tmp = ptr;
	ptr = NULL; 
	l_ptr = NULL;
	totcnt = 0; 
	count = 0; 
	l_cnt = 0;
	return tmp;
}

template<class TYPE> void GeDynamicArray<TYPE>::Free(void)
{ 
	if (ptr) 
	{
		LONG i=0;
		TYPE *buf=l_ptr;

		for (i=0;i<count;i++,buf++) buf->~TYPE();

		GeFree(ptr);
	}
	ptr = NULL;
	l_ptr = NULL;
	count = 0;
	totcnt = 0;
	l_cnt = 0;
}

template<class TYPE> GeDynamicArray<TYPE>& GeDynamicArray<TYPE>::operator =(GeDynamicArray<TYPE> &t)
{
	Free();
	SetBlockSize(t.GetBlockSize());
	if (!ReScopeNC(t.count)) return *this;

	LONG	i = 0;

	TYPE	*pbuf = l_ptr;
	TYPE	*tbuf = t.l_ptr;
	for (i = 0; i < count; i++, pbuf++, tbuf++) *pbuf = *tbuf;

	return *this;
}

template<class TYPE> GeDynamicArray<TYPE>& GeDynamicArray<TYPE>::operator =(TYPE *t) 
{ 
	Free(); 
	ptr = t; 
	l_ptr = ptr;
	count = sizeof(*ptr) / sizeof(TYPE); 
	totcnt = count; 
	return *this; 
}

template<class TYPE> GeDynamicArray<TYPE>& GeDynamicArray<TYPE>::operator =(const TYPE *t)
{
	Free();
	LONG	cnt = sizeof(*t) / sizeof(TYPE);
	if (!ReScopeNC(cnt)) return *this;

	LONG	i = 0;

	TYPE	*pbuf = l_ptr;
	const TYPE	*tbuf = t;
	for (i = 0; i < count; i++, pbuf++, tbuf++) *pbuf = *tbuf;

	return *this;
}

template<class TYPE> void GeDynamicArray<TYPE>::SetBlockSize(LONG size)
{ 
	blocksize = size;
}

//Read array from hyperfile with list of types in order of how they appear in structures
template<class TYPE> Bool GeDynamicArray<TYPE>::Read(HyperFile *hf, GeDynamicArray<LONG> &typelist)
{
	if (!typelist || !hf) return FALSE;
	if (!hf->ReadLong(&count)) return FALSE;
	if (!hf->ReadLong(&blocksize)) return FALSE;
	l_cnt = 0;
	if (!ReScopeNC(count)) return FALSE;

	TYPE	*tbuf = l_ptr;
	LONG	i = 0, o = 0;
	for (i = 0; i < count; i++, tbuf++)
	{
		CHAR	*ttbuf = (CHAR *) tbuf;
		for (o = 0; o < typelist.count; o++)
		{
			switch (typelist[o])
			{
				case DATYPE_CHAR:			if (!hf->ReadChar(ttbuf)) return FALSE; ttbuf += sizeof(CHAR); break;
				case DATYPE_UCHAR:		if (!hf->ReadUChar((UCHAR *) ttbuf)) return FALSE; ttbuf += sizeof(UCHAR); break;
				case DATYPE_WORD:			if (!hf->ReadWord((WORD *) ttbuf)) return FALSE; ttbuf += sizeof(WORD); break;
				case DATYPE_UWORD:		if (!hf->ReadUWord((UWORD *) ttbuf)) return FALSE; ttbuf += sizeof(UWORD); break;
				case DATYPE_LONG:			if (!hf->ReadLong((LONG *) ttbuf)) return FALSE; ttbuf += sizeof(LONG); break;
				case DATYPE_ULONG:		if (!hf->ReadULong((ULONG *) ttbuf)) return FALSE; ttbuf += sizeof(ULONG); break;
				case DATYPE_REAL:			if (!hf->ReadReal((Real *) ttbuf)) return FALSE; ttbuf += sizeof(Real); break;
				case DATYPE_LREAL:		if (!hf->ReadLReal((LReal *) ttbuf)) return FALSE; ttbuf += sizeof(LReal); break;
				case DATYPE_BOOL:			if (!hf->ReadBool((Bool *) ttbuf)) return FALSE; ttbuf += sizeof(Bool); break;
				case DATYPE_TIME:			if (!hf->ReadTime((BaseTime *) ttbuf)) return FALSE; ttbuf += sizeof(BaseTime); break;
				case DATYPE_VECTOR:		if (!hf->ReadVector((Vector *) ttbuf)) return FALSE; ttbuf += sizeof(Vector); break;
				case DATYPE_LVECTOR:	if (!hf->ReadLVector((LVector *) ttbuf)) return FALSE; ttbuf += sizeof(LVector); break;
				case DATYPE_MATRIX:		if (!hf->ReadMatrix((Matrix *) ttbuf)) return FALSE; ttbuf += sizeof(Matrix); break;
				case DATYPE_LMATRIX:	if (!hf->ReadLMatrix((LMatrix *) ttbuf)) return FALSE; ttbuf += sizeof(LMatrix); break;
				case DATYPE_STRING:		{ if (!hf->ReadString((String *) ttbuf)) return FALSE; String	 tstring = ((String *) ttbuf)[0]; ttbuf += sizeof(tstring); }break;
				case DATYPE_FILENAME: { if (!hf->ReadFilename((Filename *) ttbuf)) return FALSE; Filename	 tsfn = ((Filename *) ttbuf)[0]; ttbuf += sizeof(tsfn); }break;
				case DATYPE_LLONG:		if (!hf->ReadLLong((LLONG *) ttbuf)) return FALSE; ttbuf += sizeof(LLONG); break;
				default:							ttbuf += typelist[o]; break;
			}
		}
	}
	return TRUE;
}

//Write array to hyperfile
template<class TYPE> Bool	GeDynamicArray<TYPE>::Write(HyperFile *hf, GeDynamicArray<LONG> &typelist)
{
	if (!typelist || !hf) return FALSE;
	if (!hf->WriteLong(count)) return FALSE;
	if (!hf->WriteLong(blocksize)) return FALSE;
	if (!ptr || count == 0) return TRUE;

	VLONG tsize = sizeof(TYPE);
	if (!tsize) return TRUE;

	LONG	i = 0, o = 0;
	TYPE	*tbuf = l_ptr;
	for (i = 0; i < count; i++, tbuf++)
	{
		CHAR	*ttbuf = (CHAR *) tbuf;
		for (o = 0; o < typelist.count; o++)
		{
			switch (typelist[o])
			{
				case DATYPE_CHAR:			if (!hf->WriteChar(ttbuf[0])) return FALSE; ttbuf += sizeof(CHAR); break;
				case DATYPE_UCHAR:		if (!hf->WriteUChar(((UCHAR *) ttbuf)[0])) return FALSE; ttbuf += sizeof(UCHAR); break;
				case DATYPE_WORD:			if (!hf->WriteWord(((WORD *) ttbuf)[0])) return FALSE; ttbuf += sizeof(WORD); break;
				case DATYPE_UWORD:		if (!hf->WriteUWord(((UWORD *) ttbuf)[0])) return FALSE; ttbuf += sizeof(UWORD); break;
				case DATYPE_LONG:			if (!hf->WriteLong(((LONG *) ttbuf)[0])) return FALSE; ttbuf += sizeof(LONG); break;
				case DATYPE_ULONG:		if (!hf->WriteULong(((ULONG *) ttbuf)[0])) return FALSE; ttbuf += sizeof(ULONG); break;
				case DATYPE_REAL:			if (!hf->WriteReal(((Real *) ttbuf)[0])) return FALSE; ttbuf += sizeof(Real); break;
				case DATYPE_LREAL:		if (!hf->WriteLReal(((LReal *) ttbuf)[0])) return FALSE; ttbuf += sizeof(LReal); break;
				case DATYPE_BOOL:			if (!hf->WriteBool(((Bool *) ttbuf)[0])) return FALSE; ttbuf += sizeof(Bool); break;
				case DATYPE_TIME:			if (!hf->WriteTime(((BaseTime *) ttbuf)[0])) return FALSE; ttbuf += sizeof(BaseTime); break;
				case DATYPE_VECTOR:		if (!hf->WriteVector(((Vector *) ttbuf)[0])) return FALSE; ttbuf += sizeof(Vector); break;
				case DATYPE_LVECTOR:	if (!hf->WriteLVector(((LVector *) ttbuf)[0])) return FALSE; ttbuf += sizeof(LVector); break;
				case DATYPE_MATRIX:		if (!hf->WriteMatrix(((Matrix *) ttbuf)[0])) return FALSE; ttbuf += sizeof(Matrix); break;
				case DATYPE_LMATRIX:	if (!hf->WriteLMatrix(((LMatrix *) ttbuf)[0])) return FALSE; ttbuf += sizeof(LMatrix); break;
				case DATYPE_STRING:		{ if (!hf->WriteString(((String *) ttbuf)[0])) return FALSE; String	 tstring = ((String *) ttbuf)[0]; ttbuf += sizeof(tstring); }break;
				case DATYPE_FILENAME: { if (!hf->WriteFilename(((Filename *) ttbuf)[0])) return FALSE; Filename	 tsfn = ((Filename *) ttbuf)[0]; ttbuf += sizeof(tsfn); }break;
				case DATYPE_LLONG:		if (!hf->WriteLLong(((LLONG *) ttbuf)[0])) return FALSE; ttbuf += sizeof(LLONG); break;
				default:							ttbuf += typelist[o]; break;
			}
		}
	}

	return TRUE;
}

//routine to execute code on all entries in ptr array
template<class TYPE> void GeDynamicArray<TYPE>::DoToAll(GeDynamicArrayCallback *callback, void *data) 
{ 
	if (!ptr) return;

	LONG	i = 0; 
	TYPE *buf = l_ptr;
	for (i = 0; i < count; i++, buf++)
	{
		callback(i, buf, data); 
	}
}

//routine to execute code on some entries in ptr array
template<class TYPE> void GeDynamicArray<TYPE>::DoToSome(GeDynamicArrayCallback *callback, void *data, LONG do_start, LONG do_end)
{
	if (!ptr) return;

	LONG	dend = do_end;
	LONG	dsta = do_start;
	if (dend < dsta) dend = do_start, dsta = do_end;
	if (dend > count) dend = count;
	if (dsta < 0) dsta = 0;

	TYPE *buf = &l_ptr[dsta];
	LONG	i = 0;
	for (i = dsta; i < dend; i++, buf++)
	{
		callback(i, buf, data);
	}
}

//routine to execute code on entries that match TYPE p in ptr array
template<class TYPE> void GeDynamicArray<TYPE>::DoToSearch(GeDynamicArrayCallback *callback, void *data, TYPE p)
{
	if (!ptr) return;

	TYPE *buf = l_ptr;
	LONG	i = 0;
	for (i = 0; i < count; i++, buf++)
	{
		if (*buf == p) callback(i, buf, data);
	}
}

//Resizes the array without retatining the data and without clearing the data
template<class TYPE> Bool GeDynamicArray<TYPE>::ReScopeNC(LONG cnt)
{
	if (cnt <= 0)
	{
		Free();
		return TRUE;
	}

	LONG	nsize = LONG(Ceil((cnt + l_cnt) / Real(blocksize)) * blocksize), i = 0;
	TYPE *buf = NULL;

	if (nsize != totcnt)
	{
		TYPE	*newarray = (TYPE*)GeAllocNC(sizeof(TYPE) * nsize);
		if (!newarray) return FALSE;

		Free();
		ptr = newarray;
		l_ptr = &ptr[l_cnt];

		totcnt = nsize;
	}
	else
	{
		for (i = 0, buf = l_ptr;i < count;i++, buf++) buf->~TYPE();
	}

	for (i = 0, buf = l_ptr;i < cnt;i++, buf++) new(buf)TYPE;

	count = cnt;
	return TRUE;
}

//Resizes the array without retaining the data
template<class TYPE> Bool	GeDynamicArray<TYPE>::ReScope(LONG cnt)
{
	if (cnt <= 0)
	{
		Free();
		return TRUE;
	}

	LONG	nsize = LONG(Ceil((cnt + l_cnt) / Real(blocksize)) * blocksize), i = 0;
	TYPE *buf = NULL;

	if (nsize != totcnt)
	{
		TYPE	*newarray = (TYPE*)GeAlloc(sizeof(TYPE) * nsize);
		if (!newarray) return FALSE;

		Free();
		ptr = newarray;
		l_ptr = &ptr[l_cnt];

		totcnt = nsize;
	}
	else
	{
		for (i = 0,buf = l_ptr;i < count;i++, buf++) buf->~TYPE();
		ClearMem(l_ptr,sizeof(TYPE)*cnt);
	}

	for (i = 0, buf = l_ptr;i < cnt;i++, buf++) new(buf)TYPE;

	count = cnt;
	return TRUE;
}

//Resizes the array without clearing the memory used
template<class TYPE> Bool	GeDynamicArray<TYPE>::ReSizeNC(LONG cnt)
{
	if (cnt == count) return TRUE;

	if (cnt < count) return Remove(cnt, count - cnt);
	return InsertSpace(count,cnt - count,FALSE);
}

template<class TYPE> Bool	GeDynamicArray<TYPE>::ReSize(LONG cnt)
{
	if (cnt == count) return TRUE;

	if (cnt < count) return Remove(cnt, count - cnt);
	return InsertSpace(count,cnt - count,TRUE);
}

//Reize the array down
template<class TYPE> Bool	GeDynamicArray<TYPE>::ReSize(LONG c_from, LONG c_to)
{
	LONG	t_from = Clamp(0, count, c_from), t_to = Clamp(0, count, c_to + 1);
	if (t_from == t_to) return ReSize(0);
	if (t_from > t_to)
	{
		LONG	temp = t_from;
		t_from = t_to;
		t_to = temp;
	}

	Shift(t_from, -t_from);
	return ReSize(t_to - t_from);
}

//Fill the array with TYPE t between c_from and c_to
template<class TYPE> inline void GeDynamicArray<TYPE>::Fill(LONG c_from, LONG c_to, TYPE t)
{
	LONG	t_from = LONG(Clamp(0, count, c_from)), t_to = LONG(Clamp(0, count, c_to + 1));
	if (t_from == t_to) return;
	if (t_from > t_to)
	{
		LONG	temp = t_from;
		t_from = t_to;
		t_to = temp;
	}

	TYPE	*buf = NULL;
	LONG	i = 0;
	for (i = t_from, buf = &l_ptr[t_from]; i < t_to; i++, buf++) *buf = t;
}

//Fill the array with TYPE t
template<class TYPE> inline void GeDynamicArray<TYPE>::Fill(TYPE t)	
{ 
	TYPE	*buf = l_ptr; 
	LONG i = 0; 
	for (i = 0; i < count; i++, buf++) *buf = t; 
}

//Add value to the array at index
//and shifts array up
template<class TYPE> Bool GeDynamicArray<TYPE>::Insert(TYPE p, LONG index)
{
	if (index < 0) return FALSE;

	if (!InsertSpace(index,1,TRUE)) return FALSE;
	l_ptr[index] = p;
	return TRUE;
}

//Inserts (copies) an existing array into this one
template<class TYPE> Bool	GeDynamicArray<TYPE>::Insert(const TYPE *p, LONG index, LONG cnt)
{
	if (index < 0 || index > count || !p || cnt <= 0) return FALSE;

	if (!InsertSpace(index, cnt, TRUE)) return FALSE;
	LONG i=0;
	TYPE *buf = &l_ptr[index];
	const TYPE *pbuf = p;
	for (i = 0;i < cnt;i++, pbuf++, buf++) (*buf) = (*pbuf);
	return TRUE;
}

//Merges an existing dynamic array into this one, this array becomes the owner
template<class TYPE> Bool	GeDynamicArray<TYPE>::MergeIn(GeDynamicArray<TYPE>&p,LONG index)
{
	if (index < 0 || index > count || !p || p.count <= 0) return FALSE;

	if (!InsertSpace(index, p.count, FALSE, FALSE)) return FALSE;
	LONG cnt = p.count;
	TYPE *data = p.Release();
	if (!data) return FALSE;
	CopyMem(data, &l_ptr[index], sizeof(TYPE) * cnt);
	GeFree(data);
	return TRUE;
}

//Inserts a gap in the array
template<class TYPE> Bool GeDynamicArray<TYPE>::InsertSpace(LONG index,LONG ammount,Bool clear,Bool makenew)
{
	if (index < 0) return FALSE;
	
	LONG	cnt = ((count > index)?count:index) + ammount;

	if (index <= count * 0.5)
	{
		l_cnt -= ammount;
		if (l_cnt < 0)
		{
			LONG nadd = LONG(Ceil((-l_cnt)/Real(blocksize)) * blocksize);
			totcnt += nadd;
			l_cnt += nadd;
			
			TYPE *newarray = (TYPE*)GeAllocNC(sizeof(TYPE) * totcnt);
			if (!newarray) return FALSE;

			if (index > 0)
			{
				CopyMem(l_ptr, &(newarray[l_cnt]), sizeof(TYPE) * index);
				CopyMem(&(l_ptr[index]), &(newarray[index + l_cnt + ammount]), sizeof(TYPE) * (count - index));
			}
			else
			{
				CopyMem(l_ptr, &(newarray[blocksize]), sizeof(TYPE) * count);
			}
			GeFree(ptr);
			ptr = newarray;	
			l_ptr = &ptr[l_cnt];
		}
		else
		{
			l_ptr = &ptr[l_cnt];
			if (index > 0) memmove(l_ptr, &(l_ptr[ammount]), sizeof(TYPE) * index);
		}
	}
	else
	{
		LONG	nsize = LONG(Ceil((cnt + l_cnt) / Real(blocksize)) * blocksize);

		if (nsize > totcnt)
		{
			TYPE *newarray = (TYPE*)GeAllocNC(sizeof(TYPE) * nsize);
			if (!newarray) return FALSE;

			if (index < count)
			{
				CopyMem(l_ptr, &newarray[l_cnt], sizeof(TYPE) * index);
				CopyMem(&(l_ptr[index]), &(newarray[index + l_cnt + ammount]), sizeof(TYPE) * (count - index));
			}
			else
			{
				CopyMem(l_ptr, &newarray[l_cnt], sizeof(TYPE) * count);
			}

			GeFree(ptr);
			ptr = newarray;
			l_ptr = &ptr[l_cnt];
			totcnt = nsize;
		} 
		else 
		{
			if (index < count) memmove(&(l_ptr[index+ammount]), &(l_ptr[index]), sizeof(TYPE) * (count - index));
		}
	}

	LONG i = 0;
	TYPE *buf = NULL;

	if (clear) 
	{
		if (count < index) 
			ClearMem(&l_ptr[count], sizeof(TYPE) * (index - count), 0);
		
		ClearMem(&l_ptr[index],sizeof(TYPE) * ammount, 0);
	}

	if (makenew)
	{
		if (count < index)
			for (i = count, buf = &l_ptr[count]; i<index; i++, buf++) new(buf)TYPE;
		
		for (i = 0, buf = &l_ptr[index]; i < ammount; i++, buf++) new(buf)TYPE;
	}

	count = cnt;

	return TRUE;
}

//Add value to the end of the array
template<class TYPE> Bool GeDynamicArray<TYPE>::Push(TYPE p)	
{ 
	return Insert(p, count);
}

//Remove value from the array at index
//and shifts array down
template<class TYPE> Bool GeDynamicArray<TYPE>::Remove(LONG index, LONG ammount) 
{ 
	if (index < 0 || index >= count || !ptr) return FALSE;

	if (index <= 0 && ammount == count)
	{
		Free();
		return TRUE;
	}

	LONG top = LMin(index + ammount, count), amt = top - index;
	LONG i = 0;
	TYPE *buf = NULL;

	for (i = 0, buf = &l_ptr[index];i < amt;i++, buf++) buf->~TYPE();

	if (index < count * 0.5)
	{
		l_cnt += amt;
		if (l_cnt >= blocksize)
		{
			LONG nsub = LONG(Floor((l_cnt)/Real(blocksize)) * blocksize);
			totcnt -= nsub;
			l_cnt -= nsub;
			
			TYPE *newarray = (TYPE*)GeAllocNC(sizeof(TYPE) * totcnt);
			if (!newarray) return FALSE;

			if (index > 0)
			{
				CopyMem(l_ptr, &(newarray[l_cnt]), sizeof(TYPE) * index);
				CopyMem(&(l_ptr[index + amt]), &(newarray[index + l_cnt]), sizeof(TYPE) * ((count - index) - amt));
			}
			else
			{
				CopyMem(&l_ptr[amt], &(newarray[l_cnt]), sizeof(TYPE) * (count - amt));
			}

			GeFree(ptr);
			ptr = newarray;	
			l_ptr = &ptr[l_cnt];
		}
		else
		{
			if (index > 0) memmove(&l_ptr[amt], l_ptr, sizeof(TYPE) * index);
			l_ptr = &ptr[l_cnt];
		}
	}
	else
	{
		LONG	nsize = LONG(Ceil(((count + l_cnt) - amt) / Real(blocksize)) * blocksize);

		if (nsize < totcnt)
		{
			TYPE *newarray = (TYPE*)GeAllocNC(sizeof(TYPE) * nsize);
			if (!newarray) return FALSE;

			if (index < count - 1)
			{
				CopyMem(l_ptr, &newarray[l_cnt], sizeof(TYPE) * index);
				CopyMem(&(l_ptr[index + amt]), &(newarray[index + l_cnt]), sizeof(TYPE) * ((count - index) - amt));
			}
			else
			{
				CopyMem(l_ptr, &newarray[l_cnt], sizeof(TYPE) * (count - amt));
			}

			GeFree(ptr);
			ptr = newarray;
			l_ptr = &ptr[l_cnt];
			totcnt = nsize;
		} 
		else 
		{
			if (index < count - 1) memmove(&(l_ptr[index]), &(l_ptr[index + amt]), sizeof(TYPE) * (count - (index + amt) ) );
		}
	}
	count-=amt;
	return TRUE;
}

//Removes all that match p from the array
template<class TYPE> inline void GeDynamicArray<TYPE>::RemoveAll(TYPE p) 
{ 
	LONG	index = 0; 
	while (TRUE) 
	{ 
		index = Find(p, index); 
		if (index == NOTOK) break; 
		Remove(index); 
	} 
}

//Remove value from the end of the array
template<class TYPE> void GeDynamicArray<TYPE>::Pop(void) 
{ 
	Remove(count - 1);
}

//Find the index of type that matches type p
template<class TYPE> inline LONG GeDynamicArray<TYPE>::Find(TYPE p)	
{ 
	return Find(p,0); 
}

//Try to find an object from index onwards that matches type p
template<class TYPE> inline LONG GeDynamicArray<TYPE>::Find(TYPE p, LONG index)
{
	if (index >= count || !ptr) return NOTOK;

	TYPE	*buf = &l_ptr[index];
	LONG	i = 0;
	for (i = index; i < count; i++, buf++)
		if (*buf == p) return i;
	return NOTOK;
}

//Shift array down or up from index value
// negative to move down, positive to move up
template<class TYPE> void	GeDynamicArray<TYPE>::Shift(LONG index, LONG cnt)
{
	ShiftBlock(index,count,cnt);
}

//Shift a block of the array up or down
// negative to move down, positive to move up
template<class TYPE> void	GeDynamicArray<TYPE>::ShiftBlock(LONG b_from, LONG b_to, LONG ammount)
{
	LONG block_start = LMin(b_from, b_to);
	LONG block_end = LMax(b_from, b_to);
	if (ammount == 0 || block_start == block_end || block_start < 0 || block_end > count) return;

	TYPE	*buf = NULL;
	LONG	i = 0;
	if (ammount > 0)
	{
		LONG	istart = block_start;
		LONG	iend = block_end - ammount;

		if (iend < istart) iend = istart;

		LONG m_min = LMin(count, LMax(block_end, istart + ammount));
		LONG m_max = LMin(count, block_end + ammount);

		for (i = m_min, buf = &l_ptr[m_min]; i < m_max; i++, buf++) buf->~TYPE();

		m_min = LMin(count, istart + ammount);

		if (m_max - m_min > 0)
			memmove(&(l_ptr[m_min]),&(l_ptr[istart]),sizeof(TYPE)*(m_max - m_min));

		iend = LMin(istart + ammount, block_end);

		ClearMem(&l_ptr[istart],sizeof(TYPE)*(iend - istart),0);
		for (i = istart, buf = &l_ptr[istart]; i < iend; i++, buf++) new(buf)TYPE;
	}
	else
	{
		LONG	istart = block_start;
		LONG	iend = block_end;

		LONG	m_shift = 0;
		LONG	m_end = LMax(0, iend + ammount), m_max = LMin(m_end, istart);
		LONG	m_to = istart + ammount;
		if ( m_to < 0 )
		{
			m_to = 0;
			m_shift =- (istart + ammount);
		}

		for (i = m_to, buf = &l_ptr[m_to]; i < m_max; i++, buf++) buf->~TYPE();

		if (m_end - m_to > 0)
			memmove(&(l_ptr[m_to]),&(l_ptr[istart + m_shift]),sizeof(TYPE)*(m_end - m_to));

		istart = LMax(block_start, m_end);

		ClearMem(&l_ptr[istart],sizeof(TYPE)*(iend - istart),0);
		for (i = istart, buf = &l_ptr[istart]; i < iend; i++, buf++) new(buf)TYPE;
	}
}

//-----------------------------------------
//Safe Variant, this can be accessed via [] safely and will never get out of bounds
template<class TYPE> class GeSafeDynamicArray : public GeDynamicArray < TYPE >
{
	INSTANCEOF(GeDynamicArray < TYPE > , GeSafeDynamicArray < TYPE > )
public:
	GeSafeDynamicArray(void)	
	{ 
		this->ptr = NULL;
		this->blocksize = 4;
		this->Free();
	}

	GeSafeDynamicArray(LONG size)
	{ 
		this->ptr = NULL;
		this->blocksize = 4;
		this->Free();
		this->ReScope(size); 
	}

	GeSafeDynamicArray(LONG size, LONG block) 
	{
		this->ptr = NULL;
		this->blocksize = block;
		this->Free();
		this->ReScope(size); 
	}

	~GeSafeDynamicArray(void)
	{
		this->Free();
	}

	GeSafeDynamicArray<TYPE> &operator =(GeSafeDynamicArray<TYPE> &t)
	{
		this->Free();

		this->SetBlockSize(t.GetBlockSize());
		this->ReScopeNC(t.count);

		LONG	i = 0;
		TYPE *buf = this->l_ptr, *buf2 = t.l_ptr;
		for (i = 0; i < this->count; i++, buf++, buf2++) (*buf) = (*buf2);

		return *this;
	}

	GeSafeDynamicArray<TYPE> &operator =(TYPE *t) 
	{ 
		this->Free();
		this->ptr = t;
		this->count = sizeof(this->ptr) / sizeof(TYPE);
		this->totcnt = this->count;
		this->l_ptr = &(this->ptr[this->l_cnt]);
		return *this;
	}

	TYPE & operator[](LONG i)
	{
		if (this->count == 0)
		{
			this->ReScope(1);
			return this->l_ptr[0];
		}
		if (i < 0) return this->l_ptr[0];
		if (i >= this->count) return this->l_ptr[this->count - 1];
		return this->l_ptr[i];
	}
#ifndef __LINUX
	TYPE & operator[] ( int i )
	{
		return operator[]((LONG) i);
	}
#endif
	TYPE & operator[] ( unsigned i )
	{
		return operator[]((LONG) i);
	}
};

//--------------------------------------------------------
//Automatic variant, this will resize based on the index you specify in array[index]
template<class TYPE> class GeAutoDynamicArray : public GeDynamicArray < TYPE >
{
	INSTANCEOF(GeDynamicArray < TYPE > , GeAutoDynamicArray < TYPE > )
public:
	GeAutoDynamicArray(void)
	{ 
		this->ptr = NULL;
		this->blocksize = 4;
		this->Free();
	}
	
	GeAutoDynamicArray(LONG size) 
	{ 
		this->ptr = NULL;
		this->blocksize = 4;
		this->Free();
		this->ReScope(size);
	}

	GeAutoDynamicArray(LONG size, LONG block) 
	{ 
		this->ptr = NULL;
		this->blocksize = block;
		this->Free();
		this->ReScope(size);
	}
	~GeAutoDynamicArray(void)
	{
		this->Free();
	}

	GeAutoDynamicArray<TYPE> &operator =(GeAutoDynamicArray<TYPE> &t)
	{
		this->Free();
		this->SetBlockSize(t.GetBlockSize());
		this->ReScopeNC(t.count);

		LONG	i = 0;
		TYPE *buf = this->l_ptr, *buf2 = t.l_ptr;
		for (i = 0; i < this->count; i++, buf++, buf2++) (*buf) = (*buf2);

		return *this;
	}

	GeAutoDynamicArray<TYPE> &operator =(TYPE *t) 
	{ 
		this->Free(); 
		this->ptr = t; 
		this->count = sizeof(this->ptr) / sizeof(TYPE); 
		this->totcnt = this->count; 
		this->l_ptr = &(this->ptr[this->l_cnt]);
		return *this; 	
	}

	TYPE & operator[](LONG i)
	{
		if (this->count == 0)
		{
			this->ReScope(1);
		}
		if (i < 0) return this->l_ptr[0];
		if (i >= this->count)
		{
			this->ReSize(i + 1);
		}
		return this->l_ptr[i];
	}
#ifndef __LINUX
	TYPE & operator[] ( int i )
	{
		return operator[]((LONG) i);
	}
#endif
	TYPE & operator[] ( unsigned i )
	{
		return operator[]((LONG) i);
	}
};
#endif
 
 