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

#include <string.h>

// Schalter fuer Introspection-Caching
#ifndef OS2
#define USE_INTROSPECTION_CACHE
#endif

#ifdef USE_INTROSPECTION_CACHE
#define INTROSPECTION_CACHE_MAX_SIZE 100
#endif
#include <osl/diagnose.h>
#include <osl/mutex.hxx>
#include <osl/thread.h>
#include <cppuhelper/queryinterface.hxx>
#include <cppuhelper/weak.hxx>
#include <cppuhelper/component.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/implbase3.hxx>
#include <cppuhelper/typeprovider.hxx>

#include <com/sun/star/uno/DeploymentException.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XEventListener.hpp>
#include <com/sun/star/reflection/XIdlReflection.hpp>
#include <com/sun/star/reflection/XIdlClassProvider.hpp>
#include <com/sun/star/reflection/XIdlClass.hpp>
#include <com/sun/star/reflection/XIdlField2.hpp>
#include <com/sun/star/beans/UnknownPropertyException.hpp>
#include <com/sun/star/beans/Property.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XFastPropertySet.hpp>
#include <com/sun/star/beans/XIntrospection.hpp>
#include <com/sun/star/beans/XIntrospectionAccess.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
#include <com/sun/star/beans/XExactName.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyConcept.hpp>
#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/container/XIndexContainer.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>

#include <rtl/ustrbuf.hxx>
#include <rtl/ref.hxx>
#include <rtl/strbuf.hxx>
#include <hash_map>

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::reflection;
using namespace com::sun::star::container;
using namespace com::sun::star::registry;
using namespace com::sun::star::beans;
using namespace com::sun::star::beans::PropertyAttribute;
using namespace com::sun::star::beans::PropertyConcept;
using namespace com::sun::star::beans::MethodConcept;
using namespace cppu;
using namespace osl;

#define IMPLEMENTATION_NAME "com.sun.star.comp.stoc.Introspection"
#define SERVICE_NAME		"com.sun.star.beans.Introspection"

namespace stoc_inspect
{

typedef WeakImplHelper3< XIntrospectionAccess, XMaterialHolder, XExactName > IntrospectionAccessHelper;


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

// Spezial-Wert fuer Method-Concept, um "normale" Funktionen kennzeichnen zu koennen
#define  MethodConcept_NORMAL_IMPL		0x80000000


// Methode zur Feststellung, ob eine Klasse von einer anderen abgeleitet ist
sal_Bool isDerivedFrom( Reference<XIdlClass> xToTestClass, Reference<XIdlClass> xDerivedFromClass )
{
	Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();
	const Reference<XIdlClass>* pClassesArray = aClassesSeq.getConstArray();
	sal_Int32 nSuperClassCount = aClassesSeq.getLength();
	sal_Int32 i;
	for( i = 0 ; i < nSuperClassCount ; i++ )
	{
		const Reference<XIdlClass>& rxClass = pClassesArray[i];
		if( xDerivedFromClass->equals( rxClass ) )
		{
			// Treffer
			return sal_True;
		}
		else
		{
			// Rekursiv weitersuchen
			return isDerivedFrom( rxClass, xDerivedFromClass );
		}
	}
	return sal_False;
}

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

// *** Klassifizierung der Properties (kein enum, um Sequence verwenden zu koennen) ***
// Properties aus einem PropertySet-Interface
#define MAP_PROPERTY_SET	0
// Properties aus Fields
#define MAP_FIELD			1
// Properties, die durch get/set-Methoden beschrieben werden
#define MAP_GETSET			2
// Properties, die nur eine set-Methode haben
#define MAP_SETONLY			3


// Schrittweite, in der die Groesse der Sequences angepasst wird
#define ARRAY_SIZE_STEP		20



//**************************************
//*** IntrospectionAccessStatic_Impl ***
//**************************************
// Entspricht dem alten IntrospectionAccessImpl, bildet jetzt den statischen 
// Anteil des neuen Instanz-bezogenen ImplIntrospectionAccess

// ACHTUNG !!! Von Hand refcounten !!!


// Hashtable fuer die Suche nach Namen
struct hashName_Impl
{
	size_t operator()(const ::rtl::OUString Str) const
	{
		return (size_t)Str.hashCode();
	}
};

struct eqName_Impl
{
	sal_Bool operator()(const ::rtl::OUString Str1, const ::rtl::OUString Str2) const
	{
		return ( Str1 == Str2 );
	}
};

typedef std::hash_map
<
    ::rtl::OUString,
	sal_Int32,
	hashName_Impl,
	eqName_Impl
>
IntrospectionNameMap;


// Hashtable zur Zuordnung der exakten Namen zu den zu Lower-Case
// konvertierten Namen, dient zur Unterst�tzung von XExactName
typedef std::hash_map
<
    ::rtl::OUString,
    ::rtl::OUString,
	hashName_Impl,
	eqName_Impl
>
LowerToExactNameMap;


class ImplIntrospectionAccess;
class IntrospectionAccessStatic_Impl
{
	friend class ImplIntrospection;
	friend class ImplIntrospectionAccess;

	// CoreReflection halten
	Reference< XIdlReflection > mxCoreReflection;

	// InterfaceSequences, um Zusatz-Infos zu einer Property speichern zu koennen.
	// z.B. das Field bei MAP_FIELD, die get/set-Methoden bei MAP_GETSET usw.
	Sequence< Reference<XInterface> > aInterfaceSeq1;
	Sequence< Reference<XInterface> > aInterfaceSeq2;

	// Hashtables fuer die Namen
	IntrospectionNameMap maPropertyNameMap;
	IntrospectionNameMap maMethodNameMap;
	LowerToExactNameMap  maLowerToExactNameMap;

	// Sequence aller Properties, auch zum Liefern aus getProperties()
	Sequence<Property> maAllPropertySeq;

	// Mapping der Properties auf Zugriffs-Arten
	Sequence<sal_Int16> maMapTypeSeq;

	// Klassifizierung der gefundenen Methoden
	Sequence<sal_Int32> maPropertyConceptSeq;
	
	// Anzahl der Properties
	sal_Int32 mnPropCount;

	// Anzahl der Properties, die den jeweiligen Konzepten zugeordnet sind
	//sal_Int32 mnDangerousPropCount;
	sal_Int32 mnPropertySetPropCount;
	sal_Int32 mnAttributePropCount;
	sal_Int32 mnMethodPropCount;

	// Flag, ob ein FastPropertySet unterstuetzt wird
	sal_Bool mbFastPropSet;

	// Original-Handles eines FastPropertySets
	sal_Int32* mpOrgPropertyHandleArray;

	// MethodSequence, die alle Methoden aufnimmt
	Sequence< Reference<XIdlMethod> > maAllMethodSeq;

	// Klassifizierung der gefundenen Methoden
	Sequence<sal_Int32> maMethodConceptSeq;
	
	// Anzahl der Methoden
	sal_Int32 mnMethCount;

	// Sequence der Listener, die angemeldet werden koennen
	Sequence< Type > maSupportedListenerSeq;

	// BaseInit (soll spaeter in der Applikation erfolgen!)
	void BaseInit( void );

	// Hilfs-Methoden zur Groessen-Anpassung der Sequences
	void checkPropertyArraysSize
	( 
		Property*& rpAllPropArray, 
		sal_Int16*& rpMapTypeArray,
		sal_Int32*& rpPropertyConceptArray,
		sal_Int32 iNextIndex
	);
	void checkInterfaceArraySize( Sequence< Reference<XInterface> >& rSeq, Reference<XInterface>*& rpInterfaceArray, 
		sal_Int32 iNextIndex );

	// RefCount
	sal_Int32 nRefCount;


public:
	IntrospectionAccessStatic_Impl( Reference< XIdlReflection > xCoreReflection_ );
	~IntrospectionAccessStatic_Impl()
	{
		delete[] mpOrgPropertyHandleArray;
	}
	sal_Int32 getPropertyIndex( const ::rtl::OUString& aPropertyName ) const;
	sal_Int32 getMethodIndex( const ::rtl::OUString& aMethodName ) const;

	void acquire() { nRefCount++; }
	void release()
	{ 
		nRefCount--; 
		if( nRefCount <= 0 )
			delete this;
	}

	// Methoden von XIntrospectionAccess (ALT, jetzt nur Impl)
	void setPropertyValue(const Any& obj, const ::rtl::OUString& aPropertyName, const Any& aValue) const;
//	void setPropertyValue(Any& obj, const ::rtl::OUString& aPropertyName, const Any& aValue) const;
	Any getPropertyValue(const Any& obj, const ::rtl::OUString& aPropertyName) const;
	void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValue) const;
//	void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const;
	Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const;

	Sequence<Property> getProperties(void) const						{ return maAllPropertySeq; }
	Sequence< Reference<XIdlMethod> > getMethods(void) const			{ return maAllMethodSeq; }
	Sequence< Type > getSupportedListeners(void) const					{ return maSupportedListenerSeq; }
	Sequence<sal_Int32> getPropertyConcepts(void) const					{ return maPropertyConceptSeq; }
	Sequence<sal_Int32> getMethodConcepts(void) const					{ return maMethodConceptSeq; }
};


// Ctor
IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > xCoreReflection_ )
	: mxCoreReflection( xCoreReflection_ )
{
	aInterfaceSeq1.realloc( ARRAY_SIZE_STEP );
	aInterfaceSeq2.realloc( ARRAY_SIZE_STEP );

	// Property-Daten
	maAllPropertySeq.realloc( ARRAY_SIZE_STEP );
	maMapTypeSeq.realloc( ARRAY_SIZE_STEP );
	maPropertyConceptSeq.realloc( ARRAY_SIZE_STEP );

	mbFastPropSet = sal_False;
	mpOrgPropertyHandleArray = NULL;

	mnPropCount = 0;
	//mnDangerousPropCount = 0;
	mnPropertySetPropCount = 0;
	mnAttributePropCount = 0;
	mnMethodPropCount = 0;

	// Method-Daten
	mnMethCount = 0;

	// Eigenens RefCounting
	nRefCount = 0;
}

// Von Hand refcounten !!!


sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const ::rtl::OUString& aPropertyName ) const
{
	sal_Int32 iHashResult = -1;
	IntrospectionAccessStatic_Impl* pThis = (IntrospectionAccessStatic_Impl*)this;
	IntrospectionNameMap::iterator aIt = pThis->maPropertyNameMap.find( aPropertyName );
	if( !( aIt == pThis->maPropertyNameMap.end() ) )
		iHashResult = (*aIt).second;
	return iHashResult;
}

sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const ::rtl::OUString& aMethodName ) const
{
	sal_Int32 iHashResult = -1;
	IntrospectionAccessStatic_Impl* pThis = (IntrospectionAccessStatic_Impl*)this;
	IntrospectionNameMap::iterator aIt = pThis->maMethodNameMap.find( aMethodName );
	if( !( aIt == pThis->maMethodNameMap.end() ) )
	{
		iHashResult = (*aIt).second;
	}
	// #95159 Check if full qualified name matches
	else
	{
		sal_Int32 nSearchFrom = aMethodName.getLength();
		nSearchFrom = aMethodName.getLength();
		while( true )
		{
			// Strategy: Search back until the first '_' is found
			sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom );
			if( nFound == -1 )
				break;

		    ::rtl::OUString aPureMethodName = aMethodName.copy( nFound + 1 );

			aIt = pThis->maMethodNameMap.find( aPureMethodName );
			if( !( aIt == pThis->maMethodNameMap.end() ) )
			{
				// Check if it can be a type?
				// Problem: Does not work if package names contain _ ?!
			    ::rtl::OUString aStr = aMethodName.copy( 0, nFound );
			    ::rtl::OUString aTypeName = aStr.replace( '_', '.' );
				Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName );
				if( xClass.is() )
				{
					// If this is a valid class it could be the right method

					// Could be the right method, type has to be checked
					iHashResult = (*aIt).second;

					const Reference<XIdlMethod>* pMethods = maAllMethodSeq.getConstArray();
					const Reference<XIdlMethod> xMethod = pMethods[ iHashResult ];

					Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass();
					if( xClass->equals( xMethClass ) )
					{
						break;
					}
					else
					{
						iHashResult = -1;

						// Could also be another method with the same name
						// Iterate over all methods
						sal_Int32 nLen = maAllMethodSeq.getLength();
						for( int i = 0 ; i < nLen ; ++i )
						{
							const Reference<XIdlMethod> xMethod2 = pMethods[ i ];

						    ::rtl::OUString aTestClassName = xMethod2->getDeclaringClass()->getName();
						    ::rtl::OUString aTestMethodName = xMethod2->getName();

							if( xMethod2->getName() == aPureMethodName )
							{
								Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();

								if( xClass->equals( xMethClass2 ) )
								{
									iHashResult = i;
									break;
								}
							}
						}

						if( iHashResult != -1 )
							break;
					}
				}
			}

			nSearchFrom = nFound - 1;
			if( nSearchFrom < 0 )
				break;
		}
	}
	return iHashResult;
}

