/**************************************************************
 * 
 * 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_svl.hxx"

#include <string.h>
#include <stdio.h>
#ifndef GCC
#endif

#include <svl/itempool.hxx>
#include "whassert.hxx"
#include <svl/brdcst.hxx>
#include <svl/smplhint.hxx>
#include "poolio.hxx"

//========================================================================


void SfxItemPool::AddSfxItemPoolUser(SfxItemPoolUser& rNewUser)
{
	maSfxItemPoolUsers.push_back(&rNewUser);
}

void SfxItemPool::RemoveSfxItemPoolUser(SfxItemPoolUser& rOldUser)
{
	const SfxItemPoolUserVector::iterator aFindResult = ::std::find(maSfxItemPoolUsers.begin(), maSfxItemPoolUsers.end(), &rOldUser);
	if(aFindResult != maSfxItemPoolUsers.end())
	{
		maSfxItemPoolUsers.erase(aFindResult);
	}
}

const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
{
	DBG_CHKTHIS(SfxItemPool, 0);
	const SfxPoolItem* pRet;
	if( IsInRange( nWhich ) )
		pRet = *(ppPoolDefaults + GetIndex_Impl( nWhich ));
	else if( pSecondary )
		pRet = pSecondary->GetPoolDefaultItem( nWhich );
	else
	{
		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get pool default" );
		pRet = 0;
	}
	return pRet;
}

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

inline FASTBOOL SfxItemPool::IsItemFlag_Impl( sal_uInt16 nPos, sal_uInt16 nFlag ) const
{
	sal_uInt16 nItemFlag = pItemInfos[nPos]._nFlags;
	return nFlag == (nItemFlag & nFlag);
}

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

FASTBOOL SfxItemPool::IsItemFlag( sal_uInt16 nWhich, sal_uInt16 nFlag ) const
{
	for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pSecondary )
	{
		if ( pPool->IsInRange(nWhich) )
			return pPool->IsItemFlag_Impl( pPool->GetIndex_Impl(nWhich), nFlag);
	}
	DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" );
	return sal_False;
}

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

SfxBroadcaster& SfxItemPool::BC()
{
	return pImp->aBC;
}

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


SfxItemPool::SfxItemPool
(
	UniString const &	rName,          /* Name des Pools zur Idetifikation
										   im File-Format */
	sal_uInt16              nStartWhich,    /* erste Which-Id des Pools */
	sal_uInt16              nEndWhich,      /* letzte Which-Id des Pools */
#ifdef TF_POOLABLE
	const SfxItemInfo*  pInfos,         /* SID-Map und Item-Flags */
#endif
	SfxPoolItem**       pDefaults,      /* Pointer auf statische Defaults,
										   wird direkt vom Pool referenziert,
										   jedoch kein Eigent"umer"ubergang */
#ifndef TF_POOLABLE
	sal_uInt16*             pSlotIdArray,   /* Zuordnung von Slot-Ids zu Which-Ids */
#endif
	FASTBOOL            bLoadRefCounts  /* Ref-Counts mitladen oder auf 1 setzen */
)

/*  [Beschreibung]

	Der im Normalfall verwendete Konstruktor der Klasse SfxItemPool. Es
	wird eine SfxItemPool-Instanz initialisiert, die Items im b"undigen
	Which-Bereich von 'nStartWhich' bis 'nEndWhich' verwalten kann.

	F"ur jede dieser Which-Ids mu\s ein statischer Default im Array 'pDefaults'
	vorhanden sein, die dort beginnend mit einem <SfxPoolItem> mit der
	Which-Id 'nStartWhich' nach Which-Ids sortiert aufeinanderfolgend
	eingetragen sein m"ussen.

	'pItemInfos' ist ein identisch angeordnetes Array von USHORTs, die
	Slot-Ids darstellen und Flags. Die Slot-Ids k"onnen 0 sein, wenn die
	betreffenden Items ausschlie\slich in der Core verwendet werden.
	"Uber die Flags kann z.B. bestimmt werden, ob Value-Sharing
	(SFX_ITEM_POOLABLE) stattfinden soll.

	[Anmerkung]

	Wenn der Pool <SfxSetItem>s enthalten soll, k"onnen im Konstruktor noch
	keine static-Defaults angegeben werden. Dies mu\s dann nachtr"aglich
	mit <SfxItemPool::SetDefaults(SfxItemPool**)> geschehen.


	[Querverweise]

	<SfxItemPool::SetDefaults(SfxItemPool**)>
	<SfxItemPool::ReleaseDefaults(SfxPoolItem**,sal_uInt16,sal_Bool)>
	<SfxItemPool::ReldaseDefaults(sal_Bool)>
*/

:   aName(rName),
	nStart(nStartWhich),
	nEnd(nEndWhich),
#ifdef TF_POOLABLE
	pItemInfos(pInfos),
#else
	pSlotIds(pSlotIdArray),
