/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"

#ifndef _LIMITS_H
#include <limits.h>
#endif

#ifndef _STRING_H
#include <string.h>
#endif

#ifndef _STDIO_H
#include <stdio.h>
#endif
#include <tools/solar.h>
#include <impcont.hxx>
#include <tools/contnr.hxx>
#include <tools/debug.hxx>

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

DBG_NAME( CBlock )
DBG_NAME( Container )

/*************************************************************************
|*
|*	  DbgCheckCBlock()
|*
|*	  Beschreibung		Pruefung eines CBlock fuer Debug-Utilities
|*	  Ersterstellung	MI 30.01.92
|*	  Letzte Aenderung	TH 24.01.96
|*
*************************************************************************/

#ifdef DBG_UTIL
const char* CBlock::DbgCheckCBlock( const void* pBlock )
{
	CBlock* p = (CBlock*)pBlock;

	if ( p->nCount > p->nSize )
		return "nCount > nSize";

	if ( p->nSize && !p->pNodes )
		return "nSize > 0 && pNodes == NULL";

	return NULL;
}
#endif

/*************************************************************************
|*
|*	  CBlock::CBlock()
|*
|*	  Beschreibung		Construktor des Verwaltungsblocks
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

CBlock::CBlock( sal_uInt16 nInitSize, CBlock* _pPrev, CBlock* _pNext )
{
	DBG_CTOR( CBlock, DbgCheckCBlock );

	pPrev	= _pPrev;
	pNext	= _pNext;
	nSize	= nInitSize;
	nCount	= 0;

	// Datenpuffer anlegen
	pNodes = new PVOID[nSize];
}

/*************************************************************************
|*
|*	  CBlock::CBlock()
|*
|*	  Beschreibung		Construktor des Verwaltungsblocks
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

CBlock::CBlock( sal_uInt16 _nSize, CBlock* _pPrev )
{
	DBG_CTOR( CBlock, DbgCheckCBlock );
	DBG_ASSERT( _nSize, "CBlock::CBlock(): nSize == 0" );

	pPrev	= _pPrev;
	pNext	= NULL;
	nSize	= _nSize;
	nCount	= _nSize;

	// Datenpuffer anlegen und initialisieren
	pNodes = new PVOID[nSize];
	memset( pNodes, 0, nSize*sizeof(PVOID) );
}

/*************************************************************************
|*
|*	  CBlock::CBlock()
|*
|*	  Beschreibung		Copy-Construktor des Verwaltungsblocks
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

CBlock::CBlock( const CBlock& r, CBlock* _pPrev )
{
	DBG_CTOR( CBlock, DbgCheckCBlock );
	DBG_CHKOBJ( &r, CBlock, DbgCheckCBlock );

	pPrev	= _pPrev;
	pNext	= NULL;
	nSize	= r.nSize;
	nCount	= r.nCount;

	// Datenpuffer anlegen und Daten kopieren
	pNodes = new PVOID[nSize];
	memcpy( pNodes, r.pNodes, nCount*sizeof(PVOID) );
}

/*************************************************************************
|*
|*	  CBlock::~CBlock()
|*
|*	  Beschreibung		Destruktor des Verwaltungsblocks
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

inline CBlock::~CBlock()
{
	DBG_DTOR( CBlock, DbgCheckCBlock );

	// Daten loeschen
	delete[] pNodes;
}

/*************************************************************************
|*
|*	  CBlock::Insert()
|*
|*	  Beschreibung		Fuegt einen Pointer ein
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void CBlock::Insert( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );
	DBG_ASSERT( nIndex <= nCount, "CBlock::Insert(): Index > nCount" );

	// Muss Block realokiert werden
	if ( nCount == nSize )
	{
		// Neue Daten anlegen
        nSize = nSize + nReSize;    // MSVC warns here if += is used
		void** pNewNodes = new PVOID[nSize];

		// Wird angehaengt
		if ( nCount == nIndex )
		{
			// Daten kopieren
			memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
		}
		else
		{
			// Daten kopieren
			memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
			memcpy( pNewNodes + nIndex + 1,
					pNodes + nIndex,
					(nCount-nIndex)*sizeof(PVOID) );
		}

		// Alte Daten loeschen und neue setzen
		delete[] pNodes;
		pNodes = pNewNodes;
	}
	else
	{
		if ( nIndex < nCount )
		{
			memmove( pNodes + nIndex + 1,
					 pNodes + nIndex,
					 (nCount-nIndex)*sizeof(PVOID) );
		}
	}

	// Neuen Pointer setzen und Elementgroesse erhoehen
	pNodes[nIndex] = p;
	nCount++;
}

/*************************************************************************
|*
|*	  CBlock::Split()
|*
|*	  Beschreibung		Fuegt einen Pointer ein und splittet den Block
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

CBlock* CBlock::Split( void* p, sal_uInt16 nIndex, sal_uInt16 nReSize )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );

	sal_uInt16	nNewSize;
	sal_uInt16	nMiddle;
	CBlock* pNewBlock;

	nMiddle = nCount/2;

	if ( ( nIndex == nCount ) || ( nIndex == 0 ) )
		nNewSize = nReSize;
	else
	{
		// Der aktuelle Block wird in der Mitte geteilt
		nNewSize = (nCount+1) / 2;

		if ( nNewSize < nReSize )
			nNewSize = nReSize;
		else
		{
			// Neue Groesse muss ein vielfaches von Resize sein
			if ( nNewSize % nReSize )
				nNewSize += nReSize - (nNewSize % nReSize);
			else
                nNewSize = nNewSize + nReSize;  // MSVC warns here if += is used
		}
	}

	// Vor oder hinter dem aktuellem Block einfuegen?
	if ( nIndex > nMiddle )
	{
		// Neuen Split-Block anlegen und hinter dem aktuellem Block einfuegen
		pNewBlock = new CBlock( nNewSize, this, pNext );

		if ( pNext )
			pNext->pPrev = pNewBlock;
		pNext = pNewBlock;

		if ( nIndex == nCount )
		{
			// Neuen Pointer einfuegen
			pNewBlock->pNodes[0] = p;
			pNewBlock->nCount = 1;
		}
		else
		{
            nIndex = nIndex - nMiddle;  // MSVC warns here if += is used
			// Alles von Mitte bis Index kopieren
			if ( nIndex )
				memcpy( pNewBlock->pNodes, pNodes+nMiddle, nIndex*sizeof(PVOID) );

			// Neuen Pointer einfuegen
			pNewBlock->pNodes[nIndex] = p;

			// Alles von Mitte bis Ende hinter Index kopieren
			memcpy( pNewBlock->pNodes+nIndex+1,
					pNodes+nMiddle+nIndex,
					(nCount-nMiddle-nIndex) * sizeof(PVOID) );

			pNewBlock->nCount = (nCount-nMiddle+1);
			nCount = nMiddle;

			// Den aktuellen Datenbereich auch halbieren
			if ( nSize != nNewSize )
			{
				void** pNewNodes = new PVOID[nNewSize];
				memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
				delete[] pNodes;
				pNodes = pNewNodes;
				nSize = nNewSize;
			}
		}
	}
	else
	{
		// Neuen Split-Block anlegen und vor dem aktuellem Block einfuegen
		pNewBlock = new CBlock( nNewSize, pPrev, this );

		if ( pPrev )
			pPrev->pNext = pNewBlock;
		pPrev = pNewBlock;

		if ( nIndex == 0 )
		{
			// Neuen Pointer einfuegen
			pNewBlock->pNodes[0] = p;
			pNewBlock->nCount = 1;
		}
		else
		{
			// Alles von Anfang bis Index kopieren
			memcpy( pNewBlock->pNodes, pNodes, nIndex*sizeof(PVOID) );

			// Neuen Pointer einfuegen
			pNewBlock->pNodes[nIndex] = p;

			// Alles von Index bis Mitte hinter Index kopieren
			if ( nIndex != nMiddle )
			{
				memcpy( pNewBlock->pNodes+nIndex+1,
						pNodes+nIndex,
						(nMiddle-nIndex) * sizeof(PVOID) );
			}

			pNewBlock->nCount = nMiddle+1;
            nCount = nCount - nMiddle;  // MSVC warns here if += is used

			// Die zweite Haelfte in einen neuen Block kopieren
			if ( nSize != nNewSize )
			{
				void** pNewNodes = new PVOID[nNewSize];
				memcpy( pNewNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
				delete[] pNodes;
				pNodes = pNewNodes;
				nSize = nNewSize;
			}
			else
				memmove( pNodes, pNodes+nMiddle, nCount*sizeof(PVOID) );
		}
	}

	// Neu angelegten Block zurueckgeben, da gegebenfalls die Blockpointer
	// im Container angepast werden koennen
	return pNewBlock;
}

/*************************************************************************
|*
|*	  CBlock::Remove()
|*
|*	  Beschreibung		Entfernt einen Pointer
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* CBlock::Remove( sal_uInt16 nIndex, sal_uInt16 nReSize )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );

	// Alten Pointer sichern
	void* pOld = pNodes[nIndex];

	// 1 Element weniger
	nCount--;

	// Block verkleinern (wenn Reallokationsgroesse um 4 unterschritten wird)
	if ( nCount == (nSize-nReSize-4) )
	{
		// Neue Daten anlegen
        nSize = nSize - nReSize;    // MSVC warns here if += is used
		void** pNewNodes = new PVOID[nSize];

		// Wird letzter Eintrag geloescht
		if ( nIndex == nCount )
		{
			// Daten kopieren
			memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );
		}
		else
		{
			// Daten kopieren
			memcpy( pNewNodes, pNodes, nIndex*sizeof(PVOID) );
			memcpy( pNewNodes + nIndex, pNodes + nIndex+1,
					(nCount-nIndex)*sizeof(PVOID) );
		}

		// Alte Daten loeschen und neue setzen
		delete[] pNodes;
		pNodes = pNewNodes;
	}
	else
	{
		// Wenn nicht das letzte Element, dann zusammenschieben
		if ( nIndex < nCount )
		{
			memmove( pNodes + nIndex, pNodes + nIndex + 1,
					 (nCount-nIndex)*sizeof(PVOID) );
		}
	}

	// Alten Pointer zurueckgeben
	return pOld;
}

/*************************************************************************
|*
|*	  CBlock::Replace()
|*
|*	  Beschreibung		Ersetzt einen Pointer
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

inline void* CBlock::Replace( void* p, sal_uInt16 nIndex )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );

	// Alten Pointer sichern, neuen setzen und alten zurueckgeben
	void* pOld = pNodes[nIndex];
	pNodes[nIndex] = p;
	return pOld;
}

/*************************************************************************
|*
|*	  CBlock::GetObjectPtr()
|*
|*	  Beschreibung		Gibt einen Pointer auf den Pointer aus dem Block
|*						zurueck
|*	  Ersterstellung	TH 26.01.93
|*	  Letzte Aenderung	TH 26.01.93
|*
*************************************************************************/

