
//*****************************************************************************
//*  CpaListB.cpp                                                             *
//*****************************************************************************
//*                                                                           *
//* Functions of the CPA_BaseObjectList class : list of CPA_BaseObject with   *
//* different sort orders and fast search functions.                          *
//*                                                                           *
//*****************************************************************************
//* Author : Yann Le Tensorer, Alexis Vaisse                                  *
//*****************************************************************************



#include "stdafx.h"

#ifdef ACTIVE_EDITOR


#include "itf/CPAListB.hpp"
#include "itf/CPABaseO.hpp"


#define  C_lSizeIncrease  16    // When the array must be reallocated, we add space for 16 more objects


#define stricmp __asmstricmp


//*****************************************************************************
//**********             Construction and destruction                **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - constructor
//-----------------------------------------------------------------------------
CPA_BaseObjectList::CPA_BaseObjectList  (const CString _csTypeName /* = "" */)
{
    m_csTypeName          = _csTypeName;
    m_szTypeName          = (char *) (LPCTSTR) m_csTypeName;

    m_lNumberOfObjects    = 0;
    m_lMaxNumberOfObjects = 0;

	m_lCurrentUniqueIndex = 0;

    for (int i = E_lo_First ; i <= E_lo_Last ; i ++)
        m_Array [i] = NULL;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - destructor
//-----------------------------------------------------------------------------
CPA_BaseObjectList::~CPA_BaseObjectList ()
{
    DeleteAllElements ();
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - ReallocArray
// Change the size of the arrray
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::ReallocArray (long _lNewSize)
{
    for (int i = E_lo_First ; i <= E_lo_Last ; i ++)
    {
        if (_lNewSize == 0)
        {
            if (m_Array [i] != NULL)  
			{
				free (m_Array [i]);
				m_Array [i] = NULL;
			}
        }
        else
        {
            if (m_Array [i] == NULL)
                 m_Array [i] = (tdp_BaseObjectPointer *) malloc  (              sizeof (tdp_BaseObjectPointer) * _lNewSize);
            else m_Array [i] = (tdp_BaseObjectPointer *) realloc (m_Array [i] , sizeof (tdp_BaseObjectPointer) * _lNewSize);
        }
    }

    m_lMaxNumberOfObjects = _lNewSize;
    if (m_lNumberOfObjects > m_lMaxNumberOfObjects)  m_lNumberOfObjects = m_lMaxNumberOfObjects;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - DeleteAllElements
// Empty the list but do not delete the CPA_BaseObject
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::DeleteAllElements ()
{
    ReallocArray (0);
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - DeleteAllObjects
// Empty the list and delete all CPA_BaseObject
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::DeleteAllObjects ()
{
    // Delete all objects using object order (any order could workd)
    for (long i = 0 ; i < m_lNumberOfObjects ; i ++)
        delete m_Array [E_lo_Object] [i];

    DeleteAllElements ();
}


//*****************************************************************************
//**********                    Low level functions                  **********
//*****************************************************************************

//=============================================================================
// asm defined stricmp to fasten a little bit the very very slow function
// written by microsoft...
//=============================================================================
int __asmstricmp(char * a, char * b)
{
	char retour;
	_asm 
	{
		mov eax,a
		mov ebx,b
boucle:
		mov ecx,dword ptr[eax]
		mov edx,dword ptr[ebx]
;============= first word
		cmp cl,97
		jge sub32cl
		cmp dl,97
		jge sub32dl
		jmp suite
sub32cl:
		sub cl,32
		cmp dl,97
		jl	suite

sub32dl:
		sub dl,32
suite:	
		sub cl,dl

		cmp dl,0
		je  fin
		cmp cl,0
		jne fin

		cmp ch,97
		jge sub32ch
		cmp dh,97
		jge sub32dh
		jmp suite2
sub32ch:
		sub ch,32
		cmp dh,97
		jl	suite2

sub32dh:
		sub dh,32

suite2:
		sub ch,dh
		cmp dh,0
		je fin2
		cmp ch,0
		jne fin2
;================ end first word

		shr ecx,16
		shr edx,16


;============= second word
		cmp cl,97
		jge sub32clx
		cmp dl,97
		jge sub32dlx
		jmp suitex
sub32clx:
		sub cl,32
		cmp dl,97
		jl	suitex

sub32dlx:
		sub dl,32
suitex:	
		sub cl,dl
		cmp dl,0
		je  fin
		cmp cl,0
		jne fin

		cmp ch,97
		jge sub32chx
		cmp dh,97
		jge sub32dhx
		jmp suite2x
sub32chx:
		sub ch,32
		cmp dh,97
		jl suite2x

sub32dhx:
		sub dh,32

suite2x:
		sub ch,dh
		cmp dh,0
		je fin2
		cmp ch,0
		jne fin2
;================ end second word

		add eax,4
		add ebx,4
		jmp boucle

fin:	
		mov retour,cl
        jmp VraieFin
fin2:
        mov retour,ch
VraieFin:
	}
	return (int)retour;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchName
// Low level function to find an object with a given name in a given list
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchName(CPA_BaseObject** _p_oList, unsigned long _ulListSize, char* _NameToFind,BOOL* _bFound,CPA_BaseObject* _p_oAdress)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;

	while (Bas!=Haut+1)
	{
		signe=stricmp((_p_oList[Milieu]->fn_p_szGetName()),_NameToFind);	

		/* This is used to continue search on adress if wanted */
		if (signe==0 && _p_oAdress!=NULL) signe=(long)(_p_oList[Milieu]-_p_oAdress);

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
			*_bFound=TRUE;		
			return Milieu;
		}
	};

	*_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchType
// Low level function to find an object with a given type in a given list
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchType(CPA_BaseObject** _p_oList, unsigned long _ulListSize, char* _TypeToFind,BOOL* _bFound,CPA_BaseObject* _p_oAdress)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;

	while (Bas!=Haut+1)
	{
		signe=stricmp((_p_oList[Milieu]->fn_p_szGetType()),_TypeToFind);	

		/* This is used to continue search on adress if wanted */
		if (signe==0 && _p_oAdress!=NULL) signe=(long)(_p_oList[Milieu]-_p_oAdress);

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
	     *_bFound=TRUE;		
		 return Milieu;
		}
	};

	*_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchData
// Low level function to find an object with a given data in a given list
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchData(CPA_BaseObject** _p_oList, unsigned long _ulListSize, void* _DataToFind,BOOL* _bFound,CPA_BaseObject* _p_oAdress)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;

	while (Bas!=Haut+1)
	{
		signe=(long)_p_oList[Milieu]->GetData()-(long)_DataToFind;	

		/* This is used to continue search on adress if wanted */
		if (signe==0 && _p_oAdress!=NULL) signe=(long)(_p_oList[Milieu]-_p_oAdress);

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
	     *_bFound=TRUE;		
		 return Milieu;
		}
	};

	*_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchOwner
// Low level function to find an object with a given owner in a given list
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchOwner(CPA_BaseObject** _p_oList, unsigned long _ulListSize, CPA_BaseObject* _OwnerToFind,BOOL* _bFound,CPA_BaseObject* _p_oAdress)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;

	while (Bas!=Haut+1)
	{
		signe=(long)(_p_oList[Milieu]->GetOwner()-_OwnerToFind);	

		/* This is used to continue search on adress if wanted */
		if (signe==0 && _p_oAdress!=NULL) signe=(long)(_p_oList[Milieu]-_p_oAdress);

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
	     *_bFound=TRUE;		
		 return Milieu;
		}
	};

	*_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchBaseObject
// Low level function to find the index of an object in a given list
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchBaseObject(CPA_BaseObject** _List, unsigned long _ListSize, CPA_BaseObject* _BaseObjectToFind,BOOL* _bFound)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;

	while (Bas!=Haut+1)
	{
		signe=(long)(_List[Milieu]-_BaseObjectToFind);	
		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
	     *_bFound=TRUE;		
		 return Milieu;
		}
	}

	*_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchNamesTypesOwners
// Low level function to find objects which have a given name, an optional type and an optional owner
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchNamesTypesOwners(
								CPA_List<CPA_BaseObject> *_p_oReturnList, 
								CPA_BaseObject** _p_oList, 
								unsigned long _ulListSize,
								BOOL* _p_bFound, 
								char* _Name,
								char* _type,
								CPA_BaseObject* _Owner)
{
		int Count=0;
		BOOL CountOnly;
		int index,i;
				
		/* Avoid crashes, please do not replace with ASSERT... */
		if (_p_bFound==NULL || !stricmp(_Name,"") || _p_oList== NULL || ((long)_ulListSize)<=0) 
		{
			if (_p_bFound!=NULL) *_p_bFound=FALSE;
			return 0;
		}
				
		if (_p_oReturnList==NULL) 
			CountOnly=TRUE;
		else
			CountOnly=FALSE;

		/* we search the name in the sorted list */
 		index=fn_lDichoSearchName(_p_oList,_ulListSize,_Name,_p_bFound);

		if (*_p_bFound)
		{
			i=index;
			/* we search the same names before */
			while (i>=0 && !stricmp(_p_oList[i]->fn_p_szGetName(),_Name)) 
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Owner!=NO_CRITERIA*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						if (CountOnly==FALSE) _p_oReturnList->AddTail(_p_oList[i]);
						Count++;
					}
				}
				i--;
				
			}

			i=index+1;
			/* we search the same names after */
			while ((i<(long)_ulListSize) && !stricmp(_p_oList[i]->fn_p_szGetName(),_Name) )
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Type!=NULL*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						if (CountOnly==FALSE) _p_oReturnList->AddTail(_p_oList[i]);
						Count++;
					}
				}
				i++;
			}	
		}
		if (Count==0) *_p_bFound=FALSE;

		return Count;
};

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchNameTypeOwner
// Low level function to find an object which has a given name, an optional type and an optional owner
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchNameTypeOwner(
								CPA_BaseObject** _p_oList, 
								unsigned long _ulListSize, 
								BOOL* _p_bFound,
								char* _NameToFind,
								char* _type,
								CPA_BaseObject* _Owner
								)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;
	long i;

	/* Avoid crashes, please do not replace with ASSERT... */
	if (_p_bFound==NULL || _p_oList== NULL || ((long)_ulListSize)<=0)
		{
			if (_p_bFound!=NULL) *_p_bFound=FALSE;
			return 0;
		}


	while (Bas!=Haut+1)
	{
		signe=stricmp((_p_oList[Milieu]->fn_p_szGetName()),_NameToFind);	

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
			/* the name was found !*/
			/* search for type and owner if necessary*/
			i=Milieu;

			while (i>=0 && !stricmp(_p_oList[i]->fn_p_szGetName(),_NameToFind))
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Owner!=NO_CRITERIA*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						*_p_bFound=TRUE;		
						return i;
					}
				}
				i--;
			}

			i=Milieu+1;
			/* we search the same names after */
			while ((i<(long)_ulListSize) && !stricmp(_p_oList[i]->fn_p_szGetName(),_NameToFind))
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Type!=NULL*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						*_p_bFound=TRUE;		
						return i;
					}
				}
				i++;
			}	

			*_p_bFound=FALSE;		
			return Bas;
		}
	};

	*_p_bFound=FALSE;		
	return Bas;
};

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchDataTypeOwner
// Low level function to find an object which has a given data, an optional type and an optional owner
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchDataTypeOwner(
								CPA_BaseObject** _p_oList, 
								unsigned long _ulListSize, 
								BOOL* _p_bFound,
								void* _data,
								char* _type,
								CPA_BaseObject* _Owner
								)
{
	unsigned long Haut=-1;
	unsigned long Bas=_ulListSize;
	unsigned long Milieu=(Haut+Bas)>>1;
	long signe;
	int i;

	/* Avoid crashes, please do not replace with ASSERT... */
	if (_p_bFound==NULL || _p_oList== NULL || ((long)_ulListSize)<=0)
		{
			if (_p_bFound!=NULL) *_p_bFound=FALSE;
			return 0;
		}


	while (Bas!=Haut+1)
	{
		signe=(long)_p_oList[Milieu]->GetData()-(long)_data;	

		if (signe<0) 
		{
		 Haut=Milieu;
		 Milieu=(Bas+Milieu)>>1;
		}
		else
		if (signe>0) 
		{
		 Bas=Milieu;
		 Milieu=(Haut+Milieu)>>1;
		}
		else
		{
			/* the data was found !*/
			/* search for type and owner if necessary*/
			i=Milieu;
			while (i>=0 && _p_oList[i]->GetData()==_data)
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Owner!=NO_CRITERIA*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						*_p_bFound=TRUE;		
						return i;
					}
				}
				i--;
			}

			i=Milieu+1;
			/* we search the same datas after */
			while ((i<(long)_ulListSize) && _p_oList[i]->GetData()==_data )
			{
				/* also test Type if _Type!=NULL*/
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					/* also test Owner if _Type!=NULL*/
					if (_Owner==NO_CRITERIA || (_p_oList[i]->GetOwner()==_Owner))
					{
						*_p_bFound=TRUE;		
						return i;
					}
				}
				i++;
			}

			*_p_bFound=FALSE;		
			return Bas;
		}
	};

	*_p_bFound=FALSE;		
	return Bas;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lDichoSearchOwnersAndTypes