#endif
	pImp( new SfxItemPool_Impl( nStart, nEnd ) ),
	ppStaticDefaults(0),
	ppPoolDefaults(new SfxPoolItem* [ nEndWhich - nStartWhich + 1]),
	pSecondary(0),
	pMaster(this),
	_pPoolRanges( 0 ),
	bPersistentRefCounts(bLoadRefCounts),
    maSfxItemPoolUsers()
{
	DBG_CTOR(SfxItemPool, 0);
	DBG_ASSERT(nStart, "Start-Which-Id must be greater 0" );

	pImp->eDefMetric = SFX_MAPUNIT_TWIP;
	pImp->nVersion = 0;
	pImp->bStreaming = sal_False;
	pImp->nLoadingVersion = 0;
	pImp->nInitRefCount = 1;
	pImp->nVerStart = nStart;
	pImp->nVerEnd = nEnd;
	pImp->bInSetItem = sal_False;
	pImp->nStoringStart = nStartWhich;
	pImp->nStoringEnd = nEndWhich;

	memset( ppPoolDefaults, 0, sizeof( SfxPoolItem* ) * (nEnd - nStart + 1));

	if ( pDefaults )
		SetDefaults(pDefaults);
}

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


SfxItemPool::SfxItemPool
(
	const SfxItemPool&  rPool,                  //  von dieser Instanz kopieren
	sal_Bool                bCloneStaticDefaults    /*  sal_True
													statische Defaults kopieren

													sal_False
													statische Defaults
													"ubernehehmen */
)

/*  [Beschreibung]

	Copy-Konstruktor der Klasse SfxItemPool.


	[Querverweise]

	<SfxItemPool::Clone()const>
*/

:   aName(rPool.aName),
	nStart(rPool.nStart),
	nEnd(rPool.nEnd),
#ifdef TF_POOLABLE
	pItemInfos(rPool.pItemInfos),
#else
	pSlotIds(rPool.pSlotIds),
#endif
	pImp( new SfxItemPool_Impl( nStart, nEnd ) ),
	ppStaticDefaults(0),
	ppPoolDefaults(new SfxPoolItem* [ nEnd - nStart + 1]),
	pSecondary(0),
	pMaster(this),
	_pPoolRanges( 0 ),
	bPersistentRefCounts(rPool.bPersistentRefCounts ),
    maSfxItemPoolUsers()
{
	DBG_CTOR(SfxItemPool, 0);
	pImp->eDefMetric = rPool.pImp->eDefMetric;
	pImp->nVersion = rPool.pImp->nVersion;
	pImp->bStreaming = sal_False;
	pImp->nLoadingVersion = 0;
	pImp->nInitRefCount = 1;
	pImp->nVerStart = rPool.pImp->nVerStart;
	pImp->nVerEnd = rPool.pImp->nVerEnd;
	pImp->bInSetItem = sal_False;
	pImp->nStoringStart = nStart;
	pImp->nStoringEnd = nEnd;

	memset( ppPoolDefaults, 0, sizeof( SfxPoolItem* ) * (nEnd - nStart + 1));

	// Static Defaults "ubernehmen
	if ( bCloneStaticDefaults )
	{
		SfxPoolItem **ppDefaults = new SfxPoolItem*[nEnd-nStart+1];
		for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
		{
			(*( ppDefaults + n )) = (*( rPool.ppStaticDefaults + n ))->Clone(this);
			(*( ppDefaults + n ))->SetKind( SFX_ITEMS_STATICDEFAULT );
		}

		SetDefaults( ppDefaults );
	}
	else
		SetDefaults( rPool.ppStaticDefaults );

	// Pool Defaults kopieren
	for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
		if ( (*( rPool.ppPoolDefaults + n )) )
		{
			(*( ppPoolDefaults + n )) = (*( rPool.ppPoolDefaults + n ))->Clone(this);
			(*( ppPoolDefaults + n ))->SetKind( SFX_ITEMS_POOLDEFAULT );
		}

	// Copy Version-Map
	for ( size_t nVer = 0; nVer < rPool.pImp->aVersions.size(); ++nVer )
	{
		const SfxPoolVersion_ImplPtr pOld = rPool.pImp->aVersions[nVer];
		SfxPoolVersion_ImplPtr pNew = SfxPoolVersion_ImplPtr( new SfxPoolVersion_Impl( *pOld ) );
		pImp->aVersions.push_back( pNew );
	}

	// Verkettung wiederherstellen
	if ( rPool.pSecondary )
		SetSecondaryPool( rPool.pSecondary->Clone() );
}

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