void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const ::rtl::OUString& aPropertyName, const Any& aValue ) const
//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const ::rtl::OUString& aPropertyName, const Any& aValue ) const
{
	sal_Int32 i = getPropertyIndex( aPropertyName );
	if( i != -1 )
		setPropertyValueByIndex( obj, (sal_Int32)i, aValue );
	else
		throw UnknownPropertyException();
}

void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
{
	// Handelt es sich bei dem uebergebenen Objekt ueberhaupt um was passendes?
	TypeClass eObjType = obj.getValueType().getTypeClass();

	Reference<XInterface> xInterface;
	if( eObjType == TypeClass_INTERFACE )
	{
		xInterface = *( Reference<XInterface>*)obj.getValue();
	}
	else if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
	{
		throw IllegalArgumentException();
	}

	// Flags pruefen
	const Property* pProps = maAllPropertySeq.getConstArray();
	if( (pProps[ nSequenceIndex ].Attributes & READONLY) != 0 )
	{
		throw UnknownPropertyException();
	}

	const sal_Int16* pMapTypeArray = maMapTypeSeq.getConstArray();
	switch( pMapTypeArray[ nSequenceIndex ] )
	{
		case MAP_PROPERTY_SET:
		{
			// Property besorgen
			const Property& rProp = maAllPropertySeq.getConstArray()[ nSequenceIndex ];

			// Interface-Parameter auf den richtigen Typ bringen
			sal_Bool bUseCopy = sal_False;
			Any aRealValue;

			TypeClass eValType = aValue.getValueType().getTypeClass();
			if( eValType == TypeClass_INTERFACE )
			{
				Type aPropType = rProp.Type;
			    ::rtl::OUString aTypeName( aPropType.getTypeName() );
				Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName );
				//Reference<XIdlClass> xPropClass = rProp.Type;
				if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE )
				{
					Reference<XInterface> valInterface = *(Reference<XInterface>*)aValue.getValue();
					if( valInterface.is() )
					{
						//Any queryInterface( const Type& rType );
						aRealValue = valInterface->queryInterface( aPropType );
						if( aRealValue.hasValue() )
							bUseCopy = sal_True;
					}
				}
			}

			// Haben wir ein FastPropertySet und ein gueltiges Handle?
			// ACHTUNG: An dieser Stelle wird ausgenutzt, dass das PropertySet
			// zu Beginn des Introspection-Vorgangs abgefragt wird.
			sal_Int32 nOrgHandle;
			if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
			{
				// PropertySet-Interface holen
				Reference<XFastPropertySet> xFastPropSet = 
					Reference<XFastPropertySet>::query( xInterface );
				if( xFastPropSet.is() )
				{
					xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue );
				}
				else
				{
					// throw UnknownPropertyException
				}
			}
			// sonst eben das normale nehmen
			else
			{
				// PropertySet-Interface holen
				Reference<XPropertySet> xPropSet = 
					Reference<XPropertySet>::query( xInterface );
				if( xPropSet.is() )
				{
					xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue );
				}
				else
				{
					// throw UnknownPropertyException
				}
			}
		}
		break;

		case MAP_FIELD:
		{
			Reference<XIdlField> xField = (XIdlField*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get());
			Reference<XIdlField2> xField2(xField, UNO_QUERY);
			if( xField2.is() )
			{
				xField2->set( (Any&)obj, aValue );
				// IllegalArgumentException
				// NullPointerException
			} else
			if( xField.is() )
			{
				xField->set( obj, aValue );
				// IllegalArgumentException
				// NullPointerException
			}
			else
			{
				// throw IllegalArgumentException();
			}
		}
		break;

		case MAP_GETSET:
		case MAP_SETONLY:
		{
			// set-Methode holen
			Reference<XIdlMethod> xMethod = (XIdlMethod*)(aInterfaceSeq2.getConstArray()[ nSequenceIndex ].get());
			if( xMethod.is() )
			{
				Sequence<Any> args( 1 );
				args.getArray()[0] = aValue;
				xMethod->invoke( obj, args );
			}
			else
			{
				// throw IllegalArgumentException();
			}
		}
		break;
	}
}

Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const ::rtl::OUString& aPropertyName ) const
{
	sal_Int32 i = getPropertyIndex( aPropertyName );
	if( i != -1 )
		return getPropertyValueByIndex( obj, i );

	throw UnknownPropertyException();
}

Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const
{
	Any aRet;

	// Handelt es sich bei dem uebergebenen Objekt ueberhaupt um was passendes?
	TypeClass eObjType = obj.getValueType().getTypeClass();

	Reference<XInterface> xInterface;
	if( eObjType == TypeClass_INTERFACE )
	{
		xInterface = *(Reference<XInterface>*)obj.getValue();
	}
	else if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
	{
		// throw IllegalArgumentException();
		return aRet;
	}

	const sal_Int16* pMapTypeArray = maMapTypeSeq.getConstArray();
	switch( pMapTypeArray[ nSequenceIndex ] )
	{
		case MAP_PROPERTY_SET:
		{
			// Property besorgen
			const Property& rProp = maAllPropertySeq.getConstArray()[ nSequenceIndex ];

			// Haben wir ein FastPropertySet und ein gueltiges Handle?
			// ACHTUNG: An dieser Stelle wird ausgenutzt, dass das PropertySet
			// zu Beginn des Introspection-Vorgangs abgefragt wird.
			sal_Int32 nOrgHandle;
			if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
			{
				// PropertySet-Interface holen
				Reference<XFastPropertySet> xFastPropSet = 
					Reference<XFastPropertySet>::query( xInterface );
				if( xFastPropSet.is() )
				{
					aRet = xFastPropSet->getFastPropertyValue( nOrgHandle);
				}
				else
				{
					// throw UnknownPropertyException
					return aRet;
				}
			}
			// sonst eben das normale nehmen
			else
			{
				// PropertySet-Interface holen
				Reference<XPropertySet> xPropSet = 
					Reference<XPropertySet>::query( xInterface );
				if( xPropSet.is() )
				{
					aRet = xPropSet->getPropertyValue( rProp.Name );
				}
				else
				{
					// throw UnknownPropertyException
					return aRet;
				}
			}
		}
		break;

		case MAP_FIELD:
		{
			Reference<XIdlField> xField = (XIdlField*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get());
			if( xField.is() )
			{
				aRet = xField->get( obj );
				// IllegalArgumentException
				// NullPointerException
			}
			else
			{
				// throw IllegalArgumentException();
				return aRet;
			}
		}
		break;

		case MAP_GETSET:
		{
			// get-Methode holen
			Reference<XIdlMethod> xMethod = (XIdlMethod*)(aInterfaceSeq1.getConstArray()[ nSequenceIndex ].get());
			if( xMethod.is() )
			{
				Sequence<Any> args;
				aRet = xMethod->invoke( obj, args );
			}
			else
			{
				// throw IllegalArgumentException();
				return aRet;
			}
		}
		break;

		case MAP_SETONLY:
			// get-Methode gibt es nicht
			// throw WriteOnlyPropertyException();
			return aRet;
	}
	return aRet;
}


// Hilfs-Methoden zur Groessen-Anpassung der Sequences
void IntrospectionAccessStatic_Impl::checkPropertyArraysSize
( 
	Property*& rpAllPropArray, 
	sal_Int16*& rpMapTypeArray,
	sal_Int32*& rpPropertyConceptArray,
	sal_Int32 iNextIndex
)
{
	sal_Int32 nLen = maAllPropertySeq.getLength();
	if( iNextIndex >= nLen )
	{
		maAllPropertySeq.realloc( nLen + ARRAY_SIZE_STEP );
		rpAllPropArray = maAllPropertySeq.getArray();

		maMapTypeSeq.realloc( nLen + ARRAY_SIZE_STEP );
		rpMapTypeArray = maMapTypeSeq.getArray();

		maPropertyConceptSeq.realloc( nLen + ARRAY_SIZE_STEP );
		rpPropertyConceptArray = maPropertyConceptSeq.getArray();
	}
}

void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( Sequence< Reference<XInterface> >& rSeq,
	Reference<XInterface>*& rpInterfaceArray, sal_Int32 iNextIndex )
{
	sal_Int32 nLen = rSeq.getLength();
	if( iNextIndex >= nLen )
	{
		// Neue Groesse mit ARRAY_SIZE_STEP abgleichen
		sal_Int32 nMissingSize = iNextIndex - nLen + 1;
		sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1;
		sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP;

		rSeq.realloc( nNewSize );
		rpInterfaceArray = rSeq.getArray();
	}
}


//*******************************
//*** ImplIntrospectionAccess ***
//*******************************

// Neue Impl-Klasse im Rahmen der Introspection-Umstellung auf Instanz-gebundene
// Introspection mit Property-Zugriff ueber XPropertySet. Die alte Klasse
// ImplIntrospectionAccess lebt als IntrospectionAccessStatic_Impl
class ImplIntrospectionAccess : public IntrospectionAccessHelper
{
	friend class ImplIntrospection;

	// Untersuchtes Objekt
	Any maInspectedObject;

	// Als Interface
	Reference<XInterface> mxIface;

	// Statische Daten der Introspection
	IntrospectionAccessStatic_Impl* mpStaticImpl;

	// Adapter-Implementation
    WeakReference< XInterface > maAdapter;

	// Letzte Sequence, die bei getProperties geliefert wurde (Optimierung)
    Sequence<Property> maLastPropertySeq;
	sal_Int32 mnLastPropertyConcept;

	// Letzte Sequence, die bei getMethods geliefert wurde (Optimierung)
    Sequence<Reference<XIdlMethod> > maLastMethodSeq;
	sal_Int32 mnLastMethodConcept;

public:
	ImplIntrospectionAccess( const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ );
	~ImplIntrospectionAccess();

	// Methoden von XIntrospectionAccess
    virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts(void)
		throw( RuntimeException );
    virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts(void)
		throw( RuntimeException );
    virtual Property SAL_CALL getProperty(const ::rtl::OUString& Name, sal_Int32 PropertyConcepts)
		throw( NoSuchElementException, RuntimeException );
    virtual sal_Bool SAL_CALL hasProperty(const ::rtl::OUString& Name, sal_Int32 PropertyConcepts)
		throw( RuntimeException );
    virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts)
	  	throw( RuntimeException );
    virtual Reference<XIdlMethod> SAL_CALL getMethod(const ::rtl::OUString& Name, sal_Int32 MethodConcepts)
	  	throw( NoSuchMethodException, RuntimeException );
    virtual sal_Bool SAL_CALL hasMethod(const ::rtl::OUString& Name, sal_Int32 MethodConcepts)
	  	throw( RuntimeException );
    virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts)
	  	throw( RuntimeException );
    virtual Sequence< Type > SAL_CALL getSupportedListeners(void)
	  	throw( RuntimeException );
    using OWeakObject::queryAdapter;
    virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType )
	  	throw( IllegalTypeException, RuntimeException );

	// Methoden von XMaterialHolder
    virtual Any SAL_CALL getMaterial(void) throw(RuntimeException);

	// Methoden von XExactName
    virtual ::rtl::OUString SAL_CALL getExactName( const ::rtl::OUString& rApproximateName ) throw( RuntimeException );
};

ImplIntrospectionAccess::ImplIntrospectionAccess
	( const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ )
		: maInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ), maAdapter()
{
	mpStaticImpl->acquire();

	// Objekt als Interface merken, wenn moeglich
	TypeClass eType = maInspectedObject.getValueType().getTypeClass();
	if( eType == TypeClass_INTERFACE )
		mxIface = *(Reference<XInterface>*)maInspectedObject.getValue();

	mnLastPropertyConcept = -1;
	mnLastMethodConcept = -1;
}

ImplIntrospectionAccess::~ImplIntrospectionAccess()
{
	mpStaticImpl->release();
}


//*******************************
//*** ImplIntrospectionAdapter ***
//*******************************