inline void** CBlock::GetObjectPtr( sal_uInt16 nIndex )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );

	return &(pNodes[nIndex]);
}

/*************************************************************************
|*
|*	  CBlock::SetSize()
|*
|*	  Beschreibung		Aendert die Groesse des Blocks
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void CBlock::SetSize( sal_uInt16 nNewSize )
{
	DBG_CHKTHIS( CBlock, DbgCheckCBlock );
	DBG_ASSERT( nNewSize, "CBlock::SetSize(): nNewSize == 0" );

	// Unterscheidet sich die Groesse
	if ( nNewSize != nCount )
	{
		// Array erweitern
		void** pNewNodes = new PVOID[nNewSize];

		// Alte Tabelle in die Neue kopieren
		if ( nNewSize < nCount )
			memcpy( pNewNodes, pNodes, nNewSize*sizeof(PVOID) );
		else
		{
			memcpy( pNewNodes, pNodes, nCount*sizeof(PVOID) );

			// Array mit 0 initialisieren
			memset( pNewNodes+nCount, 0, (nNewSize-nCount)*sizeof(PVOID) );
		}

		// Altes Array loeschen und neue Werte setzen
		nSize  = nNewSize;
		nCount = nSize;
		delete[] pNodes;
		pNodes = pNewNodes;
	}
}

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

/*************************************************************************
|*
|*	  DbgCheckContainer()
|*
|*	  Beschreibung		Pruefung eines Container fuer Debug-Utilities
|*	  Ersterstellung	MI 30.01.92
|*	  Letzte Aenderung	TH 24.01.96
|*
*************************************************************************/