void SfxItemPool::SetDefaults( SfxPoolItem **pDefaults )
{
	DBG_CHKTHIS(SfxItemPool, 0);
	DBG_ASSERT( pDefaults, "erst wollen, dann nichts geben..." );
	DBG_ASSERT( !ppStaticDefaults, "habe schon defaults" );

	ppStaticDefaults = pDefaults;
	//! if ( (*ppStaticDefaults)->GetKind() != SFX_ITEMS_STATICDEFAULT )
	//! geht wohl nicht im Zshg mit SetItems, die hinten stehen
	{
		DBG_ASSERT( (*ppStaticDefaults)->GetRefCount() == 0 ||
					IsDefaultItem( (*ppStaticDefaults) ),
					"das sind keine statics" );
		for ( sal_uInt16 n = 0; n <= nEnd - nStart; ++n )
		{
			SFX_ASSERT( (*( ppStaticDefaults + n ))->Which() == n + nStart,
						n + nStart, "static defaults not sorted" );
			(*( ppStaticDefaults + n ))->SetKind( SFX_ITEMS_STATICDEFAULT );
			DBG_ASSERT( !(pImp->ppPoolItems[n]), "defaults with setitems with items?!" );
		}
	}
}

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

void SfxItemPool::ReleaseDefaults
(
	sal_Bool    bDelete     /*  sal_True
							l"oscht sowohl das Array als auch die einzelnen
							statischen Defaults

							sal_False
							l"oscht weder das Array noch die einzelnen
							statischen Defaults */
)

/*  [Beschreibung]

	Gibt die statischen Defaults der betreffenden SfxItemPool-Instanz frei
	und l"oscht ggf. die statischen Defaults.

	Nach Aufruf dieser Methode darf die SfxItemPool-Instanz nicht mehr
	verwendet werden, einzig ist der Aufruf des Destruktors zu"lassig.
*/

{
	DBG_ASSERT( ppStaticDefaults, "keine Arme keine Kekse" );
	ReleaseDefaults( ppStaticDefaults, nEnd - nStart + 1, bDelete );

	// KSO (22.10.98): ppStaticDefaults zeigt auf geloeschten Speicher,
	// wenn bDelete == sal_True.
	if ( bDelete )
		ppStaticDefaults = 0;
}

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

void SfxItemPool::ReleaseDefaults
(
	SfxPoolItem**   pDefaults,  /*  freizugebende statische Defaults */

	sal_uInt16          nCount,     /*  Anzahl der statischen Defaults */

	sal_Bool            bDelete     /*  sal_True
									l"oscht sowohl das Array als auch die
									einzelnen statischen Defaults

									sal_False
									l"oscht weder das Array noch die
									einzelnen statischen Defaults */
)

/*  [Beschreibung]

	Gibt die angegebenen statischen Defaults frei und l"oscht ggf.
	die statischen Defaults.

	Diese Methode darf erst nach Zerst"orung aller SfxItemPool-Instanzen,
	welche die angegebenen statischen Defaults 'pDefault' verwenden,
	aufgerufen werden.
*/

{
	DBG_ASSERT( pDefaults, "erst wollen, dann nichts geben..." );

	for ( sal_uInt16 n = 0; n < nCount; ++n )
	{
		SFX_ASSERT( IsStaticDefaultItem( *(pDefaults+n) ),
					n, "das ist kein static-default" );
		(*( pDefaults + n ))->SetRefCount( 0 );
		if ( bDelete )
			{ delete *( pDefaults + n ); *(pDefaults + n) = 0; }
	}

	if ( bDelete )
		{ delete[] pDefaults; pDefaults = 0; }
}

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

SfxItemPool::~SfxItemPool()
{
	DBG_DTOR(SfxItemPool, 0);
	DBG_ASSERT( pMaster == this, "destroying active Secondary-Pool" );

    if ( pImp->ppPoolItems && ppPoolDefaults )
		Delete();
	delete[] _pPoolRanges;
	delete pImp;
}

void SfxItemPool::Free(SfxItemPool* pPool)
{
    if(pPool)
    {
	    // tell all the registered SfxItemPoolUsers that the pool is in destruction
	    SfxItemPoolUserVector aListCopy(pPool->maSfxItemPoolUsers.begin(), pPool->maSfxItemPoolUsers.end());
	    for(SfxItemPoolUserVector::iterator aIterator = aListCopy.begin(); aIterator != aListCopy.end(); aIterator++)
	    {
		    SfxItemPoolUser* pSfxItemPoolUser = *aIterator;
		    DBG_ASSERT(pSfxItemPoolUser, "corrupt SfxItemPoolUser list (!)");
		    pSfxItemPoolUser->ObjectInDestruction(*pPool);
	    }

	    // Clear the vector. This means that user do not need to call RemoveSfxItemPoolUser()
	    // when they get called from ObjectInDestruction().
	    pPool->maSfxItemPoolUsers.clear();

        // delete pool
        delete pPool;
    }
}

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