// Low level function to find objects which have a given owner and a given type
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lDichoSearchOwnersAndTypes(CPA_List<CPA_BaseObject> * _p_oReturnList, CPA_BaseObject** _p_oList, unsigned long _ulListSize, BOOL* _p_bFound, CPA_BaseObject* _Owner,char* _type)
{
		int Count=0;
		BOOL CountOnly;
		int index,i;
		
		/* Avoid crashes, please do not replace with ASSERT... */
		if (_p_bFound==NULL || _Owner==NULL || _p_oList== NULL || ((long)_ulListSize)<=0)
		{
			if (_p_bFound!=NULL) *_p_bFound=FALSE;
			return 0;
		}
				
		if (_p_oReturnList==NULL) 
			CountOnly=TRUE;
		else
			CountOnly=FALSE;

		/* we search the owner in the sorted list */
 		index=fn_lDichoSearchOwner(_p_oList,_ulListSize,_Owner,_p_bFound);

		if (*_p_bFound)
		{
			
			i=index;
			/* we search the same owners before */
			while (i>=0 && _p_oList[i]->GetOwner()==_Owner )
			{
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					if (CountOnly==FALSE) _p_oReturnList->AddTail(_p_oList[i]);
					Count++;
				}
				i--;
			}

			i=index+1;

			/* we search the same owners after */
			while (i<(long)_ulListSize && _p_oList[i]->GetOwner()==_Owner)
			{
				if (!stricmp(_type,"") || !stricmp(_p_oList[i]->fn_p_szGetType(),_type))
				{
					if (CountOnly==FALSE) _p_oReturnList->AddTail(_p_oList[i]);
					Count++;
				}
				i++;
			}
		}
		if (Count==0) *_p_bFound=FALSE;

		return Count;
}