#ifdef DBG_UTIL
const char* Container::DbgCheckContainer( const void* pCont )
{
	Container* p = (Container*)pCont;

	if ( p->nCount && (!p->pFirstBlock || !p->pLastBlock || !p->pCurBlock) )
		return "nCount > 0 but no CBlocks";

	return NULL;
}
#endif

/*************************************************************************
|*
|*	  ImpCopyContainer()
|*
|*	  Beschreibung		Kopiert alle Daten des Containers
|*	  Ersterstellung	TH 24.01.96
|*	  Letzte Aenderung	TH 24.01.96
|*
*************************************************************************/

void Container::ImpCopyContainer( const Container* pCont2 )
{
	// Werte vom uebergebenen Container uebernehmen
	nCount	   = pCont2->nCount;
	nCurIndex  = pCont2->nCurIndex;
	nInitSize  = pCont2->nInitSize;
	nReSize    = pCont2->nReSize;
	nBlockSize = pCont2->nBlockSize;

	// Alle Bloecke kopieren
	if ( pCont2->nCount )
	{
		CBlock* pBlock1;
		CBlock* pBlock2;
		CBlock* pTempBlock;

		// Erstmal ersten Block kopieren
		pBlock2 = pCont2->pFirstBlock;
		pFirstBlock = new CBlock( *pBlock2, NULL );
		// Ist erster Block der Current-Block, dann Current-Block setzen
		if ( pBlock2 == pCont2->pCurBlock )
			pCurBlock = pFirstBlock;
		pBlock1 = pFirstBlock;
		pBlock2 = pBlock2->GetNextBlock();
		while ( pBlock2 )
		{
			// Neuen Block anlegen und aus der uebergebenen Liste kopieren
			pTempBlock = new CBlock( *pBlock2, pBlock1 );
			pBlock1->SetNextBlock( pTempBlock );
			pBlock1 = pTempBlock;

			// Current-Block beruecksichtigen
			if ( pBlock2 == pCont2->pCurBlock )
				pCurBlock = pBlock1;

			// Auf naechsten Block weitersetzen
			pBlock2 = pBlock2->GetNextBlock();
		}

		// Letzten Block setzen
		pLastBlock = pBlock1;
	}
	else
	{
		pFirstBlock = NULL;
		pLastBlock	= NULL;
		pCurBlock	= NULL;
	}
}