// Neue Impl-Klasse im Rahmen der Introspection-Umstellung auf Instanz-gebundene
// Introspection mit Property-Zugriff ueber XPropertySet. Die alte Klasse
// ImplIntrospectionAccess lebt als IntrospectionAccessStatic_Impl
class ImplIntrospectionAdapter : 
	public XPropertySet, public XFastPropertySet, public XPropertySetInfo, 
	public XNameContainer, public XIndexContainer,
	public XEnumerationAccess, public  XIdlArray,
	public OWeakObject
{
	// Parent-Objekt
    ::rtl::Reference< ImplIntrospectionAccess > mpAccess;

	// Untersuchtes Objekt
	const Any& mrInspectedObject;
    
	// Statische Daten der Introspection
	IntrospectionAccessStatic_Impl* mpStaticImpl;

	// Objekt als Interface
	Reference<XInterface> mxIface;

	// Original-Interfaces des Objekts
	Reference<XElementAccess>		mxObjElementAccess;
	Reference<XNameContainer>		mxObjNameContainer;
	Reference<XNameAccess>			mxObjNameAccess;
	Reference<XIndexAccess>			mxObjIndexAccess;
	Reference<XIndexContainer>		mxObjIndexContainer;
	Reference<XEnumerationAccess>	mxObjEnumerationAccess;
	Reference<XIdlArray>			mxObjIdlArray;

public:
	ImplIntrospectionAdapter( ImplIntrospectionAccess* pAccess_, 
		const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ );
	~ImplIntrospectionAdapter();

	// Methoden von XInterface
    virtual Any SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException );
	virtual void		SAL_CALL acquire() throw() { OWeakObject::acquire(); }
	virtual void		SAL_CALL release() throw() { OWeakObject::release(); }

	// Methoden von XPropertySet
	virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() throw( RuntimeException );
    virtual void SAL_CALL setPropertyValue(const ::rtl::OUString& aPropertyName, const Any& aValue)
		throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException );
    virtual Any SAL_CALL getPropertyValue(const ::rtl::OUString& aPropertyName)
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL addPropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) 
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL removePropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) 
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL addVetoableChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) 
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL removeVetoableChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) 
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );

	// Methoden von XFastPropertySet
	virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue)
		throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException );
	virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle)
		throw( UnknownPropertyException, WrappedTargetException, RuntimeException );

	// Methoden von XPropertySetInfo
	virtual Sequence< Property > SAL_CALL getProperties(void) throw( RuntimeException );
	virtual Property SAL_CALL getPropertyByName(const ::rtl::OUString& Name) throw( RuntimeException );
	virtual sal_Bool SAL_CALL hasPropertyByName(const ::rtl::OUString& Name) throw( RuntimeException );

	// Methoden von XElementAccess
    virtual Type SAL_CALL getElementType(void) throw( RuntimeException );
    virtual sal_Bool SAL_CALL hasElements(void) throw( RuntimeException );

	// Methoden von XNameAccess
    virtual Any SAL_CALL getByName(const ::rtl::OUString& Name)
		throw( NoSuchElementException, WrappedTargetException, RuntimeException );
    virtual Sequence< ::rtl::OUString > SAL_CALL getElementNames(void) throw( RuntimeException );
    virtual sal_Bool SAL_CALL hasByName(const ::rtl::OUString& Name) throw( RuntimeException );

	// Methoden von XNameContainer
	virtual void SAL_CALL insertByName(const ::rtl::OUString& Name, const Any& Element)
		throw( IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException );
	virtual void SAL_CALL replaceByName(const ::rtl::OUString& Name, const Any& Element)
		throw( IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException );
	virtual void SAL_CALL removeByName(const ::rtl::OUString& Name)
		throw( NoSuchElementException, WrappedTargetException, RuntimeException );

	// Methoden von XIndexAccess
    virtual sal_Int32 SAL_CALL getCount(void) throw( RuntimeException );
    virtual Any SAL_CALL getByIndex(sal_Int32 Index)
		throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException );

	// Methoden von XIndexContainer
	virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) 
		throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException );
	virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element)
		throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException );
	virtual void SAL_CALL removeByIndex(sal_Int32 Index)
		throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException );

	// Methoden von XEnumerationAccess
	virtual Reference<XEnumeration> SAL_CALL createEnumeration(void) throw( RuntimeException );

	// Methoden von XIdlArray
	virtual void SAL_CALL realloc(Any& array, sal_Int32 length)
		throw( IllegalArgumentException, RuntimeException );
	virtual sal_Int32 SAL_CALL getLen(const Any& array) throw( IllegalArgumentException, RuntimeException );
	virtual Any SAL_CALL get(const Any& array, sal_Int32 index)
		throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException );
	virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value)
		throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException );
};

ImplIntrospectionAdapter::ImplIntrospectionAdapter( ImplIntrospectionAccess* pAccess_, 
	const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ )
		: mpAccess( pAccess_), mrInspectedObject( obj ), mpStaticImpl( pStaticImpl_ )
{
	mpStaticImpl->acquire();

	// Objekt als Interfaceholen
	TypeClass eType = mrInspectedObject.getValueType().getTypeClass();
	if( eType == TypeClass_INTERFACE )
	{
		mxIface = *( Reference< XInterface >*)mrInspectedObject.getValue();

		mxObjElementAccess = Reference<XElementAccess>::query( mxIface );
		mxObjNameAccess = Reference<XNameAccess>::query( mxIface );
		mxObjNameContainer = Reference<XNameContainer>::query( mxIface );
		mxObjIndexAccess = Reference<XIndexAccess>::query( mxIface );
		mxObjIndexContainer = Reference<XIndexContainer>::query( mxIface );
		mxObjEnumerationAccess = Reference<XEnumerationAccess>::query( mxIface );
		mxObjIdlArray = Reference<XIdlArray>::query( mxIface );
	}
}

ImplIntrospectionAdapter::~ImplIntrospectionAdapter()
{
	mpStaticImpl->release();
}

// Methoden von XInterface
Any SAL_CALL ImplIntrospectionAdapter::queryInterface( const Type& rType ) 
	throw( RuntimeException )
{
	Any aRet( ::cppu::queryInterface(
		rType,
		static_cast< XPropertySet * >( this ),
		static_cast< XFastPropertySet * >( this ),
		static_cast< XPropertySetInfo * >( this ) ) );
	if( !aRet.hasValue() )
		aRet = OWeakObject::queryInterface( rType );

	if( !aRet.hasValue() )
	{
		// Wrapper fuer die Objekt-Interfaces
		if(   ( mxObjElementAccess.is() && (aRet = ::cppu::queryInterface
					( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() )
			|| ( mxObjNameAccess.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() )
			|| ( mxObjNameContainer.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() )
			|| ( mxObjIndexAccess.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() )
			|| ( mxObjIndexContainer.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() )
			|| ( mxObjEnumerationAccess	.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() )
			|| ( mxObjIdlArray.is() && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() ) 
		  )
		{
		}
	}
	return aRet;
}


//***************************************************
//*** Implementation von ImplIntrospectionAdapter ***
//***************************************************

// Methoden von XPropertySet
Reference<XPropertySetInfo> ImplIntrospectionAdapter::getPropertySetInfo(void)
	throw( RuntimeException )
{
	return (XPropertySetInfo *)this;
}

void ImplIntrospectionAdapter::setPropertyValue(const ::rtl::OUString& aPropertyName, const Any& aValue)
	throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
{
	mpStaticImpl->setPropertyValue( mrInspectedObject, aPropertyName, aValue );
}

Any ImplIntrospectionAdapter::getPropertyValue(const ::rtl::OUString& aPropertyName)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	return mpStaticImpl->getPropertyValue( mrInspectedObject, aPropertyName );
}

void ImplIntrospectionAdapter::addPropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	if( mxIface.is() )
	{
		Reference<XPropertySet> xPropSet = 
			Reference<XPropertySet>::query( mxIface );
		//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
		if( xPropSet.is() )
			xPropSet->addPropertyChangeListener(aPropertyName, aListener);
	}
}

void ImplIntrospectionAdapter::removePropertyChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	if( mxIface.is() )
	{
		Reference<XPropertySet> xPropSet = 
			Reference<XPropertySet>::query( mxIface );
		//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
		if( xPropSet.is() )
			xPropSet->removePropertyChangeListener(aPropertyName, aListener);
	}
}

void ImplIntrospectionAdapter::addVetoableChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	if( mxIface.is() )
	{
		Reference<XPropertySet> xPropSet = 
			Reference<XPropertySet>::query( mxIface );
		//Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
		if( xPropSet.is() )
			xPropSet->addVetoableChangeListener(aPropertyName, aListener);
	}
}

void ImplIntrospectionAdapter::removeVetoableChangeListener(const ::rtl::OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	if( mxIface.is() )
	{
		Reference<XPropertySet> xPropSet = 
			Reference<XPropertySet>::query( mxIface );
		if( xPropSet.is() )
			xPropSet->removeVetoableChangeListener(aPropertyName, aListener);
	}
}


// Methoden von XFastPropertySet
void ImplIntrospectionAdapter::setFastPropertyValue(sal_Int32, const Any&)
	throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
{
}

Any ImplIntrospectionAdapter::getFastPropertyValue(sal_Int32)
	throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
{
	return Any();
}

// Methoden von XPropertySetInfo
Sequence< Property > ImplIntrospectionAdapter::getProperties(void) throw( RuntimeException )
{
	return mpStaticImpl->getProperties();
}

Property ImplIntrospectionAdapter::getPropertyByName(const ::rtl::OUString& Name)
	throw( RuntimeException )
{
	return mpAccess->getProperty( Name, PropertyConcept::ALL );
}

sal_Bool ImplIntrospectionAdapter::hasPropertyByName(const ::rtl::OUString& Name)
	throw( RuntimeException )
{
	return mpAccess->hasProperty( Name, PropertyConcept::ALL );
}

// Methoden von XElementAccess
Type ImplIntrospectionAdapter::getElementType(void) throw( RuntimeException )
{
	return mxObjElementAccess->getElementType();
}

sal_Bool ImplIntrospectionAdapter::hasElements(void) throw( RuntimeException )
{
	return mxObjElementAccess->hasElements();
}

// Methoden von XNameAccess
Any ImplIntrospectionAdapter::getByName(const ::rtl::OUString& Name)
	throw( NoSuchElementException, WrappedTargetException, RuntimeException )
{
	return mxObjNameAccess->getByName( Name );
}

Sequence< ::rtl::OUString > ImplIntrospectionAdapter::getElementNames(void)
	throw( RuntimeException )
{
	return mxObjNameAccess->getElementNames();
}

sal_Bool ImplIntrospectionAdapter::hasByName(const ::rtl::OUString& Name)
	throw( RuntimeException )
{
	return mxObjNameAccess->hasByName( Name );
}

// Methoden von XNameContainer
void ImplIntrospectionAdapter::insertByName(const ::rtl::OUString& Name, const Any& Element)
	throw( IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException )
{
	mxObjNameContainer->insertByName( Name, Element );
}

void ImplIntrospectionAdapter::replaceByName(const ::rtl::OUString& Name, const Any& Element)
	throw( IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException )
{
	mxObjNameContainer->replaceByName( Name, Element );
}

void ImplIntrospectionAdapter::removeByName(const ::rtl::OUString& Name)
	throw( NoSuchElementException, WrappedTargetException, RuntimeException )
{
	mxObjNameContainer->removeByName( Name );
}

// Methoden von XIndexAccess
// Schon in XNameAccess: virtual Reference<XIdlClass> getElementType(void) const
sal_Int32 ImplIntrospectionAdapter::getCount(void) throw( RuntimeException )
{
	return mxObjIndexAccess->getCount();
}

Any ImplIntrospectionAdapter::getByIndex(sal_Int32 Index)
	throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
{
	return mxObjIndexAccess->getByIndex( Index );
}

// Methoden von XIndexContainer
void ImplIntrospectionAdapter::insertByIndex(sal_Int32 Index, const Any& Element)
	throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
{
	mxObjIndexContainer->insertByIndex( Index, Element );
}

void ImplIntrospectionAdapter::replaceByIndex(sal_Int32 Index, const Any& Element)
	throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
{
	mxObjIndexContainer->replaceByIndex( Index, Element );
}

void ImplIntrospectionAdapter::removeByIndex(sal_Int32 Index)
	throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
{
	mxObjIndexContainer->removeByIndex( Index );
}

// Methoden von XEnumerationAccess
// Schon in XNameAccess: virtual Reference<XIdlClass> getElementType(void) const;
Reference<XEnumeration> ImplIntrospectionAdapter::createEnumeration(void) throw( RuntimeException )
{
	return mxObjEnumerationAccess->createEnumeration();
}

// Methoden von XIdlArray
void ImplIntrospectionAdapter::realloc(Any& array, sal_Int32 length)
	throw( IllegalArgumentException, RuntimeException )
{
	mxObjIdlArray->realloc( array, length );
}

sal_Int32 ImplIntrospectionAdapter::getLen(const Any& array)
	throw( IllegalArgumentException, RuntimeException )
{
	return mxObjIdlArray->getLen( array );
}

Any ImplIntrospectionAdapter::get(const Any& array, sal_Int32 index)
	throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException )
{
	return mxObjIdlArray->get( array, index );
}

void ImplIntrospectionAdapter::set(Any& array, sal_Int32 index, const Any& value)
	throw( IllegalArgumentException, ArrayIndexOutOfBoundsException, RuntimeException )
{
	mxObjIdlArray->set( array, index, value );
}


//**************************************************
//*** Implementation von ImplIntrospectionAccess ***
//**************************************************

// Methoden von XIntrospectionAccess
sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts(void)
	throw( RuntimeException )
{
	return	MethodConcept::DANGEROUS |
			PROPERTY |
			LISTENER |
			ENUMERATION |
			NAMECONTAINER |
			INDEXCONTAINER;
}

sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts(void)
	throw( RuntimeException )
{
	return	PropertyConcept::DANGEROUS |
			PROPERTYSET |
			ATTRIBUTES |
			METHODS;
}