void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
{
	// ggf. an abgeh"angten Pools den Master zur"ucksetzen
	if ( pSecondary )
	{
#ifdef DBG_UTIL
		HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
		if ( ppStaticDefaults )
		{
			// Delete() ist noch nicht gelaufen?
			if ( pImp->ppPoolItems && pSecondary->pImp->ppPoolItems )
			{
				// hat der master SetItems?
				sal_Bool bHasSetItems = sal_False;
				for ( sal_uInt16 i = 0; !bHasSetItems && i < nEnd-nStart; ++i )
					bHasSetItems = ppStaticDefaults[i]->ISA(SfxSetItem);

				// abgehaengte Pools muessen leer sein
				sal_Bool bOK = bHasSetItems;
				for ( sal_uInt16 n = 0;
					  bOK && n <= pSecondary->nEnd - pSecondary->nStart;
					  ++n )
				{
					SfxPoolItemArray_Impl** ppItemArr =
												pSecondary->pImp->ppPoolItems + n;
					if ( *ppItemArr )
					{
						SfxPoolItemArrayBase_Impl::iterator ppHtArr =	(*ppItemArr)->begin();
						for( size_t i = (*ppItemArr)->size(); i; ++ppHtArr, --i )
							if ( !(*ppHtArr) )
							{
								DBG_ERROR( "old secondary pool must be empty" );
								bOK = sal_False;
								break;
							}
					}
				}
			}
		}
#endif

		pSecondary->pMaster = pSecondary;
		for ( SfxItemPool *p = pSecondary->pSecondary; p; p = p->pSecondary )
			p->pMaster = pSecondary;
	}

	// ggf. den Master der neuen Secondary-Pools setzen
	DBG_ASSERT( !pPool || pPool->pMaster == pPool, "Secondary tanzt auf zwei Hochzeiten " );
	SfxItemPool *pNewMaster = pMaster ? pMaster : this;
	for ( SfxItemPool *p = pPool; p; p = p->pSecondary )
		p->pMaster = pNewMaster;

	// neuen Secondary-Pool merken
	pSecondary = pPool;
}

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

SfxMapUnit SfxItemPool::GetMetric( sal_uInt16 ) const
{
	DBG_CHKTHIS(SfxItemPool, 0);

	return pImp->eDefMetric;
}

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

void SfxItemPool::SetDefaultMetric( SfxMapUnit eNewMetric )
{
	DBG_CHKTHIS(SfxItemPool, 0);

	pImp->eDefMetric = eNewMetric;
}

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

SfxItemPresentation SfxItemPool::GetPresentation
(
	const SfxPoolItem&  rItem,      /*  IN: <SfxPoolItem>, dessen textuelle
											Wert-Darstellung geliefert werden
											soll */
	SfxItemPresentation ePresent,   /*  IN: gew"unschte Art der Darstellung;
											siehe <SfxItemPresentation> */
	SfxMapUnit          eMetric,    /*  IN: gew"unschte Ma\seinheit der Darstellung */
	XubString&           rText,      /*  OUT: textuelle Darstellung von 'rItem' */
    const IntlWrapper * pIntlWrapper
)   const

/*  [Beschreibung]

	"Uber diese virtuelle Methode k"onnen textuelle Darstellungen der
	von der jeweilige SfxItemPool-Subklasse verwalteten SfxPoolItems
	angefordert werden.

	In Ableitungen sollte diese Methode "uberladen werden und auf
	SfxPoolItems reagiert werden, die bei <SfxPoolItem::GetPresentation()const>
	keine vollst"andige Information liefern k"onnen.

	Die Basisklasse liefert die unver"anderte Presentation von 'rItem'.
*/

{
	DBG_CHKTHIS(SfxItemPool, 0);
	return rItem.GetPresentation(
        ePresent, GetMetric(rItem.Which()), eMetric, rText, pIntlWrapper );
}


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

SfxItemPool* SfxItemPool::Clone() const
{
	DBG_CHKTHIS(SfxItemPool, 0);

	SfxItemPool *pPool = new SfxItemPool( *this );
	return pPool;
}

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