/*************************************************************************
|*
|*	  Container::Container()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

Container::Container( sal_uInt16 _nBlockSize, sal_uInt16 _nInitSize, sal_uInt16 _nReSize )
{
	DBG_CTOR( Container, DbgCheckContainer );

	// BlockSize muss mindestens 4 sein und kleiner als 64 KB
	if ( _nBlockSize < 4 )
		nBlockSize = 4;
	else
	{
		if ( _nBlockSize < CONTAINER_MAXBLOCKSIZE )
			nBlockSize = _nBlockSize;
		else
			nBlockSize = CONTAINER_MAXBLOCKSIZE;
	}

	// ReSize muss mindestens 2 sein und kleiner als BlockSize
	if ( _nReSize >= nBlockSize )
		nReSize = nBlockSize;
	else
	{
		if ( _nReSize < 2 )
			nReSize = 2;
		else
			nReSize = _nReSize;

		// BlockSize muss ein vielfaches der Resizegroesse sein
		if ( nBlockSize % nReSize )
			nBlockSize -= nReSize - (nBlockSize % nReSize);
	}

	// InitSize muss groesser gleich ReSize sein und kleiner als BlockSize
	if ( _nInitSize <= nReSize )
		nInitSize = nReSize;
	else
	{
		if ( _nInitSize >= nBlockSize )
			nInitSize = nBlockSize;
		else
		{
			nInitSize = _nInitSize;

			// InitSize muss ein vielfaches der Resizegroesse sein
			if ( nInitSize % nReSize )
				nInitSize -= nReSize - (nInitSize % nReSize);
		}
	}

	// Werte initialisieren
	pFirstBlock = NULL;
	pLastBlock	= NULL;
	pCurBlock	= NULL;
	nCount		= 0;
	nCurIndex	= 0;
}

/*************************************************************************
|*
|*	  Container::Container()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

Container::Container( sal_uIntPtr nSize )
{
	DBG_CTOR( Container, DbgCheckContainer );

	nCount	   = nSize;
	nCurIndex  = 0;
	nBlockSize = CONTAINER_MAXBLOCKSIZE;
	nInitSize  = 1;
	nReSize    = 1;

	if ( !nSize )
	{
		pFirstBlock = NULL;
		pLastBlock	= NULL;
		pCurBlock	= NULL;
	}
	else
	{
		// Muss mehr als ein Block angelegt werden
		if ( nSize <= nBlockSize )
		{
			pFirstBlock = new CBlock( (sal_uInt16)nSize, NULL );
			pLastBlock = pFirstBlock;
		}
		else
		{
			CBlock* pBlock1;
			CBlock* pBlock2;

			pFirstBlock = new CBlock( nBlockSize, NULL );
			pBlock1 = pFirstBlock;
			nSize -= nBlockSize;

			// Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
			while ( nSize > nBlockSize )
			{
				pBlock2 = new CBlock( nBlockSize, pBlock1 );
				pBlock1->SetNextBlock( pBlock2 );
				pBlock1 = pBlock2;
				nSize -= nBlockSize;
			}

			pLastBlock = new CBlock( (sal_uInt16)nSize, pBlock1 );
			pBlock1->SetNextBlock( pLastBlock );
		}

		pCurBlock  = pFirstBlock;
	}
}

/*************************************************************************
|*
|*	  Container::Container()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

Container::Container( const Container& r )
{
	DBG_CTOR( Container, DbgCheckContainer );

	// Daten kopieren
	ImpCopyContainer( &r );
}

/*************************************************************************
|*
|*	  Container::~Container()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

Container::~Container()
{
	DBG_DTOR( Container, DbgCheckContainer );

	// Alle Bloecke loeschen
	CBlock* pBlock = pFirstBlock;
	while ( pBlock )
	{
		CBlock* pTemp = pBlock->GetNextBlock();
		delete pBlock;
		pBlock = pTemp;
	}
}

/*************************************************************************
|*
|*	  Container::ImpInsert()
|*
|*	  Beschreibung		Interne Methode zum Einfuegen eines Pointers
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	DV 01.07.97
|*
*************************************************************************/