Property ImplIntrospectionAccess::getProperty(const ::rtl::OUString& Name, sal_Int32 PropertyConcepts)
	throw( NoSuchElementException, RuntimeException )
{
	Property aRet;
	sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
	sal_Bool bFound = sal_False;
	if( i != -1 )
	{
		sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts().getConstArray()[ i ];
		if( (PropertyConcepts & nConcept) != 0 )
		{
			const Property* pProps = mpStaticImpl->getProperties().getConstArray();
			aRet = pProps[ i ];
			bFound = sal_True;
		}
	}
	if( !bFound )
		throw NoSuchElementException() ;
	return aRet;
}

sal_Bool ImplIntrospectionAccess::hasProperty(const ::rtl::OUString& Name, sal_Int32 PropertyConcepts)
	throw( RuntimeException )
{
	sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
	sal_Bool bRet = sal_False;
	if( i != -1 )
	{
		sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts().getConstArray()[ i ];
		if( (PropertyConcepts & nConcept) != 0 )
			bRet = sal_True;
	}
	return bRet;
}

Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts)
	throw( RuntimeException )
{
	// Wenn alle unterstuetzten Konzepte gefordert werden, Sequence einfach durchreichen
	sal_Int32 nAllSupportedMask =	PROPERTYSET | 
									ATTRIBUTES | 
									METHODS;
	if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask )
	{
		return mpStaticImpl->getProperties();
	}

	// Gleiche Sequence wie beim vorigen mal?
	if( mnLastPropertyConcept == PropertyConcepts )
	{
		return maLastPropertySeq;
	}

	// Anzahl der zu liefernden Properties
	sal_Int32 nCount = 0;

	// Es gibt zur Zeit keine DANGEROUS-Properties
	// if( PropertyConcepts & DANGEROUS )
	//	nCount += mpStaticImpl->mnDangerousPropCount;
	if( PropertyConcepts & PROPERTYSET )
		nCount += mpStaticImpl->mnPropertySetPropCount;
	if( PropertyConcepts & ATTRIBUTES )
		nCount += mpStaticImpl->mnAttributePropCount;
	if( PropertyConcepts & METHODS )
		nCount += mpStaticImpl->mnMethodPropCount;

	// Sequence entsprechend der geforderten Anzahl reallocieren
	ImplIntrospectionAccess* pThis = (ImplIntrospectionAccess*)this;	// const umgehen
	pThis->maLastPropertySeq.realloc( nCount );
	Property* pDestProps = pThis->maLastPropertySeq.getArray();

	// Alle Properties durchgehen und entsprechend der Concepte uebernehmen
	Sequence<Property> aPropSeq = mpStaticImpl->getProperties();
	const Property* pSourceProps = aPropSeq.getConstArray();
	const sal_Int32* pConcepts = mpStaticImpl->getPropertyConcepts().getConstArray();
	sal_Int32 nLen = aPropSeq.getLength();

	sal_Int32 iDest = 0;
	for( sal_Int32 i = 0 ; i < nLen ; i++ )
	{
		sal_Int32 nConcept = pConcepts[ i ];
		if( nConcept & PropertyConcepts )
			pDestProps[ iDest++ ] = pSourceProps[ i ];

		/*
		// Property mit Concepts ausgeben
	    ::rtl::OUString aPropName = pSourceProps[ i ].Name;
		String aNameStr = OOUStringToString(aPropName, CHARSET_SYSTEM);
		String ConceptStr;
		if( nConcept & PROPERTYSET )
			ConceptStr += "PROPERTYSET";
		if( nConcept & ATTRIBUTES )
			ConceptStr += "ATTRIBUTES";
		if( nConcept & METHODS )
			ConceptStr += "METHODS";
		printf( "Property %ld: %s, Concept = %s\n", i, aNameStr.GetStr(), ConceptStr.GetStr() );
		*/
	}

	// PropertyConcept merken, dies entspricht maLastPropertySeq
	pThis->mnLastPropertyConcept = PropertyConcepts;

	// Zusammengebastelte Sequence liefern
	return maLastPropertySeq;
}

Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const ::rtl::OUString& Name, sal_Int32 MethodConcepts)
	throw( NoSuchMethodException, RuntimeException )
{
	Reference<XIdlMethod> xRet;
	sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
	if( i != -1 )
	{

		sal_Int32 nConcept = mpStaticImpl->getMethodConcepts().getConstArray()[ i ];
		if( (MethodConcepts & nConcept) != 0 )
		{
			const Reference<XIdlMethod>* pMethods = mpStaticImpl->getMethods().getConstArray();
			xRet = pMethods[i];
		}
	}
	if( !xRet.is() )
		throw NoSuchMethodException();
	return xRet;
}

sal_Bool ImplIntrospectionAccess::hasMethod(const ::rtl::OUString& Name, sal_Int32 MethodConcepts)
	throw( RuntimeException )
{
	sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
	sal_Bool bRet = sal_False;
	if( i != -1 )
	{
		sal_Int32 nConcept = mpStaticImpl->getMethodConcepts().getConstArray()[ i ];
		if( (MethodConcepts & nConcept) != 0 )
			bRet = sal_True;
	}
	return bRet;
}

Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts)
	throw( RuntimeException )
{
	ImplIntrospectionAccess* pThis = (ImplIntrospectionAccess*)this;	// const umgehen

	// Wenn alle unterstuetzten Konzepte gefordert werden, Sequence einfach durchreichen
	sal_Int32 nAllSupportedMask = 	MethodConcept::DANGEROUS |
									PROPERTY |
									LISTENER |
									ENUMERATION |
									NAMECONTAINER |
									INDEXCONTAINER |
									MethodConcept_NORMAL_IMPL;
	if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask )
	{
		return mpStaticImpl->getMethods();
	}

	// Gleiche Sequence wie beim vorigen mal?
	if( mnLastMethodConcept == MethodConcepts )
	{
		return maLastMethodSeq;
	}

	// Methoden-Sequences besorgen
	Sequence< Reference<XIdlMethod> > aMethodSeq = mpStaticImpl->getMethods();
	const Reference<XIdlMethod>* pSourceMethods = aMethodSeq.getConstArray();
	const sal_Int32* pConcepts = mpStaticImpl->getMethodConcepts().getConstArray();
	sal_Int32 nLen = aMethodSeq.getLength();

	// Sequence entsprechend der geforderten Anzahl reallocieren
	// Anders als bei den Properties kann die Anzahl nicht durch
	// Zaehler in inspect() vorher ermittelt werden, da Methoden 
	// mehreren Konzepten angehoeren koennen
	pThis->maLastMethodSeq.realloc( nLen );
	Reference<XIdlMethod>* pDestMethods = pThis->maLastMethodSeq.getArray();

	// Alle Methods durchgehen und entsprechend der Concepte uebernehmen
	sal_Int32 iDest = 0;
	for( sal_Int32 i = 0 ; i < nLen ; i++ )
	{
		sal_Int32 nConcept = pConcepts[ i ];
		if( nConcept & MethodConcepts )
			pDestMethods[ iDest++ ] = pSourceMethods[ i ];

    #if OSL_DEBUG_LEVEL > 0
        static bool debug = false;
        if ( debug )
        {
		    // Methode mit Concepts ausgeben
		    const Reference< XIdlMethod >& rxMethod = pSourceMethods[ i ];
            ::rtl::OString aNameStr = ::rtl::OUStringToOString( rxMethod->getName(), osl_getThreadTextEncoding() );
		    ::rtl::OString ConceptStr;
            if( nConcept & MethodConcept::DANGEROUS )
			    ConceptStr += "DANGEROUS |";
		    if( nConcept & MethodConcept::PROPERTY )
			    ConceptStr += "PROPERTY |";
		    if( nConcept & MethodConcept::LISTENER )
			    ConceptStr += "LISTENER |";
		    if( nConcept & MethodConcept::ENUMERATION )
			    ConceptStr += "ENUMERATION |";
		    if( nConcept & MethodConcept::NAMECONTAINER )
			    ConceptStr += "NAMECONTAINER |";
		    if( nConcept & MethodConcept::INDEXCONTAINER )
			    ConceptStr += "INDEXCONTAINER |";
		    OSL_TRACE( "Method %ld: %s, Concepts = %s", i, aNameStr.getStr(), ConceptStr.getStr() );
        }
    #endif
	}

	// Auf die richtige Laenge bringen
	pThis->maLastMethodSeq.realloc( iDest );

	// MethodConcept merken, dies entspricht maLastMethodSeq
	pThis->mnLastMethodConcept = MethodConcepts;

	// Zusammengebastelte Sequence liefern
	return maLastMethodSeq;
}

Sequence< Type > ImplIntrospectionAccess::getSupportedListeners(void)
	throw( RuntimeException )
{
	return mpStaticImpl->getSupportedListeners();
}

Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType )
	throw( IllegalTypeException, RuntimeException )
{
	// Gibt es schon einen Adapter?
    Reference< XInterface > xAdapter( maAdapter );
	if( !xAdapter.is() )
	{
        xAdapter = *( new ImplIntrospectionAdapter( this, maInspectedObject, mpStaticImpl ) );
        maAdapter = xAdapter;
	}

	Reference<XInterface> xRet;
	xAdapter->queryInterface( rType ) >>= xRet;
	return xRet;
}

// Methoden von XMaterialHolder
Any ImplIntrospectionAccess::getMaterial(void) throw(RuntimeException)
{
	return maInspectedObject;
}

// Hilfs-Funktion zur LowerCase-Wandlung eines ::rtl::OUString
::rtl::OUString toLower( ::rtl::OUString aUStr )
{
	// Tabelle fuer XExactName pflegen
    ::rtl::OUString aOWStr( aUStr.getStr() );
	::rtl::OUString aOWLowerStr = aOWStr.toAsciiLowerCase();
    ::rtl::OUString aLowerUStr( aOWLowerStr.getStr() );
	return aLowerUStr;
}

// Methoden von XExactName
::rtl::OUString ImplIntrospectionAccess::getExactName( const ::rtl::OUString& rApproximateName ) throw( RuntimeException )
{
    ::rtl::OUString aRetStr;
	LowerToExactNameMap::iterator aIt = 
		mpStaticImpl->maLowerToExactNameMap.find( toLower( rApproximateName ) );
	if( !( aIt == mpStaticImpl->maLowerToExactNameMap.end() ) )
		aRetStr = (*aIt).second;
	return aRetStr;
}


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

#ifdef USE_INTROSPECTION_CACHE

struct hashIntrospectionKey_Impl
{
	Sequence< Reference<XIdlClass> >	aIdlClasses;
	Reference<XPropertySetInfo>			xPropInfo;
	Reference<XIdlClass>				xImplClass;
	sal_Int32							nHitCount;

	void	IncHitCount() const { ((hashIntrospectionKey_Impl*)this)->nHitCount++; }
	hashIntrospectionKey_Impl() : nHitCount( 0 ) {}
	hashIntrospectionKey_Impl( const Sequence< Reference<XIdlClass> > & rIdlClasses, 
										const Reference<XPropertySetInfo> & rxPropInfo,
										const Reference<XIdlClass> & rxImplClass );
};

hashIntrospectionKey_Impl::hashIntrospectionKey_Impl
(
	const Sequence< Reference<XIdlClass> > & rIdlClasses, 
	const Reference<XPropertySetInfo> & rxPropInfo,
	const Reference<XIdlClass> & rxImplClass 
)
		: aIdlClasses( rIdlClasses )
		, xPropInfo( rxPropInfo )
		, xImplClass( rxImplClass )
		, nHitCount( 0 )
{}


struct hashIntrospectionAccessCache_Impl
{
	size_t operator()(const hashIntrospectionKey_Impl & rObj ) const
	{
		return (size_t)rObj.xImplClass.get() ^ (size_t)rObj.xPropInfo.get();
	}

	bool operator()( const hashIntrospectionKey_Impl & rObj1,
					 const hashIntrospectionKey_Impl & rObj2 ) const
	{
		if( rObj1.xPropInfo != rObj2.xPropInfo
		  || rObj1.xImplClass != rObj2.xImplClass )
			return sal_False;

		sal_Int32 nCount1 = rObj1.aIdlClasses.getLength();
		sal_Int32 nCount2 = rObj2.aIdlClasses.getLength();
		if( nCount1 != nCount2 )
			return sal_False;

		const Reference<XIdlClass>* pRefs1 = rObj1.aIdlClasses.getConstArray();
		const Reference<XIdlClass>* pRefs2 = rObj2.aIdlClasses.getConstArray();
		return memcmp( pRefs1, pRefs2, nCount1 * sizeof( Reference<XIdlClass> ) ) == 0;
	}

};

typedef std::hash_map
<
	hashIntrospectionKey_Impl,
	IntrospectionAccessStatic_Impl*,
	hashIntrospectionAccessCache_Impl,
	hashIntrospectionAccessCache_Impl
>
IntrospectionAccessCacheMap_Impl;

class IntrospectionAccessCacheMap : public IntrospectionAccessCacheMap_Impl
{
public:
 	~IntrospectionAccessCacheMap()
 	{
 		IntrospectionAccessCacheMap::iterator iter = begin();
 		IntrospectionAccessCacheMap::iterator stop = this->end();
 		while( iter != stop )
 		{
	
			(*iter).second->release();
			(*iter).second = NULL;
			iter++;
		}
	}
};