void SfxItemPool::Delete()
{
	DBG_CHKTHIS(SfxItemPool, 0);

	// schon deleted?
	if ( !pImp->ppPoolItems || !ppPoolDefaults )
		return;

	// z.B. laufenden Requests bescheidsagen
	pImp->aBC.Broadcast( SfxSimpleHint( SFX_HINT_DYING ) );

	//MA 16. Apr. 97: Zweimal durchlaufen, in der ersten Runde fuer die SetItems.
	//Der Klarheit halber wird das jetzt in zwei besser lesbare Schleifen aufgeteilt.

	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
	SfxPoolItem** ppDefaultItem = ppPoolDefaults;
	SfxPoolItem** ppStaticDefaultItem = ppStaticDefaults;
	sal_uInt16 nArrCnt;

	//Erst die SetItems abraeumen
	HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
	if ( ppStaticDefaults )
	{
		for ( nArrCnt = GetSize_Impl();
				nArrCnt;
				--nArrCnt, ++ppItemArr, ++ppDefaultItem, ++ppStaticDefaultItem )
		{
			// KSO (22.10.98): *ppStaticDefaultItem kann im dtor einer
			// von SfxItemPool abgeleiteten Klasse bereits geloescht worden
			// sein! -> CHAOS Itempool
			if ( *ppStaticDefaultItem && (*ppStaticDefaultItem)->ISA(SfxSetItem) )
			{
				if ( *ppItemArr )
				{
					SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
					for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
						if (*ppHtArr)
						{
#ifdef DBG_UTIL
							ReleaseRef( **ppHtArr, (*ppHtArr)->GetRefCount() );
#endif
							delete *ppHtArr;
						}
					DELETEZ( *ppItemArr );
				}
				if ( *ppDefaultItem )
				{
#ifdef DBG_UTIL
					SetRefCount( **ppDefaultItem, 0 );
#endif
					DELETEZ( *ppDefaultItem );
				}
			}
		}
	}

	ppItemArr = pImp->ppPoolItems;
	ppDefaultItem = ppPoolDefaults;

	//Jetzt die 'einfachen' Items
	for ( nArrCnt = GetSize_Impl();
			nArrCnt;
			--nArrCnt, ++ppItemArr, ++ppDefaultItem )
	{
		if ( *ppItemArr )
		{
			SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
			for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
				if (*ppHtArr)
				{
#ifdef DBG_UTIL
					ReleaseRef( **ppHtArr, (*ppHtArr)->GetRefCount() );
#endif
					delete *ppHtArr;
				}
			delete *ppItemArr;
		}
		if ( *ppDefaultItem )
		{
#ifdef DBG_UTIL
			SetRefCount( **ppDefaultItem, 0 );
#endif
			delete *ppDefaultItem;
		}
	}

	pImp->DeleteItems();
	delete[] ppPoolDefaults; ppPoolDefaults = 0;
}

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

void SfxItemPool::Cleanup()
{
	DBG_CHKTHIS(SfxItemPool, 0);

	//MA 16. Apr. 97: siehe ::Delete()

	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems;
	SfxPoolItem** ppDefaultItem = ppPoolDefaults;
	SfxPoolItem** ppStaticDefaultItem = ppStaticDefaults;
	sal_uInt16 nArrCnt;

	HACK( "fuer Image, dort gibt es derzeit keine Statics - Bug" )
	if ( ppStaticDefaults ) //HACK fuer Image, dort gibt es keine Statics!!
	{
		for ( nArrCnt = GetSize_Impl();
				nArrCnt;
				--nArrCnt, ++ppItemArr, ++ppDefaultItem, ++ppStaticDefaultItem )
		{
			//Fuer jedes Item gibt es entweder ein Default oder ein static Default!
			if ( *ppItemArr &&
				 ((*ppDefaultItem && (*ppDefaultItem)->ISA(SfxSetItem)) ||
				  (*ppStaticDefaultItem)->ISA(SfxSetItem)) )
			{
				SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
				for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
					if ( *ppHtArr && !(*ppHtArr)->GetRefCount() )
					{
						 DELETEZ(*ppHtArr);
					}
			}
		}
	}

	ppItemArr = pImp->ppPoolItems;

	for ( nArrCnt = GetSize_Impl();
		  nArrCnt;
		  --nArrCnt, ++ppItemArr )
	{
		if ( *ppItemArr )
		{
			SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
			for ( size_t n = (*ppItemArr)->size(); n; --n, ++ppHtArr )
				if ( *ppHtArr && !(*ppHtArr)->GetRefCount() )
					DELETEZ( *ppHtArr );
		}
	}
}

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

void SfxItemPool::SetPoolDefaultItem(const SfxPoolItem &rItem)
{
	DBG_CHKTHIS(SfxItemPool, 0);
	if ( IsInRange(rItem.Which()) )
	{
		SfxPoolItem **ppOldDefault =
			ppPoolDefaults + GetIndex_Impl(rItem.Which());
		SfxPoolItem *pNewDefault = rItem.Clone(this);
		pNewDefault->SetKind(SFX_ITEMS_POOLDEFAULT);
		if ( *ppOldDefault )
		{
			(*ppOldDefault)->SetRefCount(0);
			DELETEZ( *ppOldDefault );
		}
		*ppOldDefault = pNewDefault;
	}
	else if ( pSecondary )
		pSecondary->SetPoolDefaultItem(rItem);
	else
	{
		SFX_ASSERT( 0, rItem.Which(), "unknown Which-Id - cannot set pool default" );
	}
}

/*
 * Resets the default of the given <Which-Id> back to the static default.
 * If a pool default exists it is removed.
 */
void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId )
{
	DBG_CHKTHIS(SfxItemPool, 0);
	if ( IsInRange(nWhichId) )
	{
		SfxPoolItem **ppOldDefault =
			ppPoolDefaults + GetIndex_Impl( nWhichId );
		if ( *ppOldDefault )
		{
			(*ppOldDefault)->SetRefCount(0);
			DELETEZ( *ppOldDefault );
		}
	}
	else if ( pSecondary )
		pSecondary->ResetPoolDefaultItem(nWhichId);
	else
	{
		SFX_ASSERT( 0, nWhichId, "unknown Which-Id - cannot set pool default" );
	}
}

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