void Container::ImpInsert( void* p, CBlock* pBlock, sal_uInt16 nIndex )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	if ( !nCount )
	{
		if ( !pBlock )
		{
			pFirstBlock = new CBlock( nInitSize, NULL, NULL );
			pLastBlock	= pFirstBlock;
			pCurBlock	= pFirstBlock;
		}
		pFirstBlock->Insert( p, nIndex, nReSize );
	}
	else
	{
		// Ist im Block die maximale Blockgroesse erreicht,
		// dann neuen Block anlegen
		if ( pBlock->Count() == nBlockSize )
		{
			// Block auftrennen
			CBlock* pNewBlock = pBlock->Split( p, nIndex, nReSize );

			// Wurde Block dahinter angehaegnt
			if ( pBlock->pNext == pNewBlock )
			{
				// Gegebenenfalls LastBlock anpassen
				if ( pBlock == pLastBlock )
					pLastBlock = pNewBlock;

				// Current-Position nachfuehren
				if ( pBlock == pCurBlock )
				{
					if ( pBlock->nCount <= nCurIndex )
					{
						if ( nIndex <= nCurIndex )
							nCurIndex++;
						pCurBlock  = pNewBlock;
                        nCurIndex = nCurIndex - pBlock->nCount; // MSVC warns here if += is used
					}
				}
			}
			else
			{
				// Gegebenenfalls FirstBlock anpassen
				if ( pBlock == pFirstBlock )
					pFirstBlock = pNewBlock;

				// Current-Position nachfuehren
				if ( pBlock == pCurBlock )
				{
					if ( nIndex <= nCurIndex )
						nCurIndex++;
					if ( pNewBlock->nCount <= nCurIndex )
                        nCurIndex = nCurIndex - pNewBlock->nCount;  // MSVC warns here if += is used
					else
						pCurBlock = pNewBlock;
				}
			}
		}
		else
		{
			// Sonst reicht normales einfuegen in den Block
			pBlock->Insert( p, nIndex, nReSize );

			// Current-Position nachfuehren
			if ( (pBlock == pCurBlock) && (nIndex <= nCurIndex) )
				nCurIndex++;
		}
	}

	// Ein neues Item im Container
	nCount++;
}