//*****************************************************************************
//**********                  Medium level functions                 **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - FindObjectWithType
// Return all the objects of the list with the given type
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::FindObjectWithType (CPA_List<CPA_BaseObject> * _p_oList , const CString _csTypeName)
{
    char * szTypeNameToFind = (char *) (LPCTSTR) _csTypeName;

    if (! m_csTypeName . IsEmpty ())                     // All objects of the list have the same type
    {
        if (m_csTypeName . CompareNoCase (_csTypeName) != 0)  return 0;    // Not the same type --> no object found

        // We just make a copy of the list
        for (long i = 0 ; i < m_lNumberOfObjects ; i ++)
            _p_oList -> AddTail (m_Array [E_lo_Edited] [i]);
        return m_lNumberOfObjects;
    }
    else                                               // Not all objects have the same type : we must check the type
    {
        long lNumberOfObjectFound = 0;

        tdp_BaseObjectPointer * pBaseObjectPointer = m_Array [E_lo_Edited];
        for (long i = m_lNumberOfObjects ; i > 0 ; i --)
        {
            if (stricmp ((* pBaseObjectPointer) -> fn_p_szGetType () , szTypeNameToFind) == 0)
            {
                _p_oList -> AddTail (* pBaseObjectPointer);

                lNumberOfObjectFound ++;
            }

            pBaseObjectPointer ++;
        }

        return lNumberOfObjectFound;
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - FindIndex
// Return the index of an object into a list with a given order
// If the object is into the list, set _bExist to TRUE and return the index
// If not, set _bExist to FALSE and return the index where to insert the object
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::FindIndex (tdeListOrder _eListOrder , CPA_BaseObject * _p_oObject , BOOL * _bExist)
{
    switch (_eListOrder)
    {
    case E_lo_Object : return fn_lDichoSearchBaseObject (m_Array [E_lo_Object] , m_lNumberOfObjects , _p_oObject                      , _bExist);
    case E_lo_Type   : return fn_lDichoSearchType       (m_Array [E_lo_Type  ] , m_lNumberOfObjects , _p_oObject -> fn_p_szGetType () , _bExist , _p_oObject);
    case E_lo_Data   : return fn_lDichoSearchData       (m_Array [E_lo_Data  ] , m_lNumberOfObjects , _p_oObject -> GetData        () , _bExist , _p_oObject);
    case E_lo_Owner  : return fn_lDichoSearchOwner      (m_Array [E_lo_Owner ] , m_lNumberOfObjects , _p_oObject -> GetOwner       () , _bExist , _p_oObject);
    case E_lo_Alpha  : return fn_lDichoSearchName       (m_Array [E_lo_Alpha ] , m_lNumberOfObjects , _p_oObject -> fn_p_szGetName () , _bExist , _p_oObject);
    default          : ASSERT (0);
                       * _bExist = FALSE;
                       return -1;
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - InsertObjectInList
// Insert the give object into the given list in the given position
// Shift the index after this position
// m_lNumberOfObjects has already been increased
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::InsertObjectInList (tdeListOrder _eListOrder , CPA_BaseObject * _p_oObject , long _lIndex)
{
    // Shift the index after _lIndex
    memmove (& m_Array [_eListOrder] [_lIndex + 1] , & m_Array [_eListOrder] [_lIndex] ,
             (m_lNumberOfObjects - _lIndex - 1) * sizeof (tdp_BaseObjectPointer));

    m_Array [_eListOrder] [_lIndex] = _p_oObject;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - RemoveObjectFromList
// Remove the given index from the given list
// Shift the index after this position
// m_lNumberOfObject has already been decreased
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::RemoveObjectFromList (tdeListOrder _eListOrder , long _lIndex)
{
    // Shift the index after _lIndex
    memmove (& m_Array [_eListOrder] [_lIndex] , & m_Array [_eListOrder] [_lIndex + 1] ,
             (m_lNumberOfObjects - _lIndex) * sizeof (tdp_BaseObjectPointer));
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - MoveIndexInList
// Move an object from one position to another inside a given list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::MoveIndexInList (tdeListOrder _eListOrder , long _lOldIndex , long _lNewIndex)
{
    tdp_BaseObjectPointer pBaseObject = m_Array [_eListOrder] [_lOldIndex];

    if (_lOldIndex < _lNewIndex)
    {
        memmove (& m_Array [_eListOrder] [_lOldIndex] , & m_Array [_eListOrder] [_lOldIndex + 1] ,
                 (_lNewIndex - _lOldIndex - 1) * sizeof (tdp_BaseObjectPointer));
        m_Array [_eListOrder] [_lNewIndex - 1] = pBaseObject;
    }
    else
    {
        memmove (& m_Array [_eListOrder] [_lNewIndex + 1] , & m_Array [_eListOrder] [_lNewIndex] ,
                 (_lOldIndex - _lNewIndex) * sizeof (tdp_BaseObjectPointer));
        m_Array [_eListOrder] [_lNewIndex] = pBaseObject;
    }
}


//*****************************************************************************
//**********                     Type management                     **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bIsOfType
// Return TRUE if the list is of the given type
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bIsOfType (const CString _csTypeName)
{
    return m_csTypeName . CompareNoCase (_csTypeName) == 0;
}


//*****************************************************************************
//**********                   Add and remove objects                **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bAddObject
// Insert an object into the list.
// If the list has a type and the object has not the same type -> ASSERT
// If the object is already in the list, return FALSE
// Else insert the object into the list and return TRUE
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bAddObject (CPA_BaseObject * _p_oObject)
{
    ASSERT (m_csTypeName . IsEmpty () || _p_oObject -> fn_bIsOfType (m_csTypeName));

    long lIndex [C_lNumberOfLists];

    for (int eListType = E_lo_First ; eListType <= E_lo_Last ; eListType ++)
    {
        BOOL bExist = FALSE;
        // For the list with non specific order, we find the index where to insert the object
        if (eListType == E_lo_Common)  lIndex [eListType] = 0;                    // Beginning of the list
        else
        if (eListType == E_lo_Edited)  lIndex [eListType] = m_lNumberOfObjects;   // End of the list
        else                           lIndex [eListType] = FindIndex ((tdeListOrder) eListType , _p_oObject , & bExist);

        // If the object is already in the list, return FALSE
        if (bExist)  return FALSE;
    }

    // Increase the size of the array and check if the array is big enough
    m_lNumberOfObjects ++;
    if (m_lNumberOfObjects > m_lMaxNumberOfObjects)
        ReallocArray ((m_lNumberOfObjects + C_lSizeIncrease - 1) / C_lSizeIncrease * C_lSizeIncrease);

    for (eListType = E_lo_First ; eListType <= E_lo_Last ; eListType ++)
    {
        // Insert the object into the list
        InsertObjectInList ((tdeListOrder) eListType , _p_oObject , lIndex [eListType]);
    }

    return TRUE;    // The object has been inserted succesfully
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bRemoveObject
// Remove an object from the list
// If the object is not into the list, return FALSE
// Else remove the object from the list and return TRUE
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bRemoveObject (CPA_BaseObject * _p_oObject)
{
    long lIndex [C_lNumberOfLists];

    for (int eListType = E_lo_First ; eListType <= E_lo_Last ; eListType ++)
    {
        BOOL bExist;
        if (eListType == E_lo_Data || eListType == E_lo_Common || eListType == E_lo_Edited )
        {   // For specific order (E_lo_Common and E_lo_Edited), dicho search does not exist
			// For data order, we cannot use dicho search because this function can be called by destructor of CPA_BaseObject,
            // and in this case, the GetData pure virtual function is no longer available
            lIndex [eListType] = GetIndexOfObject (_p_oObject , (tdeListOrder) eListType);
            bExist = lIndex [eListType] != -1;
        }
		else lIndex [eListType] = FindIndex ((tdeListOrder) eListType , _p_oObject , & bExist);

        // If the object is not in the list, return FALSE
        if (! bExist)  return FALSE;
    }

    // Decrease the size of the array
    m_lNumberOfObjects --;

    for (eListType = E_lo_First ; eListType <= E_lo_Last ; eListType ++)
    {
        // Remove the object from the list
        RemoveObjectFromList ((tdeListOrder) eListType , lIndex [eListType]);
    }

    // Check if one can decrease the maximum size of the array
    if (m_lNumberOfObjects <= m_lMaxNumberOfObjects - C_lSizeIncrease)
        ReallocArray ((m_lNumberOfObjects + C_lSizeIncrease - 1) / C_lSizeIncrease * C_lSizeIncrease);

    return TRUE;
}


//*****************************************************************************
//**********                       Get functions                     **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetObjectWithIndex
// Return the object with the given index into the given sort order
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetObjectWithIndex (long _lIndex , tdeListOrder _eListOrder)
{
    return m_Array [_eListOrder] [_lIndex];
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetIndexOfObject
// Return the index (between 0 et GetCount () - 1) of a given object
// for a specific order (must be E_lo_Common or E_lo_Edited) or for E_lo_Data
// If the object is not into the list, return -1
// Do not use this function too much, because it is slower than the others
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::GetIndexOfObject (CPA_BaseObject * _p_oObject , tdeListOrder _eListOrder)
{
    ASSERT (_eListOrder == E_lo_Common || _eListOrder == E_lo_Edited || _eListOrder == E_lo_Data);

    tdp_BaseObjectPointer * pBaseObjectPointer = m_Array [_eListOrder];
    long                    i                  = m_lNumberOfObjects;

    while (--i >= 0 && * (pBaseObjectPointer++) != _p_oObject) ;

    if (i != -1)  return m_lNumberOfObjects - i - 1;
             else return -1;
}


//*****************************************************************************
//**********                      Search functions                   **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bExist
// Return TRUE if the object is into the list
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bExist (CPA_BaseObject * _p_oObject)
{
    BOOL bExist;
    FindIndex (E_lo_Object , _p_oObject , & bExist);
    return bExist;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bExist
// Return TRUE if there is an object with the given name,
// eventually with the given type and the given owner into the list
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bExist (const CString _csObjectName ,
				                    const CString _csTypeName  /* = ""          */ ,
				                    CPA_BaseObject * _p_oOwner /* = NO_CRITERIA */)
{
    return fn_p_oFindObject (_csObjectName , _csTypeName , _p_oOwner) != NULL;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_lFindObjects
// Find object from the list, put them into _p_oList
// and return the number of found objects
//-----------------------------------------------------------------------------
long CPA_BaseObjectList::fn_lFindObjects (CPA_List<CPA_BaseObject> * _p_oList ,
					             	      const CString    _csObjectName                     ,
                                          const CString    _csTypeName   /* = ""          */ ,
					            	      CPA_BaseObject * _p_oOwner     /* = NO_CRITERIA */)
{
    if (_csObjectName . IsEmpty ())    // No name to search
    {
        if (_p_oOwner == NO_CRITERIA)  return FindObjectWithType (_p_oList , _csTypeName); // Search with the type only

        BOOL bExist;
	    return fn_lDichoSearchOwnersAndTypes (_p_oList , m_Array [E_lo_Owner] , m_lNumberOfObjects , & bExist , _p_oOwner ,
                                              (char *) (LPCTSTR) _csTypeName);
    }
    else
    {
        BOOL bExist;
        return fn_lDichoSearchNamesTypesOwners (_p_oList , m_Array [E_lo_Alpha] , m_lNumberOfObjects , & bExist ,
                                                (char *) (LPCTSTR) _csObjectName , (char *) (LPCTSTR) _csTypeName , _p_oOwner);
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_p_oFindObject
// Find an object from the list with the given name,
// eventually the given type and the given owner
// If the object is into the list, return it else return NULL
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::fn_p_oFindObject (const CString    _csObjectName ,
                                                       const CString    _csTypeName /* = ""          */ ,
                                                       CPA_BaseObject * _p_oOwner   /* = NO_CRITERIA */)
{
    ASSERT (_csObjectName && ! _csObjectName . IsEmpty ());

    BOOL bExist;
 	long lIndex = fn_lDichoSearchNameTypeOwner (m_Array [E_lo_Alpha] , m_lNumberOfObjects , & bExist ,
                                                (char *) (LPCTSTR) _csObjectName ,
                                                (char *) (LPCTSTR) _csTypeName   , _p_oOwner);

    if (bExist)  return m_Array [E_lo_Alpha] [lIndex];
            else return NULL;
}
                                                                        
//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_p_oFindObject
// Find an object from the list with the given data,
// eventually the given type and the given owner
// If the object is into the list, return it else return NULL
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::fn_p_oFindObjectWithdData (void           * _p_vData ,
                                                                const CString    _csTypeName /* = ""          */ ,
                                                                CPA_BaseObject * _p_oOwner   /* = NO_CRITERIA */)
{
    BOOL bExist;
    long lIndex = fn_lDichoSearchDataTypeOwner (m_Array [E_lo_Data] , m_lNumberOfObjects , & bExist , _p_vData ,
                                                (char *) (LPCTSTR) _csTypeName , _p_oOwner);

    if (bExist)  return m_Array [E_lo_Data] [lIndex];
            else return NULL;
}


//*****************************************************************************
//**********                        Change order                     **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vBeforeChangingObjectName
// Before changing the name of a CPA_BaseObject, one must
// call this function to reorganize the alphabetic order sorted list                                            
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vBeforeChangingObjectName (CPA_BaseObject * _p_oObject , char * _szNewName)
{
    // If old name and new name are equal, we do nothing
    if (stricmp (_p_oObject -> fn_p_szGetName () , _szNewName) == 0)  return;

    BOOL bExist;
    long lOldIndex = fn_lDichoSearchName (m_Array [E_lo_Alpha] , m_lNumberOfObjects , _p_oObject -> fn_p_szGetName () , & bExist , _p_oObject);
    ASSERT (bExist);    // The object must exist

    long lNewIndex = fn_lDichoSearchName (m_Array [E_lo_Alpha] , m_lNumberOfObjects , _szNewName , & bExist , _p_oObject);

    MoveIndexInList (E_lo_Alpha , lOldIndex , lNewIndex);
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vBeforeChangingObjectData
// Before changing the data of a CPA_BaseObject, one must
// call this function to reorganize the list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vBeforeChangingObjectData (CPA_BaseObject * _p_oObject , void * _pNewData)
{
    // If old data and new data are equal, we do nothing
    if (_p_oObject -> GetData () == _pNewData)  return;

    BOOL bExist;
    long lOldIndex = fn_lDichoSearchData (m_Array [E_lo_Data] , m_lNumberOfObjects , _p_oObject -> GetData () , & bExist , _p_oObject);
    ASSERT (bExist);    // The object must exist

    long lNewIndex = fn_lDichoSearchData (m_Array [E_lo_Data] , m_lNumberOfObjects , _pNewData , & bExist , _p_oObject);

    MoveIndexInList (E_lo_Data , lOldIndex , lNewIndex);
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vBeforeChangingObjectOwner
// Before changing the owner of a CPA_BaseObject, one must
// call this function to reorganize the list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vBeforeChangingObjectOwner (CPA_BaseObject * _p_oObject , CPA_BaseObject * _pNewOwner)
{
    // If old owner and new owner are equal, we do nothing
    if (_p_oObject -> GetOwner () == _pNewOwner)  return;

    BOOL bExist;
    long lOldIndex = fn_lDichoSearchOwner (m_Array [E_lo_Owner] , m_lNumberOfObjects , _p_oObject -> GetOwner () , & bExist , _p_oObject);
    ASSERT (bExist);    // The object must exist

    long lNewIndex = fn_lDichoSearchOwner (m_Array [E_lo_Owner] , m_lNumberOfObjects , _pNewOwner , & bExist , _p_oObject);

    MoveIndexInList (E_lo_Owner , lOldIndex , lNewIndex);
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vExchangeObjectOrder
// Exchange two objects in a specific order (must be E_lo_Common or E_lo_Edited)
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vExchangeObjectOrder (long _lIndex1 , long _lIndex2 , tdeListOrder     _eListOrder)
{
    ASSERT (_eListOrder == E_lo_Common || _eListOrder == E_lo_Edited);

    // Exchange the two pointers
    tdp_BaseObjectPointer pPointer   = m_Array [_eListOrder] [_lIndex1];
    m_Array [_eListOrder] [_lIndex1] = m_Array [_eListOrder] [_lIndex2];
    m_Array [_eListOrder] [_lIndex2] = pPointer;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vChangeObjectOrder
// Change the position in a specific order sorted list of
// an object (which must already be in the list)
// Shift objects if necessary (must be E_lo_Common or E_lo_Edited)
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vChangeObjectOrder (long _lOldIndex , long _lNewIndex , tdeListOrder  _eListOrder)
{
    ASSERT (_eListOrder == E_lo_Common || _eListOrder == E_lo_Edited);

    MoveIndexInList (_eListOrder , _lOldIndex , _lNewIndex);
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bExchangeObjectOrder
// Exchange two objects in a specific order (must be E_lo_Common or E_lo_Edited)
// If you know the index of the two objects in the list (without calling the GetIndexOfObject function),
// call the fn_vExchangeObjectOrder function which is faster
// Return FALSE if one object is not in the list, else return TRUE
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bExchangeObjectOrder (CPA_BaseObject * _p_oObject1 , CPA_BaseObject * _p_oObject2 ,
                                                  tdeListOrder     _eListOrder)
{
    long lIndex1 = GetIndexOfObject (_p_oObject1 , _eListOrder);
    long lIndex2 = GetIndexOfObject (_p_oObject2 , _eListOrder);

    if (lIndex1 == -1 || lIndex2 == -1)  return FALSE;

    fn_vExchangeObjectOrder (lIndex1 , lIndex2 , _eListOrder);
    return TRUE;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_bChangeObjectOrder
// Change the position in a specific order sorted list of an object.
// Shift objects if necessary (must be E_lo_Common or E_lo_Edited).
// If you know the old index if the object in the list (without calling the GetIndexOfObject function),
// call the fn_vChangeObjectOrder function which is faster
// Return FALSE if the object is not in the list, else return TRUE
//-----------------------------------------------------------------------------
BOOL CPA_BaseObjectList::fn_bChangeObjectOrder (CPA_BaseObject* _p_oObject , long _lNewIndex , tdeListOrder _eListOrder)
{
    long lOldIndex = GetIndexOfObject (_p_oObject , _eListOrder);
    if (lOldIndex == -1)  return FALSE;

    fn_vChangeObjectOrder (lOldIndex , _lNewIndex , _eListOrder);
    return TRUE;
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vReSortListWithAlphaOrder
// If some objects may have been renamed without calling the
// fn_vBeforeChangingObjectName function, call this function to sort the list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vReSortListWithAlphaOrder ()
{
    // We check if the list is sorted or not
    BOOL                    bListSorted        = TRUE;
    tdp_BaseObjectPointer * pBaseObjectPointer = m_Array [E_lo_Alpha];
    for (long i = 0 ; i < m_lNumberOfObjects - 1 ; i ++)
    {
        if (stricmp ((* pBaseObjectPointer) -> fn_p_szGetName () , (* (pBaseObjectPointer+1)) -> fn_p_szGetName ()) > 0)
        {
            bListSorted = FALSE;
            break;
        }

        pBaseObjectPointer ++;
    }

    // If the list is already sorted, we do nothing
    if (bListSorted)  return;

    // Else we resort the list
    for (i = 1 ; i < m_lNumberOfObjects ; i ++)
    {
        // We take the object number i
        CPA_BaseObject * pBaseObject = m_Array [E_lo_Alpha] [i];
        BOOL             bExist;
        // We find the correct index
        long lNewIndex = fn_lDichoSearchName (m_Array [E_lo_Alpha] , i , pBaseObject -> fn_p_szGetName () , & bExist , pBaseObject);

        if (lNewIndex != i)
        {
            memmove (& m_Array [E_lo_Alpha] [lNewIndex + 1] , & m_Array [E_lo_Alpha] [lNewIndex] , (i - lNewIndex) * sizeof (tdp_BaseObjectPointer));
            m_Array [E_lo_Alpha] [lNewIndex] = pBaseObject;
        }
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vReSortListWithDataOrder
// If data of some objects may have been changed without calling the
// fn_vBeforeChangingObjectData function, call this function to sort the list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vReSortListWithDataOrder ()
{
    // We check if the list is sorted or not
    BOOL                    bListSorted        = TRUE;
    tdp_BaseObjectPointer * pBaseObjectPointer = m_Array [E_lo_Data];
    for (long i = 0 ; i < m_lNumberOfObjects - 1 ; i ++)
    {
        if ((* pBaseObjectPointer) -> GetData () > (* (pBaseObjectPointer+1)) -> GetData ())
        {
            bListSorted = FALSE;
            break;
        }

        pBaseObjectPointer ++;
    }

    // If the list is already sorted, we do nothing
    if (bListSorted)  return;

    // Else we resort the list
    for (i = 1 ; i < m_lNumberOfObjects ; i ++)
    {
        // We take the object number i
        CPA_BaseObject * pBaseObject = m_Array [E_lo_Data] [i];
        BOOL             bExist;
        // We find the correct index
        long lNewIndex = fn_lDichoSearchData (m_Array [E_lo_Data] , i , pBaseObject -> GetData () , & bExist , pBaseObject);

        if (lNewIndex != i)
        {
            memmove (& m_Array [E_lo_Data] [lNewIndex + 1] , & m_Array [E_lo_Data] [lNewIndex] , (i - lNewIndex) * sizeof (tdp_BaseObjectPointer));
            m_Array [E_lo_Data] [lNewIndex] = pBaseObject;
        }
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vReSortListWithOwnerOrder
// If owner of some objects may have been changed without calling the
// fn_vBeforeChangingObjectOwner function, call this function to sort the list
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vReSortListWithOwnerOrder ()
{
    // We check if the list is sorted or not
    BOOL                    bListSorted        = TRUE;
    tdp_BaseObjectPointer * pBaseObjectPointer = m_Array [E_lo_Owner];
    for (long i = 0 ; i < m_lNumberOfObjects - 1 ; i ++)
    {
        if ((* pBaseObjectPointer) -> GetOwner () > (* (pBaseObjectPointer+1)) -> GetOwner ())
        {
            bListSorted = FALSE;
            break;
        }

        pBaseObjectPointer ++;
    }

    // If the list is already sorted, we do nothing
    if (bListSorted)  return;

    // Else we resort the list
    for (i = 1 ; i < m_lNumberOfObjects ; i ++)
    {
        // We take the object number i
        CPA_BaseObject * pBaseObject = m_Array [E_lo_Owner] [i];
        BOOL             bExist;
        // We find the correct index
        long lNewIndex = fn_lDichoSearchOwner (m_Array [E_lo_Owner] , i , pBaseObject -> GetOwner () , & bExist , pBaseObject);

        if (lNewIndex != i)
        {
            memmove (& m_Array [E_lo_Owner] [lNewIndex + 1] , & m_Array [E_lo_Owner] [lNewIndex] , (i - lNewIndex) * sizeof (tdp_BaseObjectPointer));
            m_Array [E_lo_Owner] [lNewIndex] = pBaseObject;
        }
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - fn_vReSortList
// Call the three previous functions
//-----------------------------------------------------------------------------
void CPA_BaseObjectList::fn_vReSortList ()
{
    fn_vReSortListWithAlphaOrder ();
    fn_vReSortListWithDataOrder  ();
    fn_vReSortListWithOwnerOrder ();
}


//*****************************************************************************
//**********                    To go through the list               **********
//*****************************************************************************

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetHeadElement
// Same as CPA_List::GetHeadElement
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetHeadElement (Position & _Position)
{
    if (m_lNumberOfObjects > 0)
    {
        _Position = 1;
        return m_Array [E_lo_GoThrough] [0];
    }
    else
    {
        _Position = 0;
        return NULL;
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetTailElement
// Same as CPA_List::GetTailElement
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetTailElement (Position & _Position)
{
    if (m_lNumberOfObjects > 0)
    {
        _Position = m_lNumberOfObjects;
        return m_Array [E_lo_GoThrough] [m_lNumberOfObjects - 1];
    }
    else
    {
        _Position = 0;
        return NULL;
    }
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetNextElement
// Same as CPA_List::GetNextElement
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetNextElement  (Position & _Position)
{ 
	if (!_Position)  return NULL;

	if (_Position >= m_lNumberOfObjects)
	{
		_Position = 0;
		return NULL;
	}
	
	return m_Array [E_lo_GoThrough] [_Position++];
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetPrevElement
// Same as CList::GetNex
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetPrevElement  (Position & _Position)
{ 
    if (! _Position)  return NULL;

    return m_Array [E_lo_GoThrough] [-- _Position];
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetNext
// Same as CList::GetNext
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetNext (Position & _Position)
{
    if (! _Position)  return NULL;

    Position ActualPosition = _Position;
    if (_Position < m_lNumberOfObjects)  _Position ++;
                                    else _Position = 0;

    return m_Array [E_lo_GoThrough] [ActualPosition - 1];
}

//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - GetPrev
// Same as CList::GetPrev
//-----------------------------------------------------------------------------
CPA_BaseObject * CPA_BaseObjectList::GetPrev (Position & _Position)
{
    if (! _Position)  return NULL;

    return m_Array [E_lo_GoThrough] [-- _Position];
}


//-----------------------------------------------------------------------------
// Class CPA_BaseObjectList - New Name
// Type + number
//-----------------------------------------------------------------------------
CString CPA_BaseObjectList::GetNewName (const CString csDefaultBaseName /*=""*/)
{
	CString csName;
	
	if( csDefaultBaseName == "")
	{
		ASSERT(m_csTypeName != "");
		csName.Format("%s%d",m_csTypeName,++m_lCurrentUniqueIndex);
	}
	else
	{
		csName.Format("%s%d",csDefaultBaseName,++m_lCurrentUniqueIndex);
	}

	return csName;
}

#undef stricmp

#endif  // ACTIVE_EDITOR