// For XTypeProvider
struct hashTypeProviderKey_Impl
{
	Reference<XPropertySetInfo>			xPropInfo;
	Sequence< sal_Int8 >				maImpIdSeq;
	sal_Int32							nHitCount;

	void	IncHitCount() const { ((hashTypeProviderKey_Impl*)this)->nHitCount++; }
	hashTypeProviderKey_Impl() : nHitCount( 0 ) {}
	hashTypeProviderKey_Impl( const Reference<XPropertySetInfo> & rxPropInfo, const Sequence< sal_Int8 > & aImpIdSeq_ );
};

hashTypeProviderKey_Impl::hashTypeProviderKey_Impl
( 
	const Reference<XPropertySetInfo> & rxPropInfo, 
	const Sequence< sal_Int8 > & aImpIdSeq_
)
	: xPropInfo( rxPropInfo )
	, maImpIdSeq( aImpIdSeq_ )
	, nHitCount( 0 )
{}


struct TypeProviderAccessCache_Impl
{
	size_t operator()(const hashTypeProviderKey_Impl & rObj ) const;

	bool operator()( const hashTypeProviderKey_Impl & rObj1,
					 const hashTypeProviderKey_Impl & rObj2 ) const
	{
		if( rObj1.xPropInfo != rObj2.xPropInfo )
			return sal_False;

		bool bEqual = false;
		sal_Int32 nLen1 = rObj1.maImpIdSeq.getLength();
		sal_Int32 nLen2 = rObj2.maImpIdSeq.getLength();
		if( nLen1 == nLen2 && nLen1 > 0 )
		{
			const sal_Int8* pId1 = rObj1.maImpIdSeq.getConstArray();
			const sal_Int8* pId2 = rObj2.maImpIdSeq.getConstArray();
			bEqual = (memcmp( pId1, pId2, nLen1 * sizeof( sal_Int8 ) ) == 0 );
		}
		return bEqual;
	}
};

size_t TypeProviderAccessCache_Impl::operator()(const hashTypeProviderKey_Impl & rObj ) const
{
	const sal_Int32* pBytesAsInt32Array = (const sal_Int32*)rObj.maImpIdSeq.getConstArray();
	sal_Int32 nLen = rObj.maImpIdSeq.getLength();
	sal_Int32 nCount32 = nLen / 4;
	sal_Int32 nMod32 = nLen % 4;

	// XOR with full 32 bit values
	sal_Int32 nId32 = 0;
	sal_Int32 i;
	for( i = 0 ; i < nCount32 ; i++ )
		nId32 ^= *(pBytesAsInt32Array++);

	// XOR with remaining byte values
	if( nMod32 )
	{
		const sal_Int8* pBytes = (const sal_Int8*)pBytesAsInt32Array;
		sal_Int8* pInt8_Id32 = (sal_Int8*)&nId32;
		for( i = 0 ; i < nMod32 ; i++ )
			*(pInt8_Id32++) ^= *(pBytes++);
	}

	return (size_t)nId32;
}


typedef std::hash_map
<
	hashTypeProviderKey_Impl,
	IntrospectionAccessStatic_Impl*,
	TypeProviderAccessCache_Impl,
	TypeProviderAccessCache_Impl
>
TypeProviderAccessCacheMap_Impl;

class TypeProviderAccessCacheMap : public TypeProviderAccessCacheMap_Impl
{
public:
 	~TypeProviderAccessCacheMap()
 	{
 		TypeProviderAccessCacheMap::iterator iter = begin();
 		TypeProviderAccessCacheMap::iterator stop = this->end();
 		while( iter != stop )
 		{
			(*iter).second->release();
			(*iter).second = NULL;
			iter++;
		}
	}
};

#endif


//*************************
//*** ImplIntrospection ***
//*************************

struct OIntrospectionMutex
{
	Mutex							m_mutex;
};

class ImplIntrospection : public XIntrospection
						, public XServiceInfo
						, public OIntrospectionMutex
						, public OComponentHelper
{	
	friend class ImplMergeIntrospection;
	friend class ImplMVCIntrospection;

	// Implementation der Introspection.
	// ACHTUNG: RefCounting von Hand !!!
	IntrospectionAccessStatic_Impl* implInspect(const Any& aToInspectObj);

	// Save XMultiServiceFactory from createComponent
	Reference<XMultiServiceFactory> m_xSMgr;

	// CoreReflection halten
	Reference< XIdlReflection > mxCoreReflection;

	// Klassen, deren Methoden eine spezielle Rolle spielen
	Reference<XIdlClass> mxElementAccessClass;
	Reference<XIdlClass> mxNameContainerClass;
	Reference<XIdlClass> mxNameAccessClass;
	Reference<XIdlClass> mxIndexContainerClass;
	Reference<XIdlClass> mxIndexAccessClass;
	Reference<XIdlClass> mxEnumerationAccessClass;
	Reference<XIdlClass> mxInterfaceClass;
	Reference<XIdlClass> mxAggregationClass;
	sal_Bool mbDisposed;

#ifdef USE_INTROSPECTION_CACHE
	sal_uInt16 mnCacheEntryCount;
	sal_uInt16 mnTPCacheEntryCount;
	IntrospectionAccessCacheMap* mpCache;
	TypeProviderAccessCacheMap* mpTypeProviderCache;
#endif

public:
	ImplIntrospection( const Reference<XMultiServiceFactory> & rXSMgr );

	// Methoden von XInterface
	virtual Any			SAL_CALL queryInterface( const Type& rType ) throw( RuntimeException );
	virtual void		SAL_CALL acquire() throw() { OComponentHelper::acquire(); }
	virtual void		SAL_CALL release() throw() { OComponentHelper::release(); }

	// XTypeProvider
    Sequence< Type >	SAL_CALL getTypes(  ) throw( RuntimeException );
    Sequence<sal_Int8>	SAL_CALL getImplementationId(  ) throw( RuntimeException );

	// XServiceInfo
    ::rtl::OUString 					SAL_CALL getImplementationName() throw();
    sal_Bool					SAL_CALL supportsService(const ::rtl::OUString& ServiceName) throw();
    Sequence< ::rtl::OUString > 		SAL_CALL getSupportedServiceNames(void) throw();
    static ::rtl::OUString SAL_CALL	getImplementationName_Static(  );
    static Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames_Static(void) throw();

	// Methoden von XIntrospection
    virtual Reference<XIntrospectionAccess> SAL_CALL inspect(const Any& aToInspectObj)
				throw( RuntimeException );

protected:
	// some XComponent part from OComponentHelper
	virtual void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
};

enum MethodType
{
	STANDARD_METHOD,			// normale Methode, kein Bezug zu Properties oder Listenern
	GETSET_METHOD,				// gehoert zu einer get/set-Property
	ADD_LISTENER_METHOD,		// add-Methode einer Listener-Schnittstelle
	REMOVE_LISTENER_METHOD,		// remove-Methode einer Listener-Schnittstelle
	INVALID_METHOD				// Methode, deren Klasse nicht beruecksichtigt wird, z.B. XPropertySet
};

// Ctor
ImplIntrospection::ImplIntrospection( const Reference<XMultiServiceFactory> & rXSMgr )
	: OComponentHelper( m_mutex )
	, m_xSMgr( rXSMgr )
{
#ifdef USE_INTROSPECTION_CACHE
	mnCacheEntryCount = 0;
    mnTPCacheEntryCount = 0;
	mpCache = NULL;
	mpTypeProviderCache = NULL;
#endif

	// Spezielle Klassen holen
// 	Reference< XInterface > xServiceIface = m_xSMgr->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.CoreReflection")) );
// 	if( xServiceIface.is() )
// 		mxCoreReflection = Reference< XIdlReflection >::query( xServiceIface );
    Reference< XPropertySet > xProps( rXSMgr, UNO_QUERY );
    OSL_ASSERT( xProps.is() );
    if (xProps.is())
    {
        Reference< XComponentContext > xContext;
        xProps->getPropertyValue(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
        OSL_ASSERT( xContext.is() );
        if (xContext.is())
        {
            xContext->getValueByName(
                ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection") ) ) >>= mxCoreReflection;
            OSL_ENSURE( mxCoreReflection.is(), "### CoreReflection singleton not accessible!?" );
        }
    }
    if (! mxCoreReflection.is())
    {
        throw DeploymentException(
            ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection singleton not accessible") ),
            Reference< XInterface >() );
    }
    
	mxElementAccessClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XElementAccess")) );
	mxNameContainerClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameContainer")) );
	mxNameAccessClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameAccess")) );
	mxIndexContainerClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexContainer")) );
	mxIndexAccessClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexAccess")) );
	mxEnumerationAccessClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XEnumerationAccess")) );
	mxInterfaceClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XInterface")) );
	mxAggregationClass = mxCoreReflection->forName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XAggregation")) );
	mbDisposed = sal_False;
}

// XComponent
void ImplIntrospection::dispose() throw(::com::sun::star::uno::RuntimeException)
{
	OComponentHelper::dispose();

#ifdef USE_INTROSPECTION_CACHE
	// Cache loeschen
	delete mpCache;
	mpCache = NULL;
	delete mpTypeProviderCache;
	mpTypeProviderCache = NULL;
#endif

	mxElementAccessClass = NULL;
	mxNameContainerClass = NULL;
	mxNameAccessClass = NULL;
	mxIndexContainerClass = NULL;
	mxIndexAccessClass = NULL;
	mxEnumerationAccessClass = NULL;
	mxInterfaceClass = NULL;
	mxAggregationClass = NULL;
	mbDisposed = sal_True;
}


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

// XInterface
Any ImplIntrospection::queryInterface( const Type & rType )
	throw(::com::sun::star::uno::RuntimeException)
{
	Any aRet( ::cppu::queryInterface(
		rType,
		static_cast< XIntrospection * >( this ),
		static_cast< XServiceInfo * >( this ) ) );
	
	return (aRet.hasValue() ? aRet : OComponentHelper::queryInterface( rType ));
}

// XTypeProvider
Sequence< Type > ImplIntrospection::getTypes()
	throw( RuntimeException )
{
	static OTypeCollection * s_pTypes = 0;
	if (! s_pTypes)
	{
		MutexGuard aGuard( Mutex::getGlobalMutex() );
		if (! s_pTypes)
		{
			static OTypeCollection s_aTypes(
				::getCppuType( (const Reference< XIntrospection > *)0 ),
				::getCppuType( (const Reference< XServiceInfo > *)0 ),
				OComponentHelper::getTypes() );
			s_pTypes = &s_aTypes;
		}
	}
	return s_pTypes->getTypes();
}

Sequence< sal_Int8 > ImplIntrospection::getImplementationId()
	throw( RuntimeException )
{
	static OImplementationId * s_pId = 0;
	if (! s_pId)
	{
		MutexGuard aGuard( Mutex::getGlobalMutex() );
		if (! s_pId)
		{
			static OImplementationId s_aId;
			s_pId = &s_aId;
		}
	}
	return s_pId->getImplementationId();
}


// XServiceInfo
::rtl::OUString ImplIntrospection::getImplementationName() throw()
{
	return getImplementationName_Static();	
}

// XServiceInfo
sal_Bool ImplIntrospection::supportsService(const ::rtl::OUString& ServiceName) throw()
{
	Sequence< ::rtl::OUString > aSNL = getSupportedServiceNames();
	const ::rtl::OUString * pArray = aSNL.getConstArray();
	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
		if( pArray[i] == ServiceName )
			return sal_True;
	return sal_False;
}

// XServiceInfo
Sequence< ::rtl::OUString > ImplIntrospection::getSupportedServiceNames(void) throw()
{
	return getSupportedServiceNames_Static();
}

//*************************************************************************
// Helper XServiceInfo
::rtl::OUString ImplIntrospection::getImplementationName_Static(  ) 
{
	return ::rtl::OUString::createFromAscii( IMPLEMENTATION_NAME );
}

// ORegistryServiceManager_Static
Sequence< ::rtl::OUString > ImplIntrospection::getSupportedServiceNames_Static(void) throw()
{
	Sequence< ::rtl::OUString > aSNS( 1 );
	aSNS.getArray()[0] = ::rtl::OUString::createFromAscii( SERVICE_NAME );
	return aSNS;
}

//*************************************************************************

// Methoden von XIntrospection
Reference<XIntrospectionAccess> ImplIntrospection::inspect(const Any& aToInspectObj)
	throw( RuntimeException )
{
	Reference<XIntrospectionAccess> xAccess;

	if ( aToInspectObj.getValueType().getTypeClass() == TypeClass_TYPE )
	{
		Type aType;
		aToInspectObj >>= aType;

		Reference< XIdlClass > xIdlClass = mxCoreReflection->forName(((Type*)(aToInspectObj.getValue()))->getTypeName());
		
		if ( xIdlClass.is() )
		{ 
			Any aRealInspectObj;
			aRealInspectObj <<= xIdlClass;

			IntrospectionAccessStatic_Impl* pStaticImpl = implInspect( aRealInspectObj );
			if( pStaticImpl )
				xAccess = new ImplIntrospectionAccess( aRealInspectObj, pStaticImpl );
		} 
	}
	else
	{
		IntrospectionAccessStatic_Impl* pStaticImpl = implInspect( aToInspectObj );
		if( pStaticImpl )
			xAccess = new ImplIntrospectionAccess( aToInspectObj, pStaticImpl );
	}
		
	return xAccess;
}

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

// Hashtable fuer Pruefung auf mehrfache Beruecksichtigung von Interfaces
struct hashInterface_Impl
{
	size_t operator()(const void* p) const
	{
		return (size_t)p;
	}
};

struct eqInterface_Impl
{
	bool operator()(const void* p1, const void* p2) const
	{
		return ( p1 == p2 );
	}
};

typedef std::hash_map
<
	void*,
	void*,
	hashInterface_Impl,
	eqInterface_Impl
>
CheckedInterfacesMap;



// TODO: Spaeter auslagern
Reference<XIdlClass> TypeToIdlClass( const Type& rType, const Reference< XMultiServiceFactory > & xMgr )
{
	static Reference< XIdlReflection > xRefl;

	// void als Default-Klasse eintragen
	Reference<XIdlClass> xRetClass;
	typelib_TypeDescription * pTD = 0;
	rType.getDescription( &pTD );
	if( pTD )
	{
	    ::rtl::OUString sOWName( pTD->pTypeName );
		if( !xRefl.is() )
		{
			xRefl = Reference< XIdlReflection >( xMgr->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.reflection.CoreReflection")) ), UNO_QUERY );
			OSL_ENSURE( xRefl.is(), "### no corereflection!" );
		}
		xRetClass = xRefl->forName( sOWName );
	}
	return xRetClass;
}

// Implementation der Introspection.
IntrospectionAccessStatic_Impl* ImplIntrospection::implInspect(const Any& aToInspectObj)
{
	MutexGuard aGuard( m_mutex );

	// Wenn die Introspection schon disposed ist, wird nur ein leeres Ergebnis geliefert
	if( mbDisposed )
		return NULL;

	// Objekt untersuchen
	TypeClass eType = aToInspectObj.getValueType().getTypeClass();
	if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT  && eType != TypeClass_EXCEPTION )
		return NULL;

	Reference<XInterface> x;
	if( eType == TypeClass_INTERFACE )
	{
		// Interface aus dem Any besorgen
		x = *(Reference<XInterface>*)aToInspectObj.getValue();
		if( !x.is() )
			return NULL;
	}

#ifdef USE_INTROSPECTION_CACHE
	// Haben wir schon eine Cache-Instanz
	if( !mpCache ) 
		mpCache = new IntrospectionAccessCacheMap;
	if( !mpTypeProviderCache ) 
		mpTypeProviderCache = new TypeProviderAccessCacheMap;
	IntrospectionAccessCacheMap& aCache = *mpCache;
	TypeProviderAccessCacheMap& aTPCache = *mpTypeProviderCache;

	// Pointer auf ggf. noetige neue IntrospectionAccess-Instanz
	IntrospectionAccessStatic_Impl* pAccess = NULL;
#else
	// Pointer auf ggf. noetige neue IntrospectionAccess-Instanz
	IntrospectionAccessStatic_Impl* pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection );
#endif

	// Pruefen: Ist schon ein passendes Access-Objekt gecached?
	Sequence< Reference<XIdlClass> >	SupportedClassSeq;
	Sequence< Type >					SupportedTypesSeq;
	Reference<XIdlClassProvider>		xClassProvider;
	Reference<XTypeProvider>			xTypeProvider;
	Reference<XIdlClass>				xImplClass;
	Reference<XPropertySetInfo>			xPropSetInfo;
	Reference<XPropertySet>				xPropSet;

	// Bei Interfaces XTypeProvider / XIdlClassProvider- und PropertySet-Interface anfordern
	if( eType == TypeClass_INTERFACE )
	{
		// XIdlClassProvider
		xTypeProvider = Reference<XTypeProvider>::query( x );
		if( xTypeProvider.is() )
		{
			SupportedTypesSeq = xTypeProvider->getTypes();
			sal_Int32 nTypeCount = SupportedTypesSeq.getLength();
			if( nTypeCount )
			{
				SupportedClassSeq.realloc( nTypeCount );
				Reference<XIdlClass>* pClasses = SupportedClassSeq.getArray();

				const Type* pTypes = SupportedTypesSeq.getConstArray();
				for( sal_Int32 i = 0 ; i < nTypeCount ; i++ )
				{
					pClasses[ i ] = TypeToIdlClass( pTypes[ i ], m_xSMgr );
				}
				// TODO: Caching!
			}
		}
		else
		{
			// XIdlClassProvider
			xClassProvider = Reference<XIdlClassProvider>::query( x );
			if( xClassProvider.is() )
			{
				SupportedClassSeq = xClassProvider->getIdlClasses();
				if( SupportedClassSeq.getLength() )
					xImplClass = SupportedClassSeq.getConstArray()[0];
			}
		}
		// #70197, fuer InvocationAdapter: Interface-Typ im Any auch ohne 
		// ClassProvider unterstuetzen
		if( !xClassProvider.is() && !xTypeProvider.is() )
		{
			xImplClass = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr );
			SupportedClassSeq.realloc( 1 );
			SupportedClassSeq.getArray()[ 0 ] = xImplClass;
		}

		xPropSet = Reference<XPropertySet>::query( x );
		// Jetzt versuchen, das PropertySetInfo zu bekommen
		if( xPropSet.is() )
			xPropSetInfo = xPropSet->getPropertySetInfo();
	}
	else
	{
		xImplClass = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr );
	}