/*************************************************************************
|*
|*	  Container::Insert()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void Container::Insert( void* p )
{
	ImpInsert( p, pCurBlock, nCurIndex );
}

/*************************************************************************
|*
|*	  Container::Insert()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void Container::Insert( void* p, sal_uIntPtr nIndex )
{
	if ( nCount <= nIndex )
	{
		if ( pLastBlock )
			ImpInsert( p, pLastBlock, pLastBlock->Count() );
		else
			ImpInsert( p, NULL, 0 );
	}
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() < nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		ImpInsert( p, pTemp, (sal_uInt16)nIndex );
	}
}

/*************************************************************************
|*
|*	  Container::Insert()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void Container::Insert( void* pNew, void* pOld )
{
	sal_uIntPtr nIndex = GetPos( pOld );
	if ( nIndex != CONTAINER_ENTRY_NOTFOUND )
		Insert( pNew, nIndex );
}

/*************************************************************************
|*
|*	  Container::ImpRemove()
|*
|*	  Beschreibung		Interne Methode zum Entfernen eines Pointers
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::ImpRemove( CBlock* pBlock, sal_uInt16 nIndex )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	void* pOld;

	// Ist Liste danach leer
	if ( nCount == 1 )
	{
		// Block und CurIndex zuruecksetzen
		pOld = pBlock->GetObject( nIndex );
		pBlock->Reset();
		nCurIndex = 0;
	}
	else
	{
		// Ist Block nach Remove leer
		if ( pBlock->Count() == 1 )
		{
			// dann Block entfernen und Block-Pointer umsetzen
			if ( pBlock->GetPrevBlock() )
				(pBlock->GetPrevBlock())->SetNextBlock( pBlock->GetNextBlock() );
			else
				pFirstBlock = pBlock->GetNextBlock();

			if ( pBlock->GetNextBlock() )
				(pBlock->GetNextBlock())->SetPrevBlock( pBlock->GetPrevBlock() );
			else
				pLastBlock = pBlock->GetPrevBlock();

			// Current-Position nachfuehren
			if ( pBlock == pCurBlock )
			{
				if ( pBlock->GetNextBlock() )
				{
					pCurBlock = pBlock->GetNextBlock();
					nCurIndex = 0;
				}
				else
				{
					pCurBlock = pBlock->GetPrevBlock();
					nCurIndex = pCurBlock->Count()-1;
				}
			}

			pOld = pBlock->GetObject( nIndex );
			delete pBlock;
		}
		else
		{
			// Sonst Item aus dem Block entfernen
			pOld = pBlock->Remove( nIndex, nReSize );

			// Current-Position nachfuehren
			if ( (pBlock == pCurBlock) &&
				 ((nIndex < nCurIndex) || ((nCurIndex == pBlock->Count()) && nCurIndex)) )
				nCurIndex--;
		}
	}

	// Jetzt gibt es ein Item weniger
	nCount--;

	// Und den Pointer zurueckgeben, der entfernt wurde
	return pOld;
}

/*************************************************************************
|*
|*	  Container::Remove()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Remove()
{
	// Wenn kein Item vorhanden ist, NULL zurueckgeben
	if ( !nCount )
		return NULL;
	else
		return ImpRemove( pCurBlock, nCurIndex );
}

/*************************************************************************
|*
|*	  Container::Remove()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Remove( sal_uIntPtr nIndex )
{
	// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
	if ( nCount <= nIndex )
		return NULL;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() <= nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		return ImpRemove( pTemp, (sal_uInt16)nIndex );
	}
}

/*************************************************************************
|*
|*	  Container::Replace()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Replace( void* p )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	if ( !nCount )
		return NULL;
	else
		return pCurBlock->Replace( p, nCurIndex );
}

/*************************************************************************
|*
|*	  Container::Replace()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Replace( void* p, sal_uIntPtr nIndex )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
	if ( nCount <= nIndex )
		return NULL;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() <= nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		return pTemp->Replace( p, (sal_uInt16)nIndex );
	}
}

/*************************************************************************
|*
|*	  Container::SetSize()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void Container::SetSize( sal_uIntPtr nNewSize )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	if ( nNewSize )
	{
		// Unterscheiden sich die Groessen
		if ( nNewSize != nCount )
		{
			CBlock* pTemp;
			sal_uIntPtr	nTemp;

			// Wird verkleinert
			if ( nNewSize < nCount )
			{
				pTemp = pFirstBlock;
				nTemp = 0;
				while ( (nTemp+pTemp->Count()) < nNewSize )
				{
					nTemp += pTemp->Count();
					pTemp  = pTemp->GetNextBlock();
				}

				// Alle folgenden Bloecke loeschen
				sal_Bool	bLast = sal_False;
				CBlock* pDelNext;
				CBlock* pDelBlock = pTemp->GetNextBlock();
				while ( pDelBlock )
				{
					// Muss CurrentBlock umgesetzt werden
					if ( pDelBlock == pCurBlock )
						bLast = sal_True;
					pDelNext = pDelBlock->GetNextBlock();
					delete pDelBlock;
					pDelBlock = pDelNext;
				}

				// Block in der Groesse anpassen, oder bei Groesse 0 loeschen
				if ( nNewSize > nTemp )
				{
					pLastBlock = pTemp;
					pTemp->SetNextBlock( NULL );
					pTemp->SetSize( (sal_uInt16)(nNewSize-nTemp) );
				}
				else
				{
					pLastBlock = pTemp->GetPrevBlock();
					pLastBlock->SetNextBlock( NULL );
					delete pTemp;
				}

				nCount = nNewSize;
				if ( bLast )
				{
					pCurBlock = pLastBlock;
					nCurIndex = pCurBlock->Count()-1;
				}
			}
			else
			{
				// Auf den letzen Puffer setzen
				pTemp = pLastBlock;
				nTemp = nNewSize - nCount;

				if ( !pTemp )
				{
					// Muss mehr als ein Block angelegt werden
					if ( nNewSize <= nBlockSize )
					{
						pFirstBlock = new CBlock( (sal_uInt16)nNewSize, NULL );
						pLastBlock = pFirstBlock;
					}
					else
					{
						CBlock* pBlock1;
						CBlock* pBlock2;

						pFirstBlock = new CBlock( nBlockSize, NULL );
						pBlock1 = pFirstBlock;
						nNewSize -= nBlockSize;

						// Solange die Blockgroesse ueberschritten wird, neue Bloecke anlegen
						while ( nNewSize > nBlockSize )
						{
							pBlock2 = new CBlock( nBlockSize, pBlock1 );
							pBlock1->SetNextBlock( pBlock2 );
							pBlock1 = pBlock2;
							nNewSize -= nBlockSize;
						}

						pLastBlock = new CBlock( (sal_uInt16)nNewSize, pBlock1 );
						pBlock1->SetNextBlock( pLastBlock );
					}

					pCurBlock  = pFirstBlock;
				}
				// Reicht es, den letzen Puffer in der Groesse anzupassen
				else if ( (nTemp+pTemp->Count()) <= nBlockSize )
					pTemp->SetSize( (sal_uInt16)(nTemp+pTemp->Count()) );
				else
				{
					// Puffer auf max. Blockgroesse setzen
					nTemp -= nBlockSize - pTemp->GetSize();
					pTemp->SetSize( nBlockSize );

					CBlock* pTemp2;
					// Solange die Blockgroesse ueberschritten wird,
					// neue Bloecke anlegen
					while ( nTemp > nBlockSize )
					{
						pTemp2 = new CBlock( nBlockSize, pTemp );
						pTemp->SetNextBlock( pTemp2 );
						pTemp = pTemp2;
						nTemp -= nBlockSize;
					}

					// Den letzten Block anlegen
					if ( nTemp )
					{
						pLastBlock = new CBlock( (sal_uInt16)nTemp, pTemp );
						pTemp->SetNextBlock( pLastBlock );
					}
					else
						pLastBlock = pTemp;
				}

				nCount = nNewSize;
			}
		}
	}
	else
		Clear();
}

/*************************************************************************
|*
|*	  Container::Clear()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void Container::Clear()
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Erst alle Bloecke loeschen
	CBlock* pBlock = pFirstBlock;
	while ( pBlock )
	{
		CBlock* pTemp = pBlock->GetNextBlock();
		delete pBlock;
		pBlock = pTemp;
	}

	// Werte zuruecksetzen
	pFirstBlock = NULL;
	pLastBlock	= NULL;
	pCurBlock	= NULL;
	nCount		= 0;
	nCurIndex	= 0;
}

/*************************************************************************
|*
|*	  Container::GetCurObject()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::GetCurObject() const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// NULL, wenn Container leer
	if ( !nCount )
		return NULL;
	else
		return pCurBlock->GetObject( nCurIndex );
}

/*************************************************************************
|*
|*	  Container::GetCurPos()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

sal_uIntPtr Container::GetCurPos() const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// CONTAINER_ENTRY_NOTFOUND, wenn Container leer
	if ( !nCount )
		return CONTAINER_ENTRY_NOTFOUND;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		sal_uIntPtr	nTemp = 0;
		while ( pTemp != pCurBlock )
		{
			nTemp += pTemp->Count();
			pTemp  = pTemp->GetNextBlock();
		}

		return nTemp+nCurIndex;
	}
}

/*************************************************************************
|*
|*	  Container::GetObjectPtr()
|*
|*	  Beschreibung		Interne Methode fuer Referenz-Container
|*	  Ersterstellung	TH 26.01.93
|*	  Letzte Aenderung	TH 26.01.93
|*
*************************************************************************/

