/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 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/strbuf.hxx>
#include <boost/unordered_map.hpp>

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;

using ::rtl::OUString;
using ::rtl::OUStringToOString;
using ::rtl::OString;

#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 OUString Str) const
    {
        return (size_t)Str.hashCode();
    }
};

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

typedef boost::unordered_map
<
    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 boost::unordered_map
<
    OUString,
    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 OUString& aPropertyName ) const;
    sal_Int32 getMethodIndex( const 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 OUString& aPropertyName, const Any& aValue) const;
//	void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const;
    Any getPropertyValue(const Any& obj, const 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 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 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;

            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 _ ?!
                OUString aStr = aMethodName.copy( 0, nFound );
                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 ];

                            OUString aTestClassName = xMethod2->getDeclaringClass()->getName();
                            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 OUString& aPropertyName, const Any& aValue ) const
//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const 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;
                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 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();
    }
}


//*******************************
//*** 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
    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 OUString& aPropertyName, const Any& aValue)
        throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException );
    virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName)
        throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) 
        throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) 
        throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) 
        throw( UnknownPropertyException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL removeVetoableChangeListener(const 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 OUString& Name) throw( RuntimeException );
    virtual sal_Bool SAL_CALL hasPropertyByName(const 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 OUString& Name)
        throw( NoSuchElementException, WrappedTargetException, RuntimeException );
    virtual Sequence<OUString> SAL_CALL getElementNames(void) throw( RuntimeException );
    virtual sal_Bool SAL_CALL hasByName(const OUString& Name) throw( RuntimeException );

    // Methoden von XNameContainer
    virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element)
        throw( IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element)
        throw( IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException );
    virtual void SAL_CALL removeByName(const 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;
}


//*******************************
//*** 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 : IntrospectionAccessHelper
{
    friend class ImplIntrospection;

    // Untersuchtes Objekt
    Any maInspectedObject;

    // Als Interface
    Reference<XInterface> mxIface;

    // Statische Daten der Introspection
    IntrospectionAccessStatic_Impl* mpStaticImpl;

    // Adapter-Implementation
    ImplIntrospectionAdapter* mpAdapter;

    // 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 OUString& Name, sal_Int32 PropertyConcepts)
        throw( NoSuchElementException, RuntimeException );
    virtual sal_Bool SAL_CALL hasProperty(const 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 OUString& Name, sal_Int32 MethodConcepts)
          throw( NoSuchMethodException, RuntimeException );
    virtual sal_Bool SAL_CALL hasMethod(const 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 OUString SAL_CALL getExactName( const OUString& rApproximateName ) throw( RuntimeException );
};

ImplIntrospectionAccess::ImplIntrospectionAccess
    ( const Any& obj, IntrospectionAccessStatic_Impl* pStaticImpl_ )
        : maInspectedObject( obj ), mpStaticImpl( pStaticImpl_ ), mpAdapter( NULL )
{
    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();

    // Eigene Referenz loslassen
    if (mpAdapter)
        mpAdapter->release();
}


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

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

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

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

void ImplIntrospectionAdapter::addPropertyChangeListener(const 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 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 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 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 OUString& Name)
    throw( RuntimeException )
{
    return mpAccess->getProperty( Name, PropertyConcept::ALL );
}

sal_Bool ImplIntrospectionAdapter::hasPropertyByName(const 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 OUString& Name)
    throw( NoSuchElementException, WrappedTargetException, RuntimeException )
{
    return mxObjNameAccess->getByName( Name );
}

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

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

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

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

void ImplIntrospectionAdapter::removeByName(const 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 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 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 ];
    }

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

    // Zusammengebastelte Sequence liefern
    return maLastPropertySeq;
}

Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const 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 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?
    if( !mpAdapter )
    {
        ((ImplIntrospectionAccess*)this)->mpAdapter = 
            new ImplIntrospectionAdapter( this, maInspectedObject, mpStaticImpl );

        // Selbst eine Referenz halten
        mpAdapter->acquire();
    }

    Reference<XInterface> xRet;
    Any aIfaceAny( mpAdapter->queryInterface( rType ) );
    if( aIfaceAny.hasValue() )
        xRet = *(Reference<XInterface>*)aIfaceAny.getValue();

    return xRet;
}

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

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

