//	CEntryArray.cpp

#include <stdlib.h>
#include "MemUtils.h"
#include "IC_Errors.h"
#include "CEntry.h"
#include "CEntryArray.h"

/*
	the indexes of this array are Zero (0) based.  
*/

/**********************************************************************/
CEntryArray		*GetNewEntryArray(void)
{
	CEntryArray	*tUpdate = new(CEntryArray);

	tUpdate->IEntryArray();
	
	return tUpdate;
}

void	CEntryArray::IEntryArray(void)
{
	i_array.num_items	= 0;
	i_array.array_size	= kDefaultEntryArraySize;
	i_array.entryA		= (CEntryA)TrackNewPtrClear(
		"entry array", 
		sizeof(CEntry *) * kDefaultEntryArraySize);
}

void	CEntryArray::Dispose(void)
{
	TrackDisposePtr((Ptr)i_array.entryA);
	delete this;
}

CEntryArray			*CEntryArray::Duplicate(void)
{
	CEntryArray		*dupArray	= GetNewEntryArray();
	
	if (i_array.array_size != kDefaultEntryArraySize) {
		TrackDisposePtr((Ptr)dupArray->i_array.entryA);
		dupArray->i_array.entryA = (CEntryA)TrackNewPtrClear("dup entry array", sizeof(CEntry *) * i_array.array_size);
	};
	
	dupArray->i_array.num_items		= i_array.num_items;
	dupArray->i_array.array_size	= i_array.array_size;
	memcpy(dupArray->i_array.entryA, i_array.entryA, sizeof(CEntry *) * i_array.array_size);
	
	return dupArray;
}

OSErr		CEntryArray::Add(CEntry *pane)
{
	OSErr		err = noErr;
	
	i_array.num_items++;
	
	if (i_array.num_items > i_array.array_size) {
		CEntryA		entryA = (CEntryA)TrackNewPtrClear("entry array node", sizeof(CEntry *) * (i_array.array_size + kDefaultEntryArraySize));
		
		if (entryA) {
			memcpy(entryA, i_array.entryA, sizeof(CEntry *) * i_array.array_size);
			i_array.array_size += kDefaultEntryArraySize;
			TrackDisposePtr((Ptr)i_array.entryA);
			i_array.entryA = entryA;
		} else {
			err = memFullErr;
			ReportErrorStr(err, "Memory Full");
		}
		
	}
	
	if (!err) {
		i_array.entryA[i_array.num_items - 1] = pane;
	}
	
	return err;
}

long		CEntryArray::IndexOf(CEntry *pane)
{
	long			index = TA_Index_NONE;
	
	if (i_array.num_items > 0) {
		OSErr			err = noErr;
		CEntry			*curEntry;
		
		CE_FOR_EACH(this, index, curEntry, err) {
			if (pane == curEntry) {
				break;
			}
		} CE_END_EACH();
		
		if (index == i_array.num_items + 1) {
			index = TA_Index_NONE;
		}
	}
	
	return index;
}

Boolean		CEntryArray::Member(CEntry *pane)
{
	return IndexOf(pane) != TA_Index_NONE;
}

void	CEntryArray::Remove(CEntry *pane)
{
	long		pos = IndexOf(pane);

	if (pos != TA_Index_NONE) {
		i_array.num_items--;
		
		if (i_array.num_items > pos ) {
			memcpy(
				&i_array.entryA[pos], 
				&i_array.entryA[pos + 1], 
				sizeof(CEntry *) * (i_array.num_items - pos));
		}
	}
}

void	CEntryArray::RemoveAll(void)
{
	i_array.num_items = 0;
}

long	CEntryArray::Count(void)
{
	return i_array.num_items;
}

CEntry	*CEntryArray::GetIndEntry(long index)
{
	return i_array.entryA[index];
}

OSErr	CEntryArray::IterateReverse(TA_IterateType taType, void *cbData)
{
	Err				err = Err_NONE;
	long			index;
	CEntry			*curEntry;
	
	CE_FOR_EACH_REVERSE(this, index, curEntry, err) {
		err = curEntry->EntryPane_CB_EntryArray(taType, (TA_IterateData *)cbData);
	} CE_END_EACH();
	
	return err;
}

OSErr	CEntryArray::Iterate(TA_IterateType taType, void *cbData)
{
	Err				err = Err_NONE;
	long			index;
	CEntry			*curEntry;
	
	CE_FOR_EACH(this, index, curEntry, err) {
		err = curEntry->EntryPane_CB_EntryArray(taType, (TA_IterateData *)cbData);
	} CE_END_EACH();
	
	return err;
}

CEntryArray *			S_sort_this 		= NULL;
void *					S_sort_refconPV 	= NULL;
EntryA_CompareFunc		S_sort_comp_func 	= NULL;
OSErr					S_sort_err			= noErr;
long					S_sort_semaphor		= 0;

static	int		EntryA_QuickSortCompare(const void *elem1PV, const void *elem2PV)
{
	int			result	= 0;
	
	if (S_sort_err == noErr) {
		S_sort_err = (*S_sort_comp_func)(S_sort_refconPV, S_sort_this, elem1PV, elem2PV, &result);
	}
	
	return result;
}

OSErr		CEntryArray::Sort(EntryA_CompareFunc SortFuncCB, void *refconPV0)
{
	ASSERT(S_sort_semaphor >= 0);
	
	S_sort_semaphor++;

	if (S_sort_semaphor == 1) {									
		S_sort_err = noErr;
		
		ASSERT((S_sort_this == NULL) && (S_sort_refconPV == NULL) && (S_sort_comp_func == NULL));
		
		S_sort_this			= this;
		S_sort_refconPV		= refconPV0;
		S_sort_comp_func	= SortFuncCB;
		
		qsort(i_array.entryA, i_array.num_items, sizeof(CEntry *), EntryA_QuickSortCompare);

		S_sort_this			= NULL;
		S_sort_refconPV		= NULL;
		S_sort_comp_func	= NULL;
	} else {
		ReportErrorStr(-1, "the sort function is not reentrant.");
		S_sort_err = IC_Err_OS;
	}
	
	ASSERT(S_sort_semaphor > 0);
	S_sort_semaphor--;
	
	return S_sort_err;
}