void** Container::GetObjectPtr( sal_uIntPtr nIndex )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
	if ( nCount <= nIndex )
		return NULL;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() <= nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		// Item innerhalb des gefundenen Blocks zurueckgeben
		return pTemp->GetObjectPtr( (sal_uInt16)nIndex );
	}
}

/*************************************************************************
|*
|*	  Container::GetObject()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::GetObject( sal_uIntPtr nIndex ) const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Index nicht innerhalb des Containers, dann NULL zurueckgeben
	if ( nCount <= nIndex )
		return NULL;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() <= nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		// Item innerhalb des gefundenen Blocks zurueckgeben
		return pTemp->GetObject( (sal_uInt16)nIndex );
	}
}

/*************************************************************************
|*
|*	  Container::GetPos()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

sal_uIntPtr Container::GetPos( const void* p ) const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	void**	pNodes;
	CBlock* pTemp;
	sal_uIntPtr	nTemp;
	sal_uInt16	nBlockCount;
	sal_uInt16	i;

	// Block suchen
	pTemp = pFirstBlock;
	nTemp = 0;
	while ( pTemp )
	{
		pNodes = pTemp->GetNodes();
		i = 0;
		nBlockCount = pTemp->Count();
		while ( i < nBlockCount )
		{
			if ( p == *pNodes )
				return nTemp+i;
			pNodes++;
			i++;
		}
		nTemp += nBlockCount;
		pTemp  = pTemp->GetNextBlock();
	}

	return CONTAINER_ENTRY_NOTFOUND;
}

/*************************************************************************
|*
|*	  Container::GetPos()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 14.09.94
|*	  Letzte Aenderung	TH 14.09.94
|*
*************************************************************************/

sal_uIntPtr Container::GetPos( const void* p, sal_uIntPtr nStartIndex,
						 sal_Bool bForward ) const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Index nicht innerhalb des Containers, dann NOTFOUND zurueckgeben
	if ( nCount <= nStartIndex )
		return CONTAINER_ENTRY_NOTFOUND;
	else
	{
		void**	pNodes;
		sal_uInt16	nBlockCount;
		sal_uInt16	i;

		// Block suchen
		CBlock* pTemp = pFirstBlock;
		sal_uIntPtr	nTemp = 0;
		while ( nTemp+pTemp->Count() <= nStartIndex )
		{
			nTemp += pTemp->Count();
			pTemp  = pTemp->GetNextBlock();
		}

		// Jetzt den Pointer suchen
		if ( bForward )
		{
			// Alle Bloecke durchrsuchen
			i = (sal_uInt16)(nStartIndex - nTemp);
			pNodes = pTemp->GetObjectPtr( i );
			do
			{
				nBlockCount = pTemp->Count();
				while ( i < nBlockCount )
				{
					if ( p == *pNodes )
						return nTemp+i;
					pNodes++;
					i++;
				}
				nTemp += nBlockCount;
				pTemp  = pTemp->GetNextBlock();
				if ( pTemp )
				{
					i = 0;
					pNodes = pTemp->GetNodes();
				}
				else
					break;
			}
			while ( sal_True );
		}
		else
		{
			// Alle Bloecke durchrsuchen
			i = (sal_uInt16)(nStartIndex-nTemp)+1;
			pNodes = pTemp->GetObjectPtr( i-1 );
			do
			{
				do
				{
					if ( p == *pNodes )
						return nTemp+i-1;
					pNodes--;
					i--;
				}
				while ( i );
				nTemp -= pTemp->Count();
				pTemp  = pTemp->GetPrevBlock();
				if ( pTemp )
				{
					i = pTemp->Count();
					// Leere Bloecke in der Kette darf es nicht geben. Nur
					// wenn ein Block existiert, darf dieser leer sein
					pNodes = pTemp->GetObjectPtr( i-1 );
				}
				else
					break;
			}
			while ( sal_True );
		}
	}

	return CONTAINER_ENTRY_NOTFOUND;
}