const SfxPoolItem& SfxItemPool::Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
{
	DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
				0 != &((const SfxSetItem&)rItem).GetItemSet(),
				"SetItem without ItemSet" );

	DBG_CHKTHIS(SfxItemPool, 0);
	if ( 0 == nWhich )
		nWhich = rItem.Which();

	// richtigen Secondary-Pool finden
	sal_Bool bSID = nWhich > SFX_WHICH_MAX;
	if ( !bSID && !IsInRange(nWhich) )
	{
		if ( pSecondary )
			return pSecondary->Put( rItem, nWhich );
		DBG_ERROR( "unknown Which-Id - cannot put item" );
	}

	// SID oder nicht poolable (neue Definition)?
	sal_uInt16 nIndex = bSID ? USHRT_MAX : GetIndex_Impl(nWhich);
	if ( USHRT_MAX == nIndex ||
		 IsItemFlag_Impl( nIndex, SFX_ITEM_NOT_POOLABLE ) )
	{
		SFX_ASSERT( USHRT_MAX != nIndex || rItem.Which() != nWhich ||
					!IsDefaultItem(&rItem) || rItem.GetKind() == SFX_ITEMS_DELETEONIDLE,
					nWhich, "ein nicht Pool-Item ist Default?!" );
		SfxPoolItem *pPoolItem = rItem.Clone(pMaster);
		pPoolItem->SetWhich(nWhich);
		AddRef( *pPoolItem );
		return *pPoolItem;
	}

	SFX_ASSERT( rItem.IsA(GetDefaultItem(nWhich).Type()), nWhich,
				"SFxItemPool: wrong item type in Put" );

	SfxPoolItemArray_Impl** ppItemArr = pImp->ppPoolItems + nIndex;
	if( !*ppItemArr )
		*ppItemArr = new SfxPoolItemArray_Impl;

	SfxPoolItemArrayBase_Impl::iterator ppFree;
	sal_Bool ppFreeIsSet = sal_False;
	SfxPoolItemArrayBase_Impl::iterator ppHtArray = (*ppItemArr)->begin();
	if ( IsItemFlag_Impl( nIndex, SFX_ITEM_POOLABLE ) )
	{
		// wenn es ueberhaupt gepoolt ist, koennte es schon drin sein
		if ( IsPooledItem(&rItem) )
		{
			// 1. Schleife: teste ob der Pointer vorhanden ist.
			for( size_t n = (*ppItemArr)->size(); n; ++ppHtArray, --n )
				if( &rItem == (*ppHtArray) )
				{
					AddRef( **ppHtArray );
					return **ppHtArray;
				}
		}

		// 2. Schleife: dann muessen eben die Attribute verglichen werden
		size_t n;
		for ( n = (*ppItemArr)->size(), ppHtArray = (*ppItemArr)->begin();
			  n; ++ppHtArray, --n )
		{
			if ( *ppHtArray )
			{
				if( **ppHtArray == rItem )
				{
					AddRef( **ppHtArray );
					return **ppHtArray;
				}
			}
			else
				if ( ppFreeIsSet == sal_False )
				{
					ppFree = ppHtArray;
					ppFreeIsSet = sal_True;
				}
		}
	}
	else
	{
		// freien Platz suchen
		SfxPoolItemArrayBase_Impl::iterator ppHtArr;
		size_t n, nCount = (*ppItemArr)->size();
		for ( n = (*ppItemArr)->nFirstFree,
				  ppHtArr = (*ppItemArr)->begin() + n;
			  n < nCount;
			  ++ppHtArr, ++n )
			if ( !*ppHtArr )
			{
				ppFree = ppHtArr;
				ppFreeIsSet = sal_True;
				break;
			}

		// naechstmoeglichen freien Platz merken
		(*ppItemArr)->nFirstFree = n;
	}

	// nicht vorhanden, also im PtrArray eintragen
	SfxPoolItem* pNewItem = rItem.Clone(pMaster);
	pNewItem->SetWhich(nWhich);
#ifdef DBG_UTIL
	SFX_ASSERT( rItem.Type() == pNewItem->Type(), nWhich, "unequal types in Put(): no Clone()?" )
#ifdef TF_POOLABLE
	if ( !rItem.ISA(SfxSetItem) )
	{
		SFX_ASSERT( !IsItemFlag(nWhich, SFX_ITEM_POOLABLE) ||
					rItem == *pNewItem,
					nWhich, "unequal items in Put(): no operator==?" );
		SFX_ASSERT( !IsItemFlag(*pNewItem, SFX_ITEM_POOLABLE) ||
					*pNewItem == rItem,
					nWhich, "unequal items in Put(): no operator==?" );
	}
#endif
#endif
	AddRef( *pNewItem, pImp->nInitRefCount );
	SfxPoolItem* pTemp = pNewItem;
	if ( ppFreeIsSet == sal_False )
		(*ppItemArr)->push_back( pTemp );
	else
	{
		DBG_ASSERT( *ppFree == 0, "using surrogate in use" );
		*ppFree = pNewItem;
	}
	return *pNewItem;
}

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

