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



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

#include "sal/config.h"

#include <vector>

#include <sal/alloca.h>

#include <osl/diagnose.h>
#include <rtl/alloc.h>
#include <rtl/ustring.hxx>

#include <uno/mapping.hxx>

#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/implbase1.hxx>
#include <typelib/typedescription.h>

#include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/reflection/XTypeDescription.hpp>
#include <com/sun/star/reflection/XEnumTypeDescription.hpp>
#include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
#include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
#include <com/sun/star/reflection/XMethodParameter.hpp>
#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp>
#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp>
#include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
#include <com/sun/star/reflection/XStructTypeDescription.hpp>
#include <com/sun/star/reflection/XUnionTypeDescription.hpp>
#include "com/sun/star/uno/RuntimeException.hpp"

#include "boost/scoped_array.hpp"

using namespace ::rtl;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::reflection;


namespace cppu
{

static typelib_TypeDescription * createCTD(
    Reference< container::XHierarchicalNameAccess > const & access,
    const Reference< XTypeDescription > & xType );

//==================================================================================================
inline static sal_Int64 coerceToInt64( const Any & rVal )
{
	switch (rVal.getValueTypeClass())
	{
	case TypeClass_CHAR:
		return *(sal_Unicode *)rVal.getValue();
	case TypeClass_BOOLEAN:
		return (*(sal_Bool *)rVal.getValue() ? 1 : 0);
	case TypeClass_BYTE:
		return *(sal_Int8 *)rVal.getValue();
	case TypeClass_SHORT:
		return *(sal_Int16 *)rVal.getValue();
	case TypeClass_UNSIGNED_SHORT:
		return *(sal_uInt16 *)rVal.getValue();
	case TypeClass_LONG:
		return *(sal_Int32 *)rVal.getValue();
	case TypeClass_UNSIGNED_LONG:
		return *(sal_uInt32 *)rVal.getValue();
	case TypeClass_HYPER:
		return *(sal_Int64 *)rVal.getValue();
	case TypeClass_UNSIGNED_HYPER:
		return *(sal_uInt64 *)rVal.getValue();
	case TypeClass_ENUM:
		return *(int *)rVal.getValue();
    default:
        OSL_ASSERT(false);
        return 0;
	}
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
	const Reference< XUnionTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is())
	{
		OUString aTypeName( xType->getName() );

		// discriminant type
		Reference< XTypeDescription > xDiscrTD( xType->getDiscriminantType() );
		OUString aDiscrTypeName( xDiscrTD->getName() );
		typelib_TypeDescriptionReference * pDiscrTypeRef = 0;
		typelib_typedescriptionreference_new( &pDiscrTypeRef,
											  (typelib_TypeClass)xDiscrTD->getTypeClass(),
											  aDiscrTypeName.pData );
		// default member type
		Reference< XTypeDescription > xDefaultMemberTD( xType->getDefaultMemberType() );
		OUString aDefMemberTypeName( xDefaultMemberTD->getName() );
		typelib_TypeDescriptionReference * pDefMemberTypeRef = 0;
		typelib_typedescriptionreference_new( &pDefMemberTypeRef,
											  (typelib_TypeClass)xDefaultMemberTD->getTypeClass(),
											  aDefMemberTypeName.pData );
		// init array
		Sequence< Any > aDiscriminants( xType->getDiscriminants() );
		Sequence< Reference< XTypeDescription > > aMemberTypes( xType->getMemberTypes() );
		Sequence< OUString > aMemberNames( xType->getMemberNames() );
		sal_Int32 nMembers = aDiscriminants.getLength();
		OSL_ASSERT( nMembers == aMemberNames.getLength() && nMembers == aMemberTypes.getLength() );

		const Any * pDiscriminants							= aDiscriminants.getConstArray();
		const Reference< XTypeDescription > * pMemberTypes	= aMemberTypes.getConstArray();
		const OUString * pMemberNames						= aMemberNames.getConstArray();

		typelib_Union_Init * pMembers = (typelib_Union_Init *)alloca( nMembers * sizeof(typelib_Union_Init) );

		sal_Int32 nPos;
		for ( nPos = nMembers; nPos--; )
		{
			typelib_Union_Init & rEntry = pMembers[nPos];
			// member discriminant
			rEntry.nDiscriminant = coerceToInt64( pDiscriminants[nPos] );
			// member type
			OUString aMemberTypeName( pMemberTypes[nPos]->getName() );
			rEntry.pTypeRef = 0;
			typelib_typedescriptionreference_new( &rEntry.pTypeRef,
												  (typelib_TypeClass)pMemberTypes[nPos]->getTypeClass(),
												  aMemberTypeName.pData );
			// member name
			rEntry.pMemberName = pMemberNames[nPos].pData;
		}

		typelib_typedescription_newUnion( &pRet, aTypeName.pData,
										  pDiscrTypeRef,
										  coerceToInt64( xType->getDefaultDiscriminant() ),
										  pDefMemberTypeRef,
										  nMembers, pMembers );

		for ( nPos = nMembers; nPos--; )
		{
			typelib_typedescriptionreference_release( pMembers[nPos].pTypeRef );
		}

		typelib_typedescriptionreference_release( pDiscrTypeRef );
		typelib_typedescriptionreference_release( pDefMemberTypeRef );
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
	const Reference< XCompoundTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is())
	{
		typelib_TypeDescription * pBaseType = createCTD(
			Reference< XCompoundTypeDescription >::query( xType->getBaseType() ) );
		if (pBaseType)
			typelib_typedescription_register( &pBaseType );

		// construct member init array
		const Sequence<Reference< XTypeDescription > > & rMemberTypes = xType->getMemberTypes();
		const Sequence< OUString > & rMemberNames					  = xType->getMemberNames();

		const Reference< XTypeDescription > * pMemberTypes = rMemberTypes.getConstArray();
		const OUString * pMemberNames					   = rMemberNames.getConstArray();

		sal_Int32 nMembers = rMemberTypes.getLength();
		OSL_ENSURE( nMembers == rMemberNames.getLength(), "### lens differ!" );

		OUString aTypeName( xType->getName() );

		typelib_CompoundMember_Init * pMemberInits = (typelib_CompoundMember_Init *)alloca(
			sizeof(typelib_CompoundMember_Init) * nMembers );

		sal_Int32 nPos;
		for ( nPos = nMembers; nPos--; )
		{
			typelib_CompoundMember_Init & rInit = pMemberInits[nPos];
			rInit.eTypeClass = (typelib_TypeClass)pMemberTypes[nPos]->getTypeClass();

			OUString aMemberTypeName( pMemberTypes[nPos]->getName() );
			rtl_uString_acquire( rInit.pTypeName = aMemberTypeName.pData );

			// string is held by rMemberNames
			rInit.pMemberName = pMemberNames[nPos].pData;
		}

		typelib_typedescription_new(
			&pRet,
			(typelib_TypeClass)xType->getTypeClass(),
			aTypeName.pData,
			(pBaseType ? pBaseType->pWeakRef : 0),
			nMembers, pMemberInits );

		// cleanup
		for ( nPos = nMembers; nPos--; )
		{
			rtl_uString_release( pMemberInits[nPos].pTypeName );
		}
		if (pBaseType)
			typelib_typedescription_release( pBaseType );
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
    Reference< container::XHierarchicalNameAccess > const & access,
	const Reference< XStructTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is() && xType->getTypeParameters().getLength() == 0)
	{
		typelib_TypeDescription * pBaseType = createCTD(
            access, xType->getBaseType() );
		if (pBaseType)
			typelib_typedescription_register( &pBaseType );

		// construct member init array
		const Sequence<Reference< XTypeDescription > > & rMemberTypes = xType->getMemberTypes();
		const Sequence< OUString > & rMemberNames					  = xType->getMemberNames();

		const Reference< XTypeDescription > * pMemberTypes = rMemberTypes.getConstArray();
		const OUString * pMemberNames					   = rMemberNames.getConstArray();

		sal_Int32 nMembers = rMemberTypes.getLength();
		OSL_ENSURE( nMembers == rMemberNames.getLength(), "### lens differ!" );

		OUString aTypeName( xType->getName() );

		typelib_StructMember_Init * pMemberInits = (typelib_StructMember_Init *)alloca(
			sizeof(typelib_StructMember_Init) * nMembers );

        Sequence< Reference< XTypeDescription > > templateMemberTypes;
        sal_Int32 i = aTypeName.indexOf('<');
        if (i >= 0) {
            Reference< XStructTypeDescription > templateDesc(
                access->getByHierarchicalName(aTypeName.copy(0, i)),
                UNO_QUERY_THROW);
            OSL_ASSERT(
                templateDesc->getTypeParameters().getLength()
                == xType->getTypeArguments().getLength());
            templateMemberTypes = templateDesc->getMemberTypes();
            OSL_ASSERT(templateMemberTypes.getLength() == nMembers);
        }

		sal_Int32 nPos;
		for ( nPos = nMembers; nPos--; )
		{
			typelib_StructMember_Init & rInit = pMemberInits[nPos];
			rInit.aBase.eTypeClass
                = (typelib_TypeClass)pMemberTypes[nPos]->getTypeClass();

			OUString aMemberTypeName( pMemberTypes[nPos]->getName() );
			rtl_uString_acquire(
                rInit.aBase.pTypeName = aMemberTypeName.pData );

			// string is held by rMemberNames
			rInit.aBase.pMemberName = pMemberNames[nPos].pData;

            rInit.bParameterizedType = templateMemberTypes.getLength() != 0
                && (templateMemberTypes[nPos]->getTypeClass()
                    == TypeClass_UNKNOWN);
		}

		typelib_typedescription_newStruct(
			&pRet,
			aTypeName.pData,
			(pBaseType ? pBaseType->pWeakRef : 0),
			nMembers, pMemberInits );

		// cleanup
		for ( nPos = nMembers; nPos--; )
		{
			rtl_uString_release( pMemberInits[nPos].aBase.pTypeName );
		}
		if (pBaseType)
			typelib_typedescription_release( pBaseType );
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
	const Reference< XInterfaceAttributeTypeDescription2 > & xAttribute )
{
	typelib_TypeDescription * pRet = 0;
	if (xAttribute.is())
	{
		OUString aMemberName( xAttribute->getName() );
		Reference< XTypeDescription > xType( xAttribute->getType() );
		OUString aMemberTypeName( xType->getName() );
        std::vector< rtl_uString * > getExc;
        Sequence< Reference< XCompoundTypeDescription > > getExcs(
            xAttribute->getGetExceptions() );
        for (sal_Int32 i = 0; i != getExcs.getLength(); ++i)
        {
            OSL_ASSERT( getExcs[i].is() );
            getExc.push_back( getExcs[i]->getName().pData );
        }
        std::vector< rtl_uString * > setExc;
        Sequence< Reference< XCompoundTypeDescription > > setExcs(
            xAttribute->getSetExceptions() );
        for (sal_Int32 i = 0; i != setExcs.getLength(); ++i)
        {
            OSL_ASSERT( setExcs[i].is() );
            setExc.push_back( setExcs[i]->getName().pData );
        }
		typelib_typedescription_newExtendedInterfaceAttribute(
			(typelib_InterfaceAttributeTypeDescription **)&pRet,
			xAttribute->getPosition(),
			aMemberName.pData, // name
			(typelib_TypeClass)xType->getTypeClass(),
			aMemberTypeName.pData, // type name
			xAttribute->isReadOnly(),
            getExc.size(), getExc.empty() ? 0 : &getExc[0],
            setExc.size(), setExc.empty() ? 0 : &setExc[0] );
	}
	return pRet;
}
//==================================================================================================
static typelib_TypeDescription * createCTD(
	const Reference< XInterfaceMethodTypeDescription > & xMethod )
{
	typelib_TypeDescription * pRet = 0;
	if (xMethod.is())
	{
		Reference< XTypeDescription > xReturnType( xMethod->getReturnType() );

		// init all params
		const Sequence<Reference< XMethodParameter > > & rParams = xMethod->getParameters();
		const Reference< XMethodParameter > * pParams			 = rParams.getConstArray();
		sal_Int32 nParams = rParams.getLength();

		typelib_Parameter_Init * pParamInit = (typelib_Parameter_Init *)alloca(
			sizeof(typelib_Parameter_Init) * nParams );

		sal_Int32 nPos;
		for ( nPos = nParams; nPos--; )
		{
			const Reference< XMethodParameter > & xParam = pParams[nPos];
			const Reference< XTypeDescription > & xType	 = xParam->getType();
			typelib_Parameter_Init & rInit = pParamInit[xParam->getPosition()];

			rInit.eTypeClass = (typelib_TypeClass)xType->getTypeClass();
			OUString aParamTypeName( xType->getName() );
			rtl_uString_acquire( rInit.pTypeName = aParamTypeName.pData );
			OUString aParamName( xParam->getName() );
			rtl_uString_acquire( rInit.pParamName = aParamName.pData );
			rInit.bIn  = xParam->isIn();
			rInit.bOut = xParam->isOut();
		}

		// init all exception strings
		const Sequence<Reference< XTypeDescription > > & rExceptions = xMethod->getExceptions();
		const Reference< XTypeDescription > * pExceptions = rExceptions.getConstArray();
		sal_Int32 nExceptions = rExceptions.getLength();
		rtl_uString ** ppExceptionNames = (rtl_uString **)alloca(
			sizeof(rtl_uString *) * nExceptions );

		for ( nPos = nExceptions; nPos--; )
		{
			OUString aExceptionTypeName( pExceptions[nPos]->getName() );
			rtl_uString_acquire( ppExceptionNames[nPos] = aExceptionTypeName.pData );
		}

		OUString aTypeName( xMethod->getName() );
		OUString aReturnTypeName( xReturnType->getName() );

		typelib_typedescription_newInterfaceMethod(
			(typelib_InterfaceMethodTypeDescription **)&pRet,
			xMethod->getPosition(),
			xMethod->isOneway(),
			aTypeName.pData,
			(typelib_TypeClass)xReturnType->getTypeClass(),
			aReturnTypeName.pData,
			nParams, pParamInit,
			nExceptions, ppExceptionNames );

		for ( nPos = nParams; nPos--; )
		{
			rtl_uString_release( pParamInit[nPos].pTypeName );
			rtl_uString_release( pParamInit[nPos].pParamName );
		}
		for ( nPos = nExceptions; nPos--; )
		{
			rtl_uString_release( ppExceptionNames[nPos] );
		}
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
    Reference< container::XHierarchicalNameAccess > const & access,
	const Reference< XInterfaceTypeDescription2 > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is())
	{
        Sequence< Reference< XTypeDescription > > aBases(xType->getBaseTypes());
        sal_Int32 nBases = aBases.getLength();
        // Exploit the fact that a typelib_TypeDescription for an interface type
        // is also the typelib_TypeDescriptionReference for that type:
        boost::scoped_array< typelib_TypeDescription * > aBaseTypes(
            new typelib_TypeDescription *[nBases]);
        {for (sal_Int32 i = 0; i < nBases; ++i) {
            typelib_TypeDescription * p = createCTD(access, aBases[i]);
            OSL_ASSERT(
                !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(p->eTypeClass));
            typelib_typedescription_register(&p);
            aBaseTypes[i] = p;
        }}
        typelib_TypeDescriptionReference ** pBaseTypeRefs
            = reinterpret_cast< typelib_TypeDescriptionReference ** >(
                aBaseTypes.get());

		// construct all member refs
		const Sequence<Reference< XInterfaceMemberTypeDescription > > & rMembers = xType->getMembers();
		sal_Int32 nMembers = rMembers.getLength();

		typelib_TypeDescriptionReference ** ppMemberRefs = (typelib_TypeDescriptionReference **)alloca(
			sizeof(typelib_TypeDescriptionReference *) * nMembers );

		const Reference< XInterfaceMemberTypeDescription > * pMembers = rMembers.getConstArray();

		OUString aTypeName( xType->getName() );

		sal_Int32 nPos;
		for ( nPos = nMembers; nPos--; )
		{
			OUString aMemberTypeName( pMembers[nPos]->getName() );
			ppMemberRefs[nPos] = 0;
			typelib_typedescriptionreference_new(
				ppMemberRefs + nPos,
				(typelib_TypeClass)pMembers[nPos]->getTypeClass(),
				aMemberTypeName.pData );
		}

		Uik uik = xType->getUik();

		typelib_typedescription_newMIInterface(
			(typelib_InterfaceTypeDescription **)&pRet,
			aTypeName.pData,
			uik.m_Data1, uik.m_Data2, uik.m_Data3, uik.m_Data4, uik.m_Data5,
            nBases, pBaseTypeRefs,
			nMembers, ppMemberRefs );

		// cleanup refs and base type
        {for (int i = 0; i < nBases; ++i) {
            typelib_typedescription_release(aBaseTypes[i]);
        }}

		for ( nPos = nMembers; nPos--; )
		{
			typelib_typedescriptionreference_release( ppMemberRefs[nPos] );
		}
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD( const Reference< XEnumTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is())
	{
		OUString aTypeName( xType->getName() );
		Sequence< OUString > aNames( xType->getEnumNames() );
		OSL_ASSERT( sizeof(OUString) == sizeof(rtl_uString *) ); // !!!
		Sequence< sal_Int32 > aValues( xType->getEnumValues() );

		typelib_typedescription_newEnum(
			&pRet, aTypeName.pData, xType->getDefaultEnumValue(),
			aNames.getLength(),
			(rtl_uString **)aNames.getConstArray(),
			const_cast< sal_Int32 * >( aValues.getConstArray() ) );
	}
	return pRet;
}
//==================================================================================================
inline static typelib_TypeDescription * createCTD(
    Reference< container::XHierarchicalNameAccess > const & access,
	const Reference< XIndirectTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;
	if (xType.is())
	{
		typelib_TypeDescription * pRefType = createCTD(
            access, xType->getReferencedType() );
		typelib_typedescription_register( &pRefType );

		OUString aTypeName( xType->getName() );

		typelib_typedescription_new(
			&pRet,
			(typelib_TypeClass)xType->getTypeClass(),
			aTypeName.pData,
			pRefType->pWeakRef,
			0, 0 );

		// cleanup
		if (pRefType)
			typelib_typedescription_release( pRefType );
	}
	return pRet;
}

//==================================================================================================
static typelib_TypeDescription * createCTD(
    Reference< container::XHierarchicalNameAccess > const & access,
    const Reference< XTypeDescription > & xType )
{
	typelib_TypeDescription * pRet = 0;

	if (xType.is())
	{
		switch (xType->getTypeClass())
		{
			// built in types
		case TypeClass_VOID:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("void") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_VOID, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_CHAR:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("char") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_CHAR, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_BOOLEAN:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("boolean") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_BOOLEAN, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_BYTE:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("byte") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_BYTE, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_SHORT:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("short") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_SHORT, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_UNSIGNED_SHORT:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("unsigned short") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_SHORT, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_LONG:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("long") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_LONG, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_UNSIGNED_LONG:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("unsigned long") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_LONG, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_HYPER:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("hyper") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_HYPER, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_UNSIGNED_HYPER:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("unsigned hyper") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_HYPER, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_FLOAT:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("float") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_FLOAT, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_DOUBLE:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("double") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_DOUBLE, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_STRING:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("string") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_STRING, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_TYPE:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("type") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_TYPE, aTypeName.pData, 0, 0, 0 );
			break;
		}
		case TypeClass_ANY:
		{
			OUString aTypeName( RTL_CONSTASCII_USTRINGPARAM("any") );
			typelib_typedescription_new( &pRet, typelib_TypeClass_ANY, aTypeName.pData, 0, 0, 0 );
			break;
		}

		case TypeClass_UNION:
			pRet = createCTD( Reference< XUnionTypeDescription >::query( xType ) );
			break;
		case TypeClass_EXCEPTION:
			pRet = createCTD( Reference< XCompoundTypeDescription >::query( xType ) );
			break;
		case TypeClass_STRUCT:
			pRet = createCTD(
                access, Reference< XStructTypeDescription >::query( xType ) );
			break;
		case TypeClass_ENUM:
			pRet = createCTD( Reference< XEnumTypeDescription >::query( xType ) );
			break;
		case TypeClass_TYPEDEF:
		{
			Reference< XIndirectTypeDescription > xTypedef( xType, UNO_QUERY );
			if (xTypedef.is())
				pRet = createCTD( access, xTypedef->getReferencedType() );
			break;
		}
		case TypeClass_SEQUENCE:
			pRet = createCTD(
                access, Reference< XIndirectTypeDescription >::query( xType ) );
			break;
		case TypeClass_INTERFACE:
			pRet = createCTD(
                access,
                Reference< XInterfaceTypeDescription2 >::query( xType ) );
			break;
		case TypeClass_INTERFACE_METHOD:
			pRet = createCTD( Reference< XInterfaceMethodTypeDescription >::query( xType ) );
			break;
		case TypeClass_INTERFACE_ATTRIBUTE:
			pRet = createCTD( Reference< XInterfaceAttributeTypeDescription2 >::query( xType ) );
			break;
        default:
            break;
		}
	}