/*************************************************************************
|*
|*	  Container::Seek()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Seek( sal_uIntPtr nIndex )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist der Container leer, dann NULL zurueckgeben
	if ( nCount <= nIndex )
		return NULL;
	else
	{
		// Block suchen
		CBlock* pTemp = pFirstBlock;
		while ( pTemp->Count() <= nIndex )
		{
			nIndex -= pTemp->Count();
			pTemp	= pTemp->GetNextBlock();
		}

		// Item innerhalb des gefundenen Blocks zurueckgeben
		pCurBlock = pTemp;
		nCurIndex = (sal_uInt16)nIndex;
		return pCurBlock->GetObject( nCurIndex );
	}
}

/*************************************************************************
|*
|*	  Container::First()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::First()
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Container leer, dann NULL zurueckgeben
	if ( !nCount )
		return NULL;
	else
	{
		// Block und Index setzen und ersten Pointer zurueckgeben
		pCurBlock = pFirstBlock;
		nCurIndex = 0;
		return pCurBlock->GetObject( nCurIndex );
	}
}

/*************************************************************************
|*
|*	  Container::Last()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Last()
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Container leer, dann NULL zurueckgeben
	if ( !nCount )
		return NULL;
	else
	{
		// Block und Index setzen und ersten Pointer zurueckgeben
		pCurBlock = pLastBlock;
		nCurIndex = pCurBlock->Count()-1;
		return pCurBlock->GetObject( nCurIndex );
	}
}

/*************************************************************************
|*
|*	  Container::Next()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Next()
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
	// naechste Position noch im aktuellen Block ist. Falls nicht, dann
	// einen Block weiterschalten (geht ohne Gefahr, da leere Bloecke
	// nicht vorkommen duerfen, es sein denn, es ist der einzige).
	if ( !nCount )
		return NULL;
	else if ( (nCurIndex+1) < pCurBlock->Count() )
		return pCurBlock->GetObject( ++nCurIndex );
	else if ( pCurBlock->GetNextBlock() )
	{
		pCurBlock = pCurBlock->GetNextBlock();
		nCurIndex = 0;
		return pCurBlock->GetObject( nCurIndex );
	}
	else
		return NULL;
}

/*************************************************************************
|*
|*	  Container::Prev()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

void* Container::Prev()
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Ist Container leer, dann NULL zurueckgeben, ansonsten preufen ob
	// vorherige Position noch im aktuellen Block ist. Falls nicht, dann
	// einen Block zurueckschalten (geht ohne Gefahr, da leere Bloecke
	// nicht vorkommen duerfen, es sein denn, es ist der einzige).
	if ( !nCount )
		return NULL;
	else if ( nCurIndex )
		return pCurBlock->GetObject( --nCurIndex );
	else if ( pCurBlock->GetPrevBlock() )
	{
		pCurBlock = pCurBlock->GetPrevBlock();
		nCurIndex = pCurBlock->Count() - 1;
		return pCurBlock->GetObject( nCurIndex );
	}
	else
		return NULL;
}

/*************************************************************************
|*
|*	  Container::operator =()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

Container& Container::operator =( const Container& r )
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	// Erst alle Bloecke loeschen
	CBlock* pBlock = pFirstBlock;
	while ( pBlock )
	{
		CBlock* pTemp = pBlock->GetNextBlock();
		delete pBlock;
		pBlock = pTemp;
	}

	// Daten kopieren
	ImpCopyContainer( &r );
	return *this;
}

/*************************************************************************
|*
|*	  Container::operator ==()
|*
|*	  Beschreibung		CONTNR.SDW
|*	  Ersterstellung	TH 17.09.91
|*	  Letzte Aenderung	TH 17.09.91
|*
*************************************************************************/

sal_Bool Container::operator ==( const Container& r ) const
{
	DBG_CHKTHIS( Container, DbgCheckContainer );

	if ( nCount != r.nCount )
		return sal_False;

	sal_uIntPtr i = 0;
	while ( i < nCount )
	{
		if ( GetObject( i ) != r.GetObject( i ) )
			return sal_False;
		i++;
	}

	return sal_True;
}
