#include "operatingsystem.h"
#include "c4d_memory.h"
#include "ge_sort.h"
#include "ge_mtools.h"

////////////////////////////////

GeToolDynArray::~GeToolDynArray()
{
	FlushThis();
}

////////////////////////////////

Bool GeToolDynArray::CopyTo(GeToolDynArray *dest) const
{
	dest->FlushThis();
	
	dest->init = init;
	dest->step = step;

	LONG i;
	for (i = 0; i < count; ++i)
	{
		if (!dest->Append(array[i])) return FALSE;
	}
	return TRUE;
}

void GeToolDynArray::Swap(LONG a, LONG b)
{
	if (a < 0 || a >= count || b < 0 || b >= count || a == b) return;
	GeTempSwap(array[a],array[b]);
}

void GeToolDynArray::Move(LONG source, LONG dest)
{
	if (source < dest) --dest; 
	if (source < 0 || source >= count || dest < 0 || dest>= count || dest == source) return;
	void *t = array[source];
	if (Remove(source)) Insert(t,dest);
}

Bool GeToolDynArray::Enlarge(void)
{
	void **narray;
	LONG nsize;
		
	if (!size) nsize = init;
	else 
	{
		if (step) nsize = size + step; else nsize = size * 2;
	}
	if (!nsize) return FALSE;

	narray = STATIC_CAST(void**,GeAlloc(nsize * sizeof(void*)));
	if (!narray) return FALSE;
	CopyMem(array,narray,count * sizeof(void*));		
	GeFree(array);
	array = narray;
	size = nsize;
	return TRUE;
}

Bool GeToolDynArray::Append(void *e)
{
	if (count == size)
	{
		if (!Enlarge()) return FALSE;
	}	
	array[count] = e;
	count += 1;
	return TRUE;
}

Bool GeToolDynArray::SetIndexEnlarge(LONG i, void *e)
{
	if (i<count)
		return SetIndex(i,e);

	while (count<i) 
		Append(NULL);

	return Append(e);
}

Bool GeToolDynArray::Insert(void *e, LONG n)
{
	LONG i;

	if (n > count) n = count;
	if (n < 0) n = 0;

	if (count == size )
	{
		if (!Enlarge()) return FALSE;
	}	
	for (i = count; i > n; i -= 1) array[i] = array[i - 1];
	array[n] = e;
	count += 1;
	return TRUE;
}

Bool GeToolDynArray::Remove(LONG n)
{
	if (n < 0 || n >= count) return FALSE;
	for (count -= 1; n < count; n += 1) array[n] = array[n + 1];
	return TRUE;
}

Bool GeToolDynArray::Remove(void *e)
{
	return Remove(Find(e));
}

LONG GeToolDynArray::Find(const void *e) const
{
	LONG n;

	for (n = 0; n < count; ++n)
	{
		if (array[n] == e) return n;
	}
	return GE_TOOL_NOT_FOUND;
}

void GeToolDynArray::FlushThis(void)
{
	GeFree(array);
	array = NULL;
	count = size = 0;
}

void GeToolDynArray::ResetCount(void)
{
	count = 0;
}

void* GeToolDynArray::Pop()
{
	void *ret = GetIndex(count - 1);
	if (ret) Remove(count - 1);
	return ret;
}

////////////////////////////////

class GeToolDynArraySort : public GeSortAndSearch
{
	public:
	GeToolDynArraySort(LONG (*compare)(void *a, void *b)) : compare_func(compare) { }

	LONG (*compare_func)(void *a,void *b);
	LONG Compare(void *a, void *b) { return compare_func(a,b); }
};

void GeToolDynArray::Sort(LONG (*compare)(void *a, void *b))
{
	GeToolDynArraySort sort(compare);
	sort.Sort(array,count,sizeof(void*));
}

void *GeToolDynArray::Search(void *key,LONG (*search)(void *a, void *b))
{
	GeToolDynArraySort sort(search);
	return sort.Search(key,array,count,sizeof(void*));
}

////////////////////////////////

GeToolList2D::GeToolList2D(void)
{
	node = NULL; Clear();
}

GeToolList2D::~GeToolList2D(void)
{
	FlushAll();
}

void GeToolList2D::Clear(void)
{
  head.prev = NULL;
  head.next = &tail;
  tail.prev = &head;
  tail.next = NULL;
}

void GeToolList2D::FlushAll(void)
{
	GeToolNode2D *next, *node;
	
	node = STATIC_CAST(GeToolNode2D*,GetFirst());
	while (node)
	{
		next = STATIC_CAST(GeToolNode2D*,node->GetNext());
		gDelete(node);
		node = next;
	}
	Clear();
}

void GeToolList2D::RemoveAll(void)
{
	GeToolNode2D *next, *node;
	
	node = STATIC_CAST(GeToolNode2D*,GetFirst());
	while (node)
	{
		next = STATIC_CAST(GeToolNode2D*,node->GetNext());
		node->Remove();
		node = next;
	}
}

void* GeToolList2D::GetIndex(LONG index) const
{
	LONG nr = 0;
	GeToolNode2D *node;
	
	node = STATIC_CAST(GeToolNode2D*,GetFirst());
	while (node)
	{
		if (nr++ == index) return(STATIC_CAST(void*,node));
		node = STATIC_CAST(GeToolNode2D*,node->GetNext());
	}
	return(NULL);
}

void GeToolList2D::Insert(void *nv)
{
	GeToolNode2D *n = STATIC_CAST(GeToolNode2D*,nv);

	n->next = head.next;
	n->prev = &head;
	head.next->prev = n;
	head.next = n;
}

void GeToolList2D::Append(void *nv)
{
	GeToolNode2D *n = STATIC_CAST(GeToolNode2D*,nv);

	n->next = &tail;
	n->prev = tail.prev;
	tail.prev->next = n;
	tail.prev = n;
}

LONG GeToolList2D::GetCount(void) const
{
	LONG count = 0; GeToolNode2D *n;

	for (n = (GeToolNode2D*)GetFirst(); n; n = (GeToolNode2D*)n->GetNext()) ++count;

	return count;
}

////////////////////////////////

GeToolNode2D::~GeToolNode2D(void)
{
	Remove();
}

void GeToolNode2D::InsertAfter(void *nv)
{
	GeToolNode2D *n = STATIC_CAST(GeToolNode2D*,nv);

	next = n->next;
	n->next = this;
	prev = n;
	n->next->prev = this;
}

void GeToolNode2D::InsertBefore(void *nv)
{
	GeToolNode2D *n = STATIC_CAST(GeToolNode2D*,nv);

	prev = n->prev;
	n->prev = this;
	next = n;
	this->prev->next = this;
}

void GeToolNode2D::Remove(void)
{
  if (prev && next) {
		prev->next = this->next;
		next->prev = this->prev;
		prev = next = NULL;
	}
}

////////////////////////////////