#ifdef USE_INTROSPECTION_CACHE
	if( xTypeProvider.is() )
	{
		Sequence< sal_Int8 > aImpIdSeq = xTypeProvider->getImplementationId();
		sal_Int32 nIdLen = aImpIdSeq.getLength();

		if( nIdLen )
		{
			// cache only, if the descriptor class is set
			hashTypeProviderKey_Impl aKeySeq( xPropSetInfo, aImpIdSeq );

			TypeProviderAccessCacheMap::iterator aIt = aTPCache.find( aKeySeq );
			if( aIt == aTPCache.end() )
			{
				// not found
				// Neue Instanz anlegen und unter dem gegebenen Key einfuegen
				pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection );

				// RefCount von Hand erhoehen, muss beim Entfernen
				// aus der Hashtable wieder released werden
				pAccess->acquire();

				// Groesse begrenzen, alten Eintrag wieder rausschmeissen
				if( mnTPCacheEntryCount > INTROSPECTION_CACHE_MAX_SIZE )
				{
					// Access mit dem kleinsten HitCount suchen
					TypeProviderAccessCacheMap::iterator iter = aTPCache.begin();
					TypeProviderAccessCacheMap::iterator end = aTPCache.end();
					TypeProviderAccessCacheMap::iterator toDelete = iter;
					while( iter != end )
					{
						if( (*iter).first.nHitCount < (*toDelete).first.nHitCount )
							toDelete = iter;
						++iter;
					}

					// Gefundenen Eintrag entfernen
					if( (*toDelete).second )
						(*toDelete).second->release();
					(*toDelete).second = NULL;
					aTPCache.erase( toDelete );
				}
				else
					mnTPCacheEntryCount++;

				// Neuer Eintrage rein in die Table
				aKeySeq.nHitCount = 1;
				aTPCache[ aKeySeq ] = pAccess;

			}
			else
			{
				// Hit-Count erhoehen
				(*aIt).first.IncHitCount();
				return (*aIt).second;
			}
		}
	}
	else if( xImplClass.is() )
	{
		// cache only, if the descriptor class is set
		hashIntrospectionKey_Impl	aKeySeq( SupportedClassSeq, xPropSetInfo, xImplClass );

		IntrospectionAccessCacheMap::iterator aIt = aCache.find( aKeySeq );
		if( aIt == aCache.end() )
		{
			// not found
			// Neue Instanz anlegen und unter dem gegebenen Key einfuegen
			pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection );

			// RefCount von Hand erhoehen, muss beim Entfernen
			// aus der Hashtable wieder released werden
			pAccess->acquire();

			// Groesse begrenzen, alten Eintrag wieder rausschmeissen
			if( mnCacheEntryCount > INTROSPECTION_CACHE_MAX_SIZE )
			{
				// Access mit dem kleinsten HitCount suchen
				IntrospectionAccessCacheMap::iterator iter = aCache.begin();
				IntrospectionAccessCacheMap::iterator end = aCache.end();
				IntrospectionAccessCacheMap::iterator toDelete = iter;
				while( iter != end )
				{
					if( (*iter).first.nHitCount < (*toDelete).first.nHitCount )
						toDelete = iter;
					++iter;
				}

				// Gefundenen Eintrag entfernen
				if( (*toDelete).second )
					(*toDelete).second->release();
				(*toDelete).second = NULL;
				aCache.erase( toDelete );
			}
			else
				mnCacheEntryCount++;

			// Neuer Eintrage rein in die Table
			aKeySeq.nHitCount = 1;
			aCache[ aKeySeq ] = pAccess;

		}
		else
		{
			// Hit-Count erhoehen
			(*aIt).first.IncHitCount();
			return (*aIt).second;
		}
	}