void SfxItemPool::Remove( const SfxPoolItem& rItem )
{
	DBG_CHKTHIS(SfxItemPool, 0);

	DBG_ASSERT( !rItem.ISA(SfxSetItem) ||
				0 != &((const SfxSetItem&)rItem).GetItemSet(),
				"SetItem without ItemSet" );

	SFX_ASSERT( !IsPoolDefaultItem(&rItem), rItem.Which(),
				"wo kommt denn hier ein Pool-Default her" );

	// richtigen Secondary-Pool finden
	const sal_uInt16 nWhich = rItem.Which();
	sal_Bool bSID = nWhich > SFX_WHICH_MAX;
	if ( !bSID && !IsInRange(nWhich) )
	{
		if ( pSecondary )
		{
			pSecondary->Remove( rItem );
			return;
		}
		DBG_ERROR( "unknown Which-Id - cannot remove item" );
	}

	// SID oder nicht poolable (neue Definition)?
	sal_uInt16 nIndex = bSID ? USHRT_MAX : GetIndex_Impl(nWhich);
	if ( bSID || IsItemFlag_Impl( nIndex, SFX_ITEM_NOT_POOLABLE ) )
	{
		SFX_ASSERT( USHRT_MAX != nIndex ||
					!IsDefaultItem(&rItem), rItem.Which(),
					"ein nicht Pool-Item ist Default?!" );
		if ( 0 == ReleaseRef(rItem) )
		{
			SfxPoolItem *pItem = &(SfxPoolItem &)rItem;
			delete pItem;
		}
		return;
	}

	SFX_ASSERT( rItem.GetRefCount(), rItem.Which(), "RefCount == 0, Remove unmoeglich" );

	// statische Defaults sind eben einfach da
	if ( rItem.GetKind() == SFX_ITEMS_STATICDEFAULT &&
		 &rItem == *( ppStaticDefaults + GetIndex_Impl(nWhich) ) )
		return;

	// Item im eigenen Pool suchen
	SfxPoolItemArray_Impl** ppItemArr = (pImp->ppPoolItems + nIndex);
	SFX_ASSERT( *ppItemArr, rItem.Which(), "removing Item not in Pool" );
	SfxPoolItemArrayBase_Impl::iterator ppHtArr = (*ppItemArr)->begin();
	for( size_t n = (*ppItemArr)->size(); n; ++ppHtArr, --n )
		if( *ppHtArr == &rItem )
		{
			if ( (*ppHtArr)->GetRefCount() ) //!
				ReleaseRef( **ppHtArr );
			else
			{
				SFX_ASSERT( 0, rItem.Which(), "removing Item without ref" );
				SFX_TRACE( "to be removed, but not no refs: ", *ppHtArr );
			}

			// ggf. kleinstmoegliche freie Position merken
			size_t nPos = (*ppItemArr)->size() - n;
			if ( (*ppItemArr)->nFirstFree > nPos )
				(*ppItemArr)->nFirstFree = nPos;

			//! MI: Hack, solange wir das Problem mit dem Outliner haben
			//! siehe anderes MI-REF
			if ( 0 == (*ppHtArr)->GetRefCount() && nWhich < 4000 )
				DELETEZ(*ppHtArr);
			return;
		}

	// nicht vorhanden
	SFX_ASSERT( 0, rItem.Which(), "removing Item not in Pool" );
	SFX_TRACE( "to be removed, but not in pool: ", &rItem );
}

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

const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const
{
	DBG_CHKTHIS(SfxItemPool, 0);

	if ( !IsInRange(nWhich) )
	{
		if ( pSecondary )
			return pSecondary->GetDefaultItem( nWhich );
		SFX_ASSERT( 0, nWhich, "unknown which - dont ask me for defaults" );
	}

	DBG_ASSERT( ppStaticDefaults, "no defaults known - dont ask me for defaults" );
	sal_uInt16 nPos = GetIndex_Impl(nWhich);
	SfxPoolItem *pDefault = *(ppPoolDefaults + nPos);
	if ( pDefault )
		return *pDefault;
	return **(ppStaticDefaults + nPos);
}

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


void SfxItemPool::FreezeIdRanges()

/*	[Beschreibung]

	This method should be called at the master pool, when all secondary
	pools are appended to it.

	It calculates the ranges of 'which-ids' for fast construction of
	item-sets, which contains all 'which-ids'.
*/

{
	FillItemIdRanges_Impl( _pPoolRanges );
}


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

void SfxItemPool::FillItemIdRanges_Impl( sal_uInt16*& pWhichRanges ) const
{
	DBG_CHKTHIS(SfxItemPool, 0);
	DBG_ASSERT( !_pPoolRanges, "GetFrozenRanges() would be faster!" );

	const SfxItemPool *pPool;
	sal_uInt16 nLevel = 0;
	for( pPool = this; pPool; pPool = pPool->pSecondary )
		++nLevel;

	pWhichRanges = new sal_uInt16[ 2*nLevel + 1 ];

	nLevel = 0;
	for( pPool = this; pPool; pPool = pPool->pSecondary )
	{
		*(pWhichRanges+(nLevel++)) = pPool->nStart;
		*(pWhichRanges+(nLevel++)) = pPool->nEnd;
		*(pWhichRanges+nLevel) = 0;
	}
}

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