// Methoden von XExactName
OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName ) throw( RuntimeException )
{
    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 boost::unordered_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 boost::unordered_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
    OUString 					SAL_CALL getImplementationName() throw();
    sal_Bool					SAL_CALL supportsService(const OUString& ServiceName) throw();
    Sequence< OUString > 		SAL_CALL getSupportedServiceNames(void) throw();
    static OUString SAL_CALL	getImplementationName_Static(  );
    static Sequence< 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( 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(
            OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xContext;
        OSL_ASSERT( xContext.is() );
        if (xContext.is())
        {
            xContext->getValueByName(
                OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection") ) ) >>= mxCoreReflection;
            OSL_ENSURE( mxCoreReflection.is(), "### CoreReflection singleton not accessible!?" );
        }
    }
    if (! mxCoreReflection.is())
    {
        throw DeploymentException(
            OUString( RTL_CONSTASCII_USTRINGPARAM("/singletons/com.sun.star.reflection.theCoreReflection singleton not accessible") ),
            Reference< XInterface >() );
    }
    
    mxElementAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XElementAccess")) );
    mxNameContainerClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameContainer")) );
    mxNameAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XNameAccess")) );
    mxIndexContainerClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexContainer")) );
    mxIndexAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XIndexAccess")) );
    mxEnumerationAccessClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.container.XEnumerationAccess")) );
    mxInterfaceClass = mxCoreReflection->forName( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uno.XInterface")) );
    mxAggregationClass = mxCoreReflection->forName( 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
OUString ImplIntrospection::getImplementationName() throw()
{
    return getImplementationName_Static();	
}

// XServiceInfo
sal_Bool ImplIntrospection::supportsService(const OUString& ServiceName) throw()
{
    Sequence< OUString > aSNL = getSupportedServiceNames();
    const 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< OUString > ImplIntrospection::getSupportedServiceNames(void) throw()
{
    return getSupportedServiceNames_Static();
}

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

// ORegistryServiceManager_Static
Sequence< OUString > ImplIntrospection::getSupportedServiceNames_Static(void) throw()
{
    Sequence< OUString > aSNS( 1 );
    aSNS.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(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 boost::unordered_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 )
    {
        OUString sOWName( pTD->pTypeName );
        if( !xRefl.is() )
        {
            xRefl = Reference< XIdlReflection >( xMgr->createInstance( 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
                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_FAIL( OString( "Introspection: Property \"" ) +
                        OUStringToOString( aPropName, RTL_TEXTENCODING_ASCII_US ) +
                        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 ];
                            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
                            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;
                        }

                        OUString aMethName;
                        OUString aPropName;
                        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 != OUString( RTL_CONSTASCII_USTRINGPARAM("queryInterface")) )
                                    {
                                        rMethodConcept_i |= MethodConcept::DANGEROUS;
                                        continue;
                                    }
                                }
                            }
                            else if( rxMethod_i->getDeclaringClass()->equals( mxAggregationClass ) )
                            {
                                if( aMethName == 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 == 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
                                    OUString aMethName2 = rxMethod_k->getName();
                                    OUString aStartStr2 = aMethName2.copy( 0, 3 );
                                    // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!!
                                    if( !( aStartStr2 == OUString( RTL_CONSTASCII_USTRINGPARAM("set")) ) )
                                        continue;

                                    // Ist es denn der gleiche Name?
                                    OUString aPropName2 = aMethName2.copy( 3 );
                                    // ACHTUNG: Wegen SDL-Bug NICHT != bei 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 == OUString( RTL_CONSTASCII_USTRINGPARAM("add")) )
                            {
                                OUString aListenerStr( RTL_CONSTASCII_USTRINGPARAM("Listener" ) );

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

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

                                // Welcher Listener?
                                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
                                    OUString aMethName2 = rxMethod_k->getName();
                                    sal_Int32 nNameLen = aMethName2.getLength();
                                    sal_Int32 nCopyLen2 = (nNameLen < 6) ? nNameLen : 6;
                                    OUString aStartStr2 = aMethName2.copy( 0, nCopyLen2 );
                                    OUString aRemoveStr( RTL_CONSTASCII_USTRINGPARAM("remove" ) );
                                    // ACHTUNG: Wegen SDL-Bug NICHT != bei OUString verwenden !!!
                                    if( !( aStartStr2 == aRemoveStr ) )
                                        continue;

                                    // Ist es denn der gleiche Listener?
                                    if( aMethName2.getLength() - aRemoveStr.getLength() <= aListenerStr.getLength() )
                                        continue;
                                    OUString aListenerName2 = aMethName2.copy
                                        ( 6, aMethName2.getLength() - aRemoveStr.getLength() - aListenerStr.getLength() );
                                    // ACHTUNG: Wegen SDL-Bug NICHT != bei 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 == 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
                                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_FAIL( "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();
            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 ),
            OUString::createFromAscii( pImplName ),
            stoc_inspect::ImplIntrospection_CreateInstance,
            stoc_inspect::ImplIntrospection::getSupportedServiceNames_Static() ) );
        
        if (xFactory.is())
        {
            xFactory->acquire();
            pRet = xFactory.get();
        }
    }
    
    return pRet;
}
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