#endif

	// Kein Access gecached -> neu anlegen
	Property* pAllPropArray;
	Reference<XInterface>* pInterfaces1;
	Reference<XInterface>* pInterfaces2;
	sal_Int16* pMapTypeArray;
	sal_Int32* pPropertyConceptArray;
	sal_Int32 i;

	if( !pAccess )
		pAccess = new IntrospectionAccessStatic_Impl( mxCoreReflection );

	// Referenzen auf wichtige Daten von pAccess
	sal_Int32& rPropCount = pAccess->mnPropCount;
	IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap;
	IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap;
	LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap;

	// Schon mal Pointer auf das eigene Property-Feld holen
	pAllPropArray = pAccess->maAllPropertySeq.getArray();
	pInterfaces1 = pAccess->aInterfaceSeq1.getArray();
	pInterfaces2 = pAccess->aInterfaceSeq2.getArray();
	pMapTypeArray = pAccess->maMapTypeSeq.getArray();
	pPropertyConceptArray = pAccess->maPropertyConceptSeq.getArray();

	//*************************
	//*** Analyse vornehmen ***
	//*************************
	if( eType == TypeClass_INTERFACE )
	{
		// Zunaechst nach speziellen Interfaces suchen, die fuer
		// die Introspection von besonderer Bedeutung sind.

		// XPropertySet vorhanden?
		if( xPropSet.is() && xPropSetInfo.is() )
		{
			// Gibt es auch ein FastPropertySet?
			Reference<XFastPropertySet> xDummy = Reference<XFastPropertySet>::query( x );
			sal_Bool bFast = pAccess->mbFastPropSet = xDummy.is();

			Sequence<Property> aPropSeq = xPropSetInfo->getProperties();
			const Property* pProps = aPropSeq.getConstArray();
			sal_Int32 nLen = aPropSeq.getLength();

			// Bei FastPropertySet muessen wir uns die Original-Handles merken
			if( bFast )
				pAccess->mpOrgPropertyHandleArray = new sal_Int32[ nLen ];

			for( i = 0 ; i < nLen ; i++ )
			{
				// Property in eigene Liste uebernehmen
				pAccess->checkPropertyArraysSize
					( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount );
				Property& rProp = pAllPropArray[ rPropCount ];
				rProp = pProps[ i ];

				if( bFast )
					pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;

				// PropCount als Handle fuer das eigene FastPropertySet eintragen
				rProp.Handle = rPropCount;

				// Art der Property merken
				pMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
				pPropertyConceptArray[ rPropCount ] = PROPERTYSET;
				pAccess->mnPropertySetPropCount++;

				// Namen in Hashtable eintragen, wenn nicht schon bekannt
			    ::rtl::OUString aPropName = rProp.Name;

				// Haben wir den Namen schon?
				IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
				if( aIt == rPropNameMap.end() )
				{
					// Neuer Eintrag in die Hashtable
					rPropNameMap[ aPropName ] = rPropCount;

					// Tabelle fuer XExactName pflegen
					rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName;
				}
				else
				{
					OSL_ENSURE( sal_False, 
						::rtl::OString( "Introspection: Property \"" ) + 
					    ::rtl::OUStringToOString( aPropName, RTL_TEXTENCODING_ASCII_US ) +
                        ::rtl::OString( "\" found more than once in PropertySet" ) );
				}

				// Count pflegen
				rPropCount++;
			}
		}


		// Jetzt alle weiteren implementierten Interfaces durchgehen
		// Diese muessen durch das XIdlClassProvider-Interface geliefert werden.
		// #70197, fuer InvocationAdapter: Interface-Typ im Any auch ohne 
		// ClassProvider unterstuetzen
		//if( xClassProvider.is() )
		{
			// Indizes in die Export-Tabellen
			sal_Int32 iAllExportedMethod = 0;
			sal_Int32 iAllSupportedListener = 0;

			// Hashtable fuer Pruefung auf mehrfache Beruecksichtigung von Interfaces
			CheckedInterfacesMap aCheckedInterfacesMap;

			// Flag, ob XInterface-Methoden erfasst werden sollen
			// (das darf nur einmal erfolgen, initial zulassen)
			sal_Bool bXInterfaceIsInvalid = sal_False;

			// Flag, ob die XInterface-Methoden schon erfasst wurden. Wenn sal_True, 
			// wird bXInterfaceIsInvalid am Ende der Iface-Schleife aktiviert und 
			// XInterface-Methoden werden danach abgeklemmt.
			sal_Bool bFoundXInterface = sal_False;

			// Schleife ueber alle vom ClassProvider angegebenen Klassen
			sal_Int32 nClassCount = SupportedClassSeq.getLength();
			for( sal_Int32 nIdx = 0 ; nIdx < nClassCount; nIdx++ )
			{
				Reference<XIdlClass> xImplClass2 = SupportedClassSeq.getConstArray()[nIdx];
				while( xImplClass2.is() )
				{
					// Interfaces der Implementation holen
					Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces();
					sal_Int32 nIfaceCount = aClassSeq.getLength();

					aClassSeq.realloc( nIfaceCount + 1 );
					aClassSeq.getArray()[ nIfaceCount ] = xImplClass2;
					nIfaceCount++;

					const Reference<XIdlClass>* pParamArray = aClassSeq.getConstArray();

					for( sal_Int32 j = 0 ; j < nIfaceCount ; j++ )
					{
						const Reference<XIdlClass>& rxIfaceClass = pParamArray[j];

						// Pruefen, ob das Interface schon beruecksichtigt wurde. 
						XInterface* pIface = SAL_STATIC_CAST( XInterface*, rxIfaceClass.get() );
						if( aCheckedInterfacesMap.count( pIface ) > 0 )
						{
							// Kennen wir schon
							continue;
						}
						else
						{
							// Sonst eintragen
							aCheckedInterfacesMap[ pIface ] = pIface;
						}

						//********************************************************************

						// 2. Fields als Properties registrieren

						// Felder holen
						Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields();
						const Reference<XIdlField>* pFields = fields.getConstArray();
						sal_Int32 nLen = fields.getLength();

						for( i = 0 ; i < nLen ; i++ )
						{
							Reference<XIdlField> xField = pFields[i];
							Reference<XIdlClass> xPropType = xField->getType();

							// Ist die PropertySequence gross genug?
							pAccess->checkPropertyArraysSize
								( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount );

							// In eigenes Property-Array eintragen
							Property& rProp = pAllPropArray[ rPropCount ];
						    ::rtl::OUString aFieldName = xField->getName();
							rProp.Name = aFieldName;
							rProp.Handle = rPropCount;
							Type aFieldType( xPropType->getTypeClass(), xPropType->getName() );
							rProp.Type = aFieldType;
							FieldAccessMode eAccessMode = xField->getAccessMode();
							rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY || 
												eAccessMode == FieldAccessMode_CONST) 
												? READONLY : 0;

							// Namen in Hashtable eintragen
						    ::rtl::OUString aPropName = rProp.Name;

							// Haben wir den Namen schon?
							IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
							if( !( aIt == rPropNameMap.end() ) )
							{
								/* TODO
								OSL_TRACE( 
									String( "Introspection: Property \"" ) + 
									OOUStringToString( aPropName, CHARSET_SYSTEM ) +
									String( "\" found more than once" ) );
									*/
								continue;
							}

							// Neuer Eintrag in die Hashtable
							rPropNameMap[ aPropName ] = rPropCount;

							// Tabelle fuer XExactName pflegen
							rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName;

							// Field merken
							pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, 
								pInterfaces1, rPropCount );
							pInterfaces1[ rPropCount ] = xField;
						
							// Art der Property merken
							pMapTypeArray[ rPropCount ] = MAP_FIELD;
							pPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
							pAccess->mnAttributePropCount++;

							// Count pflegen
							rPropCount++;
						}

						//********************************************************************

						// 3. Methoden

						// Zaehler fuer die gefundenen Listener
						sal_Int32 nListenerCount = 0;

						// Alle Methoden holen und merken
						Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods();
						const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
						sal_Int32 nSourceMethodCount = methods.getLength();

						// 3. a) get/set- und Listener-Methoden suchen

						// Feld fuer Infos ueber die Methoden anlegen, damit spaeter leicht die Methoden 
						// gefunden werden koennen, die nicht im Zusammenhang mit Properties oder Listenern 
						// stehen. NEU: auch MethodConceptArray initialisieren
						MethodType* pMethodTypes = new MethodType[ nSourceMethodCount ];
						sal_Int32* pLocalMethodConcepts = new sal_Int32[ nSourceMethodCount ];
						for( i = 0 ; i < nSourceMethodCount ; i++ )
						{
							pMethodTypes[ i ] = STANDARD_METHOD;
							pLocalMethodConcepts[ i ] = 0;
						}

					    ::rtl::OUString aMethName;
					    ::rtl::OUString aPropName;
					    ::rtl::OUString aStartStr;
						for( i = 0 ; i < nSourceMethodCount ; i++ )
						{
							// Methode ansprechen
							const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
							sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];

							// Namen besorgen
							aMethName = rxMethod_i->getName();

							// Methoden katalogisieren
							// Alle (?) Methoden von XInterface filtern, damit z.B. nicht 
							// vom Scripting aus aquire oder release gerufen werden kann
							if( rxMethod_i->getDeclaringClass()->equals( mxInterfaceClass ) )
							{
								// XInterface-Methoden sind hiermit einmal beruecksichtigt
								bFoundXInterface = sal_True;

								if( bXInterfaceIsInvalid )
								{
									pMethodTypes[ i ] = INVALID_METHOD;
									continue;
								}
								else
								{
									if( aMethName != ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("queryInterface")) )
									{
										rMethodConcept_i |= MethodConcept::DANGEROUS;
										continue;
									}
								}
							}
							else if( rxMethod_i->getDeclaringClass()->equals( mxAggregationClass ) )
							{
								if( aMethName == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("setDelegator")) )
								{
									rMethodConcept_i |= MethodConcept::DANGEROUS;
									continue;
								}
							}
							else if( rxMethod_i->getDeclaringClass()->equals( mxElementAccessClass ) )
							{
								rMethodConcept_i |= ( NAMECONTAINER  |
													  INDEXCONTAINER |
													  ENUMERATION );
							}
							else if( rxMethod_i->getDeclaringClass()->equals( mxNameContainerClass ) ||
									 rxMethod_i->getDeclaringClass()->equals( mxNameAccessClass ) )
							{
								rMethodConcept_i |= NAMECONTAINER;
							}
							else if( rxMethod_i->getDeclaringClass()->equals( mxIndexContainerClass ) ||
									 rxMethod_i->getDeclaringClass()->equals( mxIndexAccessClass ) )
							{
								rMethodConcept_i |= INDEXCONTAINER;
							}
							else if( rxMethod_i->getDeclaringClass()->equals( mxEnumerationAccessClass ) )
							{
								rMethodConcept_i |= ENUMERATION;
							}

							// Wenn der Name zu kurz ist, wird's sowieso nichts
							if( aMethName.getLength() <= 3 )
								continue;

							// Ist es eine get-Methode?
							aStartStr = aMethName.copy( 0, 3 );
							if( aStartStr == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("get")) )
							{
								// Namen der potentiellen Property
								aPropName = aMethName.copy( 3 );

								// get-Methode darf keinen Parameter haben
								Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes();
								if( getParams.getLength() > 0 )
								{
									continue;
								}

								// Haben wir den Namen schon?
								IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
								if( !( aIt == rPropNameMap.end() ) )
								{
									/* TODO
									OSL_TRACE( 
										String( "Introspection: Property \"" ) + 
										OOUStringToString( aPropName, CHARSET_SYSTEM ) +
										String( "\" found more than once" ) );
										*/
									continue;
								}

								// Eine readonly-Property ist es jetzt mindestens schon
								rMethodConcept_i |= PROPERTY;

								pMethodTypes[i] = GETSET_METHOD;
								Reference<XIdlClass> xGetRetType = rxMethod_i->getReturnType();

								// Ist die PropertySequence gross genug?
								pAccess->checkPropertyArraysSize
									( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount );

								// In eigenes Property-Array eintragen
								Property& rProp = pAllPropArray[ rPropCount ];
								rProp.Name = aPropName;
								rProp.Handle = rPropCount;
								rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
								rProp.Attributes = READONLY;

								// Neuer Eintrag in die Hashtable
								rPropNameMap[ aPropName ] = rPropCount;

								// Tabelle fuer XExactName pflegen
								rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName;

								// get-Methode merken
								pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, 
									pInterfaces1, rPropCount );
								pInterfaces1[ rPropCount ] = rxMethod_i;
							
								// Art der Property merken
								pMapTypeArray[ rPropCount ] = MAP_GETSET;
								pPropertyConceptArray[ rPropCount ] = METHODS;
								pAccess->mnMethodPropCount++;

								// Passende set-Methode suchen
								sal_Int32 k;
								for( k = 0 ; k < nSourceMethodCount ; k++ )
								{
									// Methode ansprechen
									const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];

									// Nur Methoden nehmen, die nicht schon zugeordnet sind
									if( k == i || pMethodTypes[k] != STANDARD_METHOD )
										continue;

									// Name holen und auswerten
								    ::rtl::OUString aMethName2 = rxMethod_k->getName();
								    ::rtl::OUString aStartStr2 = aMethName2.copy( 0, 3 );
									// ACHTUNG: Wegen SDL-Bug NICHT != bei ::rtl::OUString verwenden !!!
									if( !( aStartStr2 == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("set")) ) )
										continue;

									// Ist es denn der gleiche Name?
								    ::rtl::OUString aPropName2 = aMethName2.copy( 3 );
									// ACHTUNG: Wegen SDL-Bug NICHT != bei ::rtl::OUString verwenden !!!
									if( !( aPropName == aPropName2 ) )
										continue;

									// set-Methode muss void returnen
									Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType();
									if( xSetRetType->getTypeClass() != TypeClass_VOID )
									{
										continue;
									}

									// set-Methode darf nur einen Parameter haben
									Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes();
									sal_Int32 nParamCount = setParams.getLength();
									if( nParamCount != 1 )
									{
										continue;
									}

									// Jetzt muss nur noch der return-Typ dem Parameter-Typ entsprechen
									const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray();
									Reference<XIdlClass> xParamType = pParamArray2[ 0 ];
									if( xParamType->equals( xGetRetType ) )
									{
										pLocalMethodConcepts[ k ] = PROPERTY;

										pMethodTypes[k] = GETSET_METHOD;

										// ReadOnly-Flag wieder loschen
										rProp.Attributes &= ~READONLY;

										// set-Methode merken
										pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq2, 
											pInterfaces2, rPropCount );
										pInterfaces2[ rPropCount ] = rxMethod_k;
									}
								}

								// Count pflegen
								rPropCount++;
							}

							// Ist es eine addListener-Methode?
							else if( aStartStr == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("add")) )
							{
							    ::rtl::OUString aListenerStr( RTL_CONSTASCII_USTRINGPARAM("Listener" ) );

								// Namen der potentiellen Property
								sal_Int32 nStrLen = aMethName.getLength();
                                sal_Int32 nCopyLen = nStrLen - aListenerStr.getLength();
                                ::rtl::OUString aEndStr = aMethName.copy( nCopyLen > 0 ? nCopyLen : 0 );

								// Endet das Teil auf Listener?
								// ACHTUNG: Wegen SDL-Bug NICHT != bei ::rtl::OUString verwenden !!!
								if( !( aEndStr == aListenerStr ) )
									continue;

								// Welcher Listener?
							    ::rtl::OUString aListenerName = aMethName.copy( 3, nStrLen - aListenerStr.getLength() - 3 );

								// TODO: Hier koennten noch genauere Pruefungen vorgenommen werden
								// - Rueckgabe-Typ
								// - Anzahl und Art der Parameter


								// Passende remove-Methode suchen, sonst gilt's nicht
								sal_Int32 k;
								for( k = 0 ; k < nSourceMethodCount ; k++ )
								{
									// Methode ansprechen
									const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];

									// Nur Methoden nehmen, die nicht schon zugeordnet sind
									if( k == i || pMethodTypes[k] != STANDARD_METHOD )
										continue;

									// Name holen und auswerten
								    ::rtl::OUString aMethName2 = rxMethod_k->getName();
                                    sal_Int32 nNameLen = aMethName2.getLength();
                                    sal_Int32 nCopyLen2 = (nNameLen < 6) ? nNameLen : 6;
								    ::rtl::OUString aStartStr2 = aMethName2.copy( 0, nCopyLen2 );
								    ::rtl::OUString aRemoveStr( RTL_CONSTASCII_USTRINGPARAM("remove" ) );
									// ACHTUNG: Wegen SDL-Bug NICHT != bei ::rtl::OUString verwenden !!!
									if( !( aStartStr2 == aRemoveStr ) )
										continue;

									// Ist es denn der gleiche Listener?
									if( aMethName2.getLength() - aRemoveStr.getLength() <= aListenerStr.getLength() )
										continue;
								    ::rtl::OUString aListenerName2 = aMethName2.copy
										( 6, aMethName2.getLength() - aRemoveStr.getLength() - aListenerStr.getLength() );
									// ACHTUNG: Wegen SDL-Bug NICHT != bei ::rtl::OUString verwenden !!!
									if( !( aListenerName == aListenerName2 ) )
										continue;

									// TODO: Hier koennten noch genauere Pruefungen vorgenommen werden
									// - Rueckgabe-Typ
									// - Anzahl und Art der Parameter


									// Methoden sind als Listener-Schnittstelle erkannt
									rMethodConcept_i |= LISTENER;
									pLocalMethodConcepts[ k ] |= LISTENER;

									pMethodTypes[i] = ADD_LISTENER_METHOD;
									pMethodTypes[k] = REMOVE_LISTENER_METHOD;
									nListenerCount++;
								}
							}
						}


						// Jetzt koennen noch SET-Methoden ohne zugehoerige GET-Methode existieren,
						// diese muessen zu Write-Only-Properties gemachte werden.
						for( i = 0 ; i < nSourceMethodCount ; i++ )
						{
							// Methode ansprechen
							const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];

							// Nur Methoden nehmen, die nicht schon zugeordnet sind
							if( pMethodTypes[i] != STANDARD_METHOD )
								continue;

							// Namen besorgen
							aMethName = rxMethod_i->getName();
							
							// Wenn der Name zu kurz ist, wird's sowieso nichts
							if( aMethName.getLength() <= 3 )
								continue;

							// Ist es eine set-Methode ohne zugehoerige get-Methode?
							aStartStr = aMethName.copy( 0, 3 );
							if( aStartStr == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("set")) )
							{
								// Namen der potentiellen Property
								aPropName = aMethName.copy( 3 );

								// set-Methode muss void returnen
								Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType();
								if( xSetRetType->getTypeClass() != TypeClass_VOID )
								{
									continue;
								}

								// set-Methode darf nur einen Parameter haben
								Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes();
								sal_Int32 nParamCount = setParams.getLength();
								if( nParamCount != 1 )
								{
									continue;
								}

								// Haben wir den Namen schon?
								IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
								if( !( aIt == rPropNameMap.end() ) )
								{
									/* TODO:
									OSL_TRACE( 
										String( "Introspection: Property \"" ) + 
										OOUStringToString( aPropName, CHARSET_SYSTEM ) +
										String( "\" found more than once" ) );
										*/
									continue;
								}

								// Alles klar, es ist eine Write-Only-Property
								pLocalMethodConcepts[ i ] = PROPERTY;

								pMethodTypes[i] = GETSET_METHOD;
								Reference<XIdlClass> xGetRetType = setParams.getConstArray()[0];

								// Ist die PropertySequence gross genug?
								pAccess->checkPropertyArraysSize
									( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount );

								// In eigenes Property-Array eintragen
								Property& rProp = pAllPropArray[ rPropCount ];
								rProp.Name = aPropName;
								rProp.Handle = rPropCount;
								rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
								rProp.Attributes = 0;	// PROPERTY_WRITEONLY ???

								// Neuer Eintrag in die Hashtable
								rPropNameMap[ aPropName ] = rPropCount;

								// Tabelle fuer XExactName pflegen
								rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName;

								// set-Methode merken
								pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq2, 
									pInterfaces2, rPropCount );
								pInterfaces2[ rPropCount ] = rxMethod_i;

								// Art der Property merken
								pMapTypeArray[ rPropCount ] = MAP_SETONLY;
								pPropertyConceptArray[ rPropCount ] = METHODS;
								pAccess->mnMethodPropCount++;

								// Count pflegen
								rPropCount++;
							}
						}


						//********************************************************************

						// 4. Methoden in die Gesamt-Sequence uebernehmen

						// Wieviele Methoden muessen in die Method-Sequence?
						sal_Int32 nExportedMethodCount = 0;
						sal_Int32 nSupportedListenerCount = 0;
						for( i = 0 ; i < nSourceMethodCount ; i++ )
						{
							if( pMethodTypes[ i ] != INVALID_METHOD )
							{
								nExportedMethodCount++;
							}
							if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
							{
								nSupportedListenerCount++;
							}
						}				

						// Sequences im Access-Objekt entsprechend aufbohren
						pAccess->maAllMethodSeq.realloc( nExportedMethodCount + iAllExportedMethod );
						pAccess->maMethodConceptSeq.realloc( nExportedMethodCount + iAllExportedMethod );
						pAccess->maSupportedListenerSeq.realloc( nSupportedListenerCount + iAllSupportedListener );

						// Methoden reinschreiben
						Reference<XIdlMethod>* pDestMethods = pAccess->maAllMethodSeq.getArray();
						sal_Int32* pMethodConceptArray = pAccess->maMethodConceptSeq.getArray();
						Type* pListenerClassRefs = pAccess->maSupportedListenerSeq.getArray();
						for( i = 0 ; i < nSourceMethodCount ; i++ )
						{
							if( pMethodTypes[ i ] != INVALID_METHOD )
							{
								// Methode ansprechen
								const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];

								// Namen in Hashtable eintragen, wenn nicht schon bekannt
							    ::rtl::OUString aMethName2 = rxMethod->getName();
								IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 );
								if( aIt == rMethodNameMap.end() )
								{
									// Eintragen
									rMethodNameMap[ aMethName2 ] = iAllExportedMethod;

								    // Tabelle fuer XExactName pflegen
								    rLowerToExactNameMap[ toLower( aMethName2 ) ] = aMethName2;
								}
                                else
                                {
                            		sal_Int32 iHashResult = (*aIt).second;

                                	Reference<XIdlMethod> xExistingMethod = pDestMethods[ iHashResult ];

					                Reference< XIdlClass > xExistingMethClass = 
                                        xExistingMethod->getDeclaringClass();
					                Reference< XIdlClass > xNewMethClass = rxMethod->getDeclaringClass();
					                if( xExistingMethClass->equals( xNewMethClass ) )
                                        continue;
                                }

								pDestMethods[ iAllExportedMethod ] = rxMethod;

								// Wenn kein Concept gesetzt wurde, ist die Methode "normal"
								sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
								if( !rMethodConcept_i )
									rMethodConcept_i = MethodConcept_NORMAL_IMPL;
								pMethodConceptArray[ iAllExportedMethod ] = rMethodConcept_i;
								iAllExportedMethod++;
							}
							if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
							{
								// Klasse des Listeners ermitteln
								const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];

								// void als Default-Klasse eintragen
								Reference<XIdlClass> xListenerClass = TypeToIdlClass( getCppuVoidType(), m_xSMgr );
								// ALT: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass();

								// 1. Moeglichkeit: Parameter nach einer Listener-Klasse durchsuchen
								// Nachteil: Superklassen muessen rekursiv durchsucht werden
								Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes();
								const Reference<XIdlClass>* pParamArray2 = aParams.getConstArray();

								Reference<XIdlClass> xEventListenerClass = TypeToIdlClass( getCppuType( (Reference<XEventListener>*) NULL ), m_xSMgr );
								// ALT: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass();
								sal_Int32 nParamCount = aParams.getLength();
								sal_Int32 k;
								for( k = 0 ; k < nParamCount ; k++ )
								{
									const Reference<XIdlClass>& rxClass = pParamArray2[k];

									// Sind wir von einem Listener abgeleitet?
									if( rxClass->equals( xEventListenerClass ) || 
										isDerivedFrom( rxClass, xEventListenerClass ) )
									{
										xListenerClass = rxClass;
										break;
									}
								}

								// 2. Moeglichkeit: Namen der Methode auswerden
								// Nachteil: geht nicht bei Test-Listenern, die es nicht gibt
								//aMethName = rxMethod->getName();
								//aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 );
								//Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName );
								Type aListenerType( TypeClass_INTERFACE, xListenerClass->getName() );
								pListenerClassRefs[ iAllSupportedListener ] = aListenerType;
								iAllSupportedListener++;
							}
						}

						// Wenn in diesem Durchlauf XInterface-Methoden 
						// dabei waren, diese zukuenftig ignorieren
						if( bFoundXInterface )
							bXInterfaceIsInvalid = sal_True;

						delete[] pMethodTypes;
						delete[] pLocalMethodConcepts;
					}

					// Super-Klasse(n) vorhanden? Dann dort fortsetzen
					Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses();

					// Zur Zeit wird nur von einer Superklasse ausgegangen
					if( aSuperClassSeq.getLength() >= 1 )
					{
						xImplClass2 = aSuperClassSeq.getConstArray()[0];
						OSL_ENSURE( xImplClass2.is(), "super class null" );
					}
					else
					{
						xImplClass2 = NULL;
					}
				}
			}

			// Anzahl der exportierten Methoden uebernehmen und Sequences anpassen
			// (kann abweichen, weil doppelte Methoden erst nach der Ermittlung
			//  von nExportedMethodCount herausgeworfen werden)
			sal_Int32& rMethCount = pAccess->mnMethCount;
			rMethCount = iAllExportedMethod;
			pAccess->maAllMethodSeq.realloc( rMethCount );
			pAccess->maMethodConceptSeq.realloc( rMethCount );

			// Groesse der Property-Sequences anpassen
			pAccess->maAllPropertySeq.realloc( rPropCount );
			pAccess->maPropertyConceptSeq.realloc( rPropCount );
			pAccess->maMapTypeSeq.realloc( rPropCount );

			// Ende der Schleife ueber alle vom ClassProvider angegebenen Klassen
		}
	}
	// Bei structs Fields als Properties registrieren
	else //if( eType == TypeClass_STRUCT )
	{
		// Ist es ein Interface oder eine struct?
		//Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass();
		Reference<XIdlClass> xClassRef = TypeToIdlClass( aToInspectObj.getValueType(), m_xSMgr );
		if( !xClassRef.is() )
		{
			OSL_ENSURE( sal_False, "Can't get XIdlClass from Reflection" );
			return pAccess;
		}

		// Felder holen
		Sequence< Reference<XIdlField> > fields = xClassRef->getFields();
		const Reference<XIdlField>* pFields = fields.getConstArray();
		sal_Int32 nLen = fields.getLength();

		for( i = 0 ; i < nLen ; i++ )
		{
			Reference<XIdlField> xField = pFields[i];
			Reference<XIdlClass> xPropType = xField->getType();
		    ::rtl::OUString aPropName = xField->getName();

			// Ist die PropertySequence gross genug?
			pAccess->checkPropertyArraysSize
				( pAllPropArray, pMapTypeArray, pPropertyConceptArray, rPropCount );

			// In eigenes Property-Array eintragen
			Property& rProp = pAllPropArray[ rPropCount ];
			rProp.Name = aPropName;
			rProp.Handle = rPropCount;
			rProp.Type = Type( xPropType->getTypeClass(), xPropType->getName() );
			FieldAccessMode eAccessMode = xField->getAccessMode();
			rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY || 
								eAccessMode == FieldAccessMode_CONST) 
								? READONLY : 0;

			//FieldAccessMode eAccessMode = xField->getAccessMode();
			//rProp.Attributes = (eAccessMode == FieldAccessMode::READONLY || eAccessMode == CONST) 
				//? PropertyAttribute::READONLY : 0;

			// Namen in Hashtable eintragen
			rPropNameMap[ aPropName ] = rPropCount;

			// Tabelle fuer XExactName pflegen
			rLowerToExactNameMap[ toLower( aPropName ) ] = aPropName;

			// Field merken
			pAccess->checkInterfaceArraySize( pAccess->aInterfaceSeq1, 
				pInterfaces1, rPropCount );
			pInterfaces1[ rPropCount ] = xField;
		
			// Art der Property merken
			pMapTypeArray[ rPropCount ] = MAP_FIELD;
			pPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
			pAccess->mnAttributePropCount++;

			// Count pflegen
			rPropCount++;
		}
	}

	// Property-Sequence auf die richtige Laenge bringen
	pAccess->maAllPropertySeq.realloc( pAccess->mnPropCount );

	return pAccess;
}

//*************************************************************************
Reference< XInterface > SAL_CALL ImplIntrospection_CreateInstance( const Reference< XMultiServiceFactory > & rSMgr ) 
	throw( RuntimeException )
{
	Reference< XInterface > xService = (OWeakObject*)(OComponentHelper*)new ImplIntrospection( rSMgr );
	return xService;
}

}

extern "C"
{
//==================================================================================================
void SAL_CALL component_getImplementationEnvironment(
	const sal_Char ** ppEnvTypeName, uno_Environment ** )
{
	*ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}
//==================================================================================================
void * SAL_CALL component_getFactory(
	const sal_Char * pImplName, void * pServiceManager, void * )
{
	void * pRet = 0;
	
	if (pServiceManager && rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0)
	{
		Reference< XSingleServiceFactory > xFactory( createOneInstanceFactory(
			reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
		    ::rtl::OUString::createFromAscii( pImplName ),
			stoc_inspect::ImplIntrospection_CreateInstance,
			stoc_inspect::ImplIntrospection::getSupportedServiceNames_Static() ) );
		
		if (xFactory.is())
		{
			xFactory->acquire();
			pRet = xFactory.get();
		}
	}
	
	return pRet;
}
}