const SfxPoolItem *SfxItemPool::GetItem2(sal_uInt16 nWhich, sal_uInt32 nOfst) const
{
	DBG_CHKTHIS(SfxItemPool, 0);

	if ( !IsInRange(nWhich) )
	{
		if ( pSecondary )
			return pSecondary->GetItem2( nWhich, nOfst );
		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot resolve surrogate" );
		return 0;
	}

	// dflt-Attribut?
	if ( nOfst == SFX_ITEMS_DEFAULT )
		return *(ppStaticDefaults + GetIndex_Impl(nWhich));

	SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(nWhich));
	if( pItemArr && nOfst < pItemArr->size() )
		return (*pItemArr)[nOfst];

	return 0;
}

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

sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const
{
	DBG_CHKTHIS(SfxItemPool, 0);

	if ( !IsInRange(nWhich) )
	{
		if ( pSecondary )
			return pSecondary->GetItemCount2( nWhich );
		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot resolve surrogate" );
		return 0;
	}

	SfxPoolItemArray_Impl* pItemArr = *(pImp->ppPoolItems + GetIndex_Impl(nWhich));
	if  ( pItemArr )
		return pItemArr->size();
	return 0;
}

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

sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, sal_Bool bDeep ) const
{
	if ( !IsSlot(nSlotId) )
		return nSlotId;

#ifdef TF_POOLABLE
	sal_uInt16 nCount = nEnd - nStart + 1;
	for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
		if ( pItemInfos[nOfs]._nSID == nSlotId )
			return nOfs + nStart;
#else
	if ( pSlotIds )
	{
		sal_uInt16 nCount = nEnd - nStart + 1;
		for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
			if ( pSlotIds[nOfs] == nSlotId )
				return nOfs + nStart;
	}
#endif
	if ( pSecondary && bDeep )
		return pSecondary->GetWhich(nSlotId);
	return nSlotId;
}

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

sal_uInt16 SfxItemPool::GetSlotId( sal_uInt16 nWhich, sal_Bool bDeep ) const
{
	if ( !IsWhich(nWhich) )
		return nWhich;

	if ( !IsInRange( nWhich ) )
	{
		if ( pSecondary && bDeep )
			return pSecondary->GetSlotId(nWhich);
		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get slot-id" );
		return 0;
	}
#ifdef TF_POOLABLE

	sal_uInt16 nSID = pItemInfos[nWhich - nStart]._nSID;
	return nSID ? nSID : nWhich;
#else
	else if ( pSlotIds )
		return pSlotIds[nWhich - nStart];
	return nWhich;
#endif
}

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

sal_uInt16 SfxItemPool::GetTrueWhich( sal_uInt16 nSlotId, sal_Bool bDeep ) const
{
	if ( !IsSlot(nSlotId) )
		return 0;

#ifdef TF_POOLABLE
	sal_uInt16 nCount = nEnd - nStart + 1;
	for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
		if ( pItemInfos[nOfs]._nSID == nSlotId )
			return nOfs + nStart;
#else
	if ( pSlotIds )
	{
		sal_uInt16 nCount = nEnd - nStart + 1;
		for ( sal_uInt16 nOfs = 0; nOfs < nCount; ++nOfs )
			if ( pSlotIds[nOfs] == nSlotId )
				return nOfs + nStart;
	}
#endif
	if ( pSecondary && bDeep )
		return pSecondary->GetTrueWhich(nSlotId);
	return 0;
}

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

sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich, sal_Bool bDeep ) const
{
	if ( !IsWhich(nWhich) )
		return 0;

	if ( !IsInRange( nWhich ) )
	{
		if ( pSecondary && bDeep )
			return pSecondary->GetTrueSlotId(nWhich);
		SFX_ASSERT( 0, nWhich, "unknown Which-Id - cannot get slot-id" );
		return 0;
	}
#ifdef TF_POOLABLE
	return pItemInfos[nWhich - nStart]._nSID;
#else
	else if ( pSlotIds )
		return pSlotIds[nWhich - nStart];
	else
		return 0;
#endif
}
// -----------------------------------------------------------------------
void SfxItemPool::SetFileFormatVersion( sal_uInt16 nFileFormatVersion )

/*  [Description]

	You must call this function to set the file format version after
	concatenating your secondary-pools but before you store any
	pool, itemset or item. Only set the version at the master pool,
	never at any secondary pool.
*/

{
	DBG_ASSERT( this == pMaster,
				"SfxItemPool::SetFileFormatVersion() but not a master pool" );
	for ( SfxItemPool *pPool = this; pPool; pPool = pPool->pSecondary )
		pPool->_nFileFormatVersion = nFileFormatVersion;
}