	return pRet;
}


//==================================================================================================
extern "C"
{
static void SAL_CALL typelib_callback(
    void * pContext, typelib_TypeDescription ** ppRet, rtl_uString * pTypeName )
{
	OSL_ENSURE( pContext && ppRet && pTypeName, "### null ptr!" );
	if (ppRet)
	{
		if (*ppRet)
		{
			::typelib_typedescription_release( *ppRet );
			*ppRet = 0;
		}
		if (pContext && pTypeName)
		{
            Reference< container::XHierarchicalNameAccess > access(
                reinterpret_cast< container::XHierarchicalNameAccess * >(
                    pContext));
			try
			{
                OUString const & rTypeName = OUString::unacquired( &pTypeName );
				Reference< XTypeDescription > xTD;
				if (access->getByHierarchicalName(rTypeName ) >>= xTD)
				{
					*ppRet = createCTD( access, xTD );
				}
			}
            catch (container::NoSuchElementException & exc)
            {
                (void) exc; // avoid warning about unused variable
                OSL_TRACE(
                    "typelibrary type not available: %s",
                    OUStringToOString(
                        exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
            }
			catch (Exception & exc)
			{
                (void) exc; // avoid warning about unused variable
                OSL_TRACE(
                    "%s",
                    OUStringToOString(
                        exc.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
			}
		}
	}
}
}

//==================================================================================================
class EventListenerImpl
    : public WeakImplHelper1< lang::XEventListener >
{
    Reference< container::XHierarchicalNameAccess > m_xTDMgr;

public:
	inline EventListenerImpl(
        Reference< container::XHierarchicalNameAccess > const & xTDMgr )
        SAL_THROW( () )
        : m_xTDMgr( xTDMgr )
		{}

	// XEventListener
	virtual void SAL_CALL disposing( lang::EventObject const & rEvt )
        throw (RuntimeException);
};
//__________________________________________________________________________________________________
void EventListenerImpl::disposing( lang::EventObject const & rEvt )
    throw (RuntimeException)
{
    if (rEvt.Source != m_xTDMgr) {
        OSL_ASSERT(false);
    }
	// deregister of c typelib callback
	::typelib_typedescription_revokeCallback( m_xTDMgr.get(), typelib_callback );
}

//==================================================================================================
sal_Bool SAL_CALL installTypeDescriptionManager(
    Reference< container::XHierarchicalNameAccess > const & xTDMgr_c )
    SAL_THROW( () )
{
	uno::Environment curr_env(Environment::getCurrent());
	uno::Environment target_env(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV))));

	uno::Mapping curr2target(curr_env, target_env);


	Reference<container::XHierarchicalNameAccess> xTDMgr(
		reinterpret_cast<container::XHierarchicalNameAccess *>(
			curr2target.mapInterface(xTDMgr_c.get(), ::getCppuType(&xTDMgr_c))),
		SAL_NO_ACQUIRE);

    Reference< lang::XComponent > xComp( xTDMgr, UNO_QUERY );
    if (xComp.is())
    {
        xComp->addEventListener( new EventListenerImpl( xTDMgr ) );
        // register c typelib callback
        ::typelib_typedescription_registerCallback( xTDMgr.get(), typelib_callback );
        return sal_True;
    }
    return sal_False;
}

} // end namespace cppu

