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

#include "climaker_share.h"

#include "rtl/string.hxx"
#include "rtl/ustrbuf.hxx"
#include "com/sun/star/reflection/XIndirectTypeDescription.hpp"
#include "com/sun/star/reflection/XStructTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceTypeDescription2.hpp"
#include "com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription.hpp"
#include "com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp"
#include <vector>

using namespace ::System::Reflection;

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

namespace climaker
{
System::String ^ mapUnoPolymorphicName(System::String ^ unoName);
//------------------------------------------------------------------------------
static inline ::System::String ^ to_cts_name(
	OUString const & uno_name )
{
	OUStringBuffer buf( 7 + uno_name.getLength() );
	buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("unoidl.") );
	buf.append( uno_name );
	return ustring_to_String( buf.makeStringAndClear() );
}

//------------------------------------------------------------------------------
static inline ::System::Object ^ to_cli_constant( Any const & value )
{
	switch (value.getValueTypeClass())
	{
	case TypeClass_CHAR:
		return (::System::Object ^)((::System::Char) *reinterpret_cast< sal_Unicode const * >(
				value.getValue() ));
	case TypeClass_BOOLEAN:
		return (::System::Object ^)((::System::Boolean)
			 sal_False != *reinterpret_cast< sal_Bool const * >(
				 value.getValue() ));
	case TypeClass_BYTE:
		return (::System::Object ^)((::System::Byte) *reinterpret_cast< sal_Int8 const * >(
				value.getValue() ));
	case TypeClass_SHORT:
		return (::System::Object ^)((::System::Int16) *reinterpret_cast< sal_Int16 const * >(
				value.getValue() ));
	case TypeClass_UNSIGNED_SHORT:
		return (::System::Object ^)((::System::UInt16) *reinterpret_cast< sal_uInt16 const * >(
				value.getValue() ));
	case TypeClass_LONG:
		return (::System::Object ^)((::System::Int32) *reinterpret_cast< sal_Int32 const * >(
				value.getValue() ));
	case TypeClass_UNSIGNED_LONG:
		return (::System::Object ^)((::System::UInt32) *reinterpret_cast< sal_uInt32 const * >(
				value.getValue() ));
	case TypeClass_HYPER:
		return (::System::Object ^)((::System::Int64) *reinterpret_cast< sal_Int64 const * >(
				value.getValue() ));
	case TypeClass_UNSIGNED_HYPER:
		return (::System::Object ^)((::System::UInt64) *reinterpret_cast< sal_uInt64 const * >(
				value.getValue() ));
	case TypeClass_FLOAT:
		return (::System::Object ^)((::System::Single) *reinterpret_cast< float const * >(
				value.getValue() ));
	case TypeClass_DOUBLE:
		return (::System::Object ^)((::System::Double) *reinterpret_cast< double const * >(
				value.getValue() ));
	default:
		throw RuntimeException(
			OUSTR("unexpected constant type ") +
			value.getValueType().getTypeName(),
			Reference< XInterface >() );
	}
}

//------------------------------------------------------------------------------
static inline void emit_ldarg( Emit::ILGenerator ^ code, ::System::Int32 index )
{
	switch (index)
	{
	case 0:
		code->Emit( Emit::OpCodes::Ldarg_0 );
		break;
	case 1:
		code->Emit( Emit::OpCodes::Ldarg_1 );
		break;
	case 2:
		code->Emit( Emit::OpCodes::Ldarg_2 );
		break;
	case 3:
		code->Emit( Emit::OpCodes::Ldarg_3 );
		break;
	default:
		if (index < 0x100)
			code->Emit( Emit::OpCodes::Ldarg_S, (::System::Byte) index );
		else if (index < 0x8000)
			code->Emit( Emit::OpCodes::Ldarg_S, (::System::Int16) index );
		else
			code->Emit( Emit::OpCodes::Ldarg, index );
		break;
	}
}

void polymorphicStructNameToStructName(::System::String ^* sPolyName)
{
	if ((*sPolyName)->EndsWith(">") == false)
		return;

	int index = (*sPolyName)->IndexOf('<');
	OSL_ASSERT(index != -1);
	*sPolyName = (*sPolyName)->Substring(0, index);
}


System::String ^ mapUnoTypeName(System::String ^ typeName)
{
	::System::Text::StringBuilder ^ buf= gcnew System::Text::StringBuilder();
	::System::String ^ sUnoName = ::System::String::Copy(typeName);
	//determine if the type is a sequence and its dimensions
	int dims= 0;
	if (typeName->StartsWith("["))//if (usUnoName[0] == '[')
	{
		int index= 1;
		while (true)
		{
			if (typeName[ index++ ] == ']')//if (usUnoName[index++] == ']')
				dims++;
			if (typeName[ index++ ] != '[')//usUnoName[index++] != '[')
				break;
		}
		sUnoName = sUnoName->Substring(index - 1);//usUnoName = usUnoName.copy(index - 1);
	}
	if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoBool)))
		buf->Append(const_cast<System::String ^>(Constants::sBoolean));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoChar)))
		buf->Append(const_cast<System::String ^>(Constants::sChar));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoByte)))
		buf->Append(const_cast<System::String ^>(Constants::sByte));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoShort)))
		buf->Append(const_cast<System::String ^>(Constants::sInt16));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoUShort)))
		buf->Append(const_cast<System::String ^>(Constants::sUInt16));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoLong)))
		buf->Append(const_cast<System::String ^>(Constants::sInt32));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoULong)))
		buf->Append(const_cast<System::String ^>(Constants::sUInt32));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoHyper)))
		buf->Append(const_cast<System::String ^>(Constants::sInt64));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoUHyper)))
		buf->Append(const_cast<System::String ^>(Constants::sUInt64));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoFloat)))
		buf->Append(const_cast<System::String ^>(Constants::sSingle));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoDouble)))
		buf->Append(const_cast<System::String ^>(Constants::sDouble));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoString)))
		buf->Append(const_cast<System::String ^>(Constants::sString));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoVoid)))
		buf->Append(const_cast<System::String ^>(Constants::sVoid));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoType)))
		buf->Append(const_cast<System::String ^>(Constants::sType));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoXInterface)))
		buf->Append(const_cast<System::String ^>(Constants::sObject));
	else if (sUnoName->Equals(const_cast<System::String ^>(Constants::sUnoAny)))
	{
		buf->Append(const_cast<System::String ^>(Constants::sAny));
	}
	else
	{
		//put "unoidl." at the beginning
		buf->Append(const_cast<System::String ^>(Constants::sUnoidl));
		buf->Append(mapUnoPolymorphicName(sUnoName));
	}
	// append []
	for (;dims--;)
		buf->Append(const_cast<System::String ^>(Constants::sBrackets));

	return buf->ToString();
}


/** For example, there is an uno type
	com.sun.star.Foo<char, long>.
	The values in the type list
	are uno types and are replaced by cli types, such as System.Char,
	System.Int32, etc.

	Strings can be as complicated as this
	test.MyStruct<char,test.MyStruct<long, []string>>
 */
System::String ^ mapUnoPolymorphicName(System::String ^ unoName)
{
	int index = unoName->IndexOf('<');
	if (index == -1)
		return unoName;

	System::Text::StringBuilder ^ builder =
		gcnew System::Text::StringBuilder(unoName->Substring(0, index +1 ));

	//Find the first occurrence of ','
	//If the parameter is a polymorphic struct then we need to ignore everything
	//between the brackets because it can also contain commas
	//get the type list within < and >
	int endIndex = unoName->Length - 1;
	index++;
	int cur = index;
	int countParams = 0;
	while (cur <= endIndex)
	{
		System::Char c = unoName[cur];
		if (c == ',' || c == '>')
		{
			//insert a comma if needed
			if (countParams != 0)
				builder->Append(",");
			countParams++;
			System::String ^ sParam = unoName->Substring(index, cur - index);
			//skip the comma
			cur++;
			//the index to the beginning of the next param
			index = cur;
			builder->Append(mapUnoTypeName(sParam));
		}
		else if (c == '<')
		{
			cur++;
			//continue until the matching '>'
			int numNested = 0;
			for (;;cur++)
			{
				System::Char curChar = unoName[cur];
				if (curChar == '<')
				{
					numNested ++;
				}
				else if (curChar == '>')
				{
					if (numNested > 0)
						numNested--;
					else
						break;
				}
			}
		}
		cur++;
	}

	builder->Append((System::Char) '>');
	return builder->ToString();
}



//______________________________________________________________________________
Assembly ^ TypeEmitter::type_resolve(
	::System::Object ^, ::System::ResolveEventArgs ^ args )
{
	::System::String ^ cts_name = args->Name;

	// Two things have to happen before anything else, and both exist because
	// AppDomain::TypeResolve is not re-entrancy-guarded: asking the
	// ModuleBuilder for a name it cannot resolve raises TypeResolve again, for
	// the same name, and lands straight back here.
	//
	// First: refuse to answer a name we are already answering.  Returning
	// nullptr tells the runtime we cannot help, which is true, and ends the
	// chain instead of extending it.
	if (m_resolving->ContainsKey( cts_name ))
		return nullptr;

	// Second: consult the incomplete-interface table BEFORE the ModuleBuilder.
	// A type that has been DefineType'd but not yet CreateType'd is in that
	// table, and on .NET 4 ModuleBuilder::GetType does not return it -- so
	// asking the ModuleBuilder first is both slower and the thing that
	// recurses.
	::System::Type ^ ret_type = nullptr;
	{
		iface_entry ^ entry = dynamic_cast< iface_entry ^ >(
			m_incomplete_ifaces[ cts_name ] );
		if (nullptr != entry)
			ret_type = entry->m_type_builder;
	}

	if (nullptr == ret_type)
	{
		m_resolving->Add( cts_name, cts_name );
		try
		{
			ret_type = m_module_builder->GetType( cts_name, false /* no exc */ );
		}
		finally
		{
			m_resolving->Remove( cts_name );
		}
	}
	if (nullptr == ret_type)
	{
		sal_Int32 len = m_extra_assemblies->Length;
		for ( sal_Int32 pos = 0; pos < len; ++pos )
		{
			ret_type = m_extra_assemblies[ pos ]->GetType(
				cts_name, false /* no exc */ );
			if (nullptr != ret_type)
			{
				if (g_verbose)
				{
					::System::Console::WriteLine(
						"> resolving type {0} from {1}.",
						cts_name, ret_type->Assembly->FullName );
				}
				break;
			}
		}
	}
	if (nullptr != ret_type)
		return ret_type->Assembly;
	return nullptr;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	::System::String ^ cts_name, bool throw_exc )
{
	::System::Type ^ ret_type = m_module_builder->GetType( cts_name, false );

	// The lines below were commented out with the note "We get the type from
	// the ModuleBuilder even if the type is not complete but have been
	// defined."  That was true of the .NET this was written against; it is not
	// true of .NET 4, where ModuleBuilder::GetType returns null for a type that
	// has been DefineType'd but not yet CreateType'd.
	//
	// Leaving them commented out is not merely a missed lookup -- it does not
	// terminate.  The caller falls through to Type::GetType, which raises
	// AppDomain::TypeResolve, whose handler is type_resolve, which asks
	// ModuleBuilder::GetType for the same name, which raises TypeResolve
	// again.  AppDomain::TypeResolve has no re-entrancy guard, so climaker
	// dies with a StackOverflowException the second time any interface is
	// looked up -- the first time defines it, the second recurses:
	//
	//     Process is terminated due to StackOverflowException.
	//
	// The incomplete-interface table is exactly the right answer here, which
	// is presumably why it was written in the first place.
	if (ret_type == nullptr)
	{
		iface_entry ^ entry = dynamic_cast< iface_entry ^ >(
			m_incomplete_ifaces[ cts_name ] );
		if (nullptr != entry)
			ret_type = entry->m_type_builder;
	}
		//try the cli_basetypes assembly
	if (ret_type == nullptr)
	{
		::System::Text::StringBuilder ^ builder = gcnew ::System::Text::StringBuilder(cts_name);
		builder->Append(",cli_basetypes");
		ret_type = ::System::Type::GetType(builder->ToString());
	}

	if (ret_type == nullptr)
	{
		try
		{
			// may call on type_resolve()
			return ::System::Type::GetType( cts_name, throw_exc );
		}
		catch (::System::Exception ^ exc)
		{
			//If the type is not found one may have forgotten to specify assemblies with
			//additional types
			::System::Text::StringBuilder ^ sb = gcnew ::System::Text::StringBuilder();
			sb->Append(gcnew ::System::String("\nThe type "));
			sb->Append(cts_name);
			sb->Append(gcnew ::System::String(" \n could not be found. Did you forget to " \
				"specify an additional assembly with the --reference option?\n"));
			if (throw_exc)
				throw gcnew ::System::Exception(sb->ToString(), exc);
		}
	}
	else
	{
		return ret_type;
	}
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type_Exception()
{
	if (nullptr == m_type_Exception)
	{
		m_type_Exception = get_type(
			"unoidl.com.sun.star.uno.Exception", false /* no exc */ );
		if (nullptr == m_type_Exception)
		{
			// define hardcoded type unoidl.com.sun.star.uno.Exception
			Emit::TypeBuilder ^ type_builder =
				m_module_builder->DefineType(
					  "unoidl.com.sun.star.uno.Exception",
					  (TypeAttributes) (TypeAttributes::Public |
										TypeAttributes::BeforeFieldInit |
										TypeAttributes::AnsiClass),
					  ::System::Exception::typeid );
			Emit::FieldBuilder ^ field_Context = type_builder->DefineField(
				"Context", ::System::Object::typeid,
				FieldAttributes::Public );
			// default .ctor
			type_builder->DefineDefaultConstructor( c_ctor_method_attr );
			// .ctor
			cli::array< ::System::Type ^ > ^ param_types =
				  gcnew cli::array< ::System::Type ^ >( 2 );
			param_types[ 0 ] = ::System::String::typeid;
			param_types[ 1 ] = ::System::Object::typeid;
			Emit::ConstructorBuilder ^ ctor_builder =
				type_builder->DefineConstructor(
					c_ctor_method_attr, CallingConventions::Standard,
					param_types );
			ctor_builder->DefineParameter(
				1, ParameterAttributes::In, "Message" );
			ctor_builder->DefineParameter(
				2, ParameterAttributes::In, "Context" );
			Emit::ILGenerator ^ code = ctor_builder->GetILGenerator();
			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit( Emit::OpCodes::Ldarg_1 );
			param_types = gcnew cli::array< ::System::Type ^ >( 1 );
			param_types[ 0 ] = ::System::String::typeid;
			code->Emit(
				Emit::OpCodes::Call,
				::System::Exception::typeid
				  ->GetConstructor( param_types ) );
			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit( Emit::OpCodes::Ldarg_2 );
			code->Emit( Emit::OpCodes::Stfld, field_Context );
			code->Emit( Emit::OpCodes::Ret );

			if (g_verbose)
			{
				::System::Console::WriteLine(
					"> emitting exception type "
					"unoidl.com.sun.star.uno.Exception" );
			}
			m_type_Exception = type_builder->CreateType();
		}
	}
	return m_type_Exception;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type_RuntimeException()
{
	if (nullptr == m_type_RuntimeException)
	{
		m_type_RuntimeException = get_type(
			"unoidl.com.sun.star.uno.RuntimeException", false /* no exc */ );
		if (nullptr == m_type_RuntimeException)
		{
			// define hardcoded type unoidl.com.sun.star.uno.RuntimeException
			::System::Type ^ type_Exception = get_type_Exception();
			Emit::TypeBuilder ^ type_builder =
				  m_module_builder->DefineType(
					  "unoidl.com.sun.star.uno.RuntimeException",
					  (TypeAttributes) (TypeAttributes::Public |
										TypeAttributes::BeforeFieldInit |
										TypeAttributes::AnsiClass),
					  type_Exception );
			// default .ctor
			type_builder->DefineDefaultConstructor( c_ctor_method_attr );
			// .ctor
			cli::array< ::System::Type ^ > ^ param_types =
				  gcnew cli::array< ::System::Type ^ >( 2 );
			param_types[ 0 ] = ::System::String::typeid;
			param_types[ 1 ] = ::System::Object::typeid;
			Emit::ConstructorBuilder ^ ctor_builder =
				type_builder->DefineConstructor(
					c_ctor_method_attr, CallingConventions::Standard,
					param_types );
			ctor_builder->DefineParameter(
				1, ParameterAttributes::In, "Message" );
			ctor_builder->DefineParameter(
				2, ParameterAttributes::In, "Context" );
			Emit::ILGenerator ^ code = ctor_builder->GetILGenerator();
			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit( Emit::OpCodes::Ldarg_1 );
			code->Emit( Emit::OpCodes::Ldarg_2 );
			code->Emit(
				Emit::OpCodes::Call,
				type_Exception->GetConstructor( param_types ) );
			code->Emit( Emit::OpCodes::Ret );

			if (g_verbose)
			{
				::System::Console::WriteLine(
					"> emitting exception type "
					"unoidl.com.sun.star.uno.RuntimeException" );
			}
			m_type_RuntimeException = type_builder->CreateType();
		}
	}
	return m_type_RuntimeException;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XConstantTypeDescription > const & xType )
{
	::System::String ^ cts_name = to_cts_name( xType->getName() );
	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (nullptr == ret_type)
	{
		Reference< reflection::XConstantTypeDescription > xConstant(
			xType, UNO_QUERY_THROW );
		::System::Object ^ constant =
			  to_cli_constant( xConstant->getConstantValue() );
		Emit::TypeBuilder ^ type_builder =
			m_module_builder->DefineType(
				cts_name,
				(TypeAttributes) (TypeAttributes::Public |
								  TypeAttributes::Sealed |
								  TypeAttributes::BeforeFieldInit |
								  TypeAttributes::AnsiClass) );

		Emit::FieldBuilder ^ field_builder = type_builder->DefineField(
			cts_name->Substring( cts_name->LastIndexOf( '.' ) +1 ),
			constant->GetType(),
			(FieldAttributes) (FieldAttributes::Public |
							   FieldAttributes::Static |
							   FieldAttributes::Literal) );
		field_builder->SetConstant( constant );

		if (g_verbose)
		{
			::System::Console::WriteLine(
				"> emitting constant type {0}", cts_name );
		}
		ret_type = type_builder->CreateType();
	}
	return ret_type;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XConstantsTypeDescription > const & xType )
{
	::System::String ^ cts_name = to_cts_name( xType->getName() );
	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (nullptr == ret_type)
	{
		Emit::TypeBuilder ^ type_builder =
			m_module_builder->DefineType(
				cts_name,
				(TypeAttributes) (TypeAttributes::Public |
								  TypeAttributes::Sealed |
								  TypeAttributes::BeforeFieldInit |
								  TypeAttributes::AnsiClass) );

		Sequence< Reference<
			reflection::XConstantTypeDescription > > seq_constants(
				xType->getConstants() );
		Reference< reflection::XConstantTypeDescription > const * constants =
			seq_constants.getConstArray();
		sal_Int32 constants_length = seq_constants.getLength();
		for ( sal_Int32 constants_pos = 0;
			  constants_pos < constants_length; ++constants_pos )
		{
			Reference<
				reflection::XConstantTypeDescription > const & xConstant =
				constants[ constants_pos ];
			::System::Object ^ constant =
				  to_cli_constant( xConstant->getConstantValue() );
			::System::String ^ uno_name =
				  ustring_to_String( xConstant->getName() );
			Emit::FieldBuilder ^ field_builder = type_builder->DefineField(
				uno_name->Substring( uno_name->LastIndexOf( '.' ) +1 ),
				constant->GetType(),
				(FieldAttributes) (FieldAttributes::Public |
								   FieldAttributes::Static |
								   FieldAttributes::Literal) );
			field_builder->SetConstant( constant );
		}

		if (g_verbose)
		{
			::System::Console::WriteLine(
				"> emitting constants group type {0}", cts_name );
		}
		ret_type = type_builder->CreateType();
	}
	return ret_type;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XEnumTypeDescription > const & xType )
{
	::System::String ^ cts_name = to_cts_name( xType->getName() );
	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (nullptr == ret_type)
	{
//		 Emit::EnumBuilder ^ enum_builder =
//			 m_module_builder->DefineEnum(
//				 cts_name,
//				 (TypeAttributes) (TypeAttributes::Public |
// //								   TypeAttributes::Sealed |
//								   TypeAttributes::AnsiClass),
//				 ::System::Int32::typeid );
		// workaround enum builder bug
		Emit::TypeBuilder ^ enum_builder =
			m_module_builder->DefineType(
				cts_name,
				(TypeAttributes) (TypeAttributes::Public |
								  TypeAttributes::Sealed),
				::System::Enum::typeid );
		enum_builder->DefineField(
			"value__", ::System::Int32::typeid,
			(FieldAttributes) (FieldAttributes::Private |
							   FieldAttributes::SpecialName |
							   FieldAttributes::RTSpecialName) );
		Sequence< OUString > seq_enum_names( xType->getEnumNames() );
		Sequence< sal_Int32 > seq_enum_values( xType->getEnumValues() );
		sal_Int32 enum_length = seq_enum_names.getLength();
		OSL_ASSERT( enum_length == seq_enum_values.getLength() );
		OUString const * enum_names = seq_enum_names.getConstArray();
		sal_Int32 const * enum_values = seq_enum_values.getConstArray();
		for ( sal_Int32 enum_pos = 0; enum_pos < enum_length; ++enum_pos )
		{
//			 enum_builder->DefineLiteral(
//				 ustring_to_String( enum_names[ enum_pos ] ),
//				 (::System::Object ^)((::System::Int32) enum_values[ enum_pos ]) );
			Emit::FieldBuilder ^ field_builder =
				enum_builder->DefineField(
					ustring_to_String( enum_names[ enum_pos ] ),
					enum_builder,
					(FieldAttributes) (FieldAttributes::Public |
									   FieldAttributes::Static |
									   FieldAttributes::Literal) );
			field_builder->SetConstant(
				(::System::Object ^)((::System::Int32) enum_values[ enum_pos ]) );
		}

		if (g_verbose)
		{
			::System::Console::WriteLine(
				"> emitting enum type {0}", cts_name );
		}
		ret_type = enum_builder->CreateType();
	}
	return ret_type;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XCompoundTypeDescription > const & xType )
{
	OUString uno_name( xType->getName() );
	if (TypeClass_EXCEPTION == xType->getTypeClass())
	{
		if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
									   "com.sun.star.uno.Exception") ))
		{
			return get_type_Exception();
		}
		if (uno_name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
									   "com.sun.star.uno.RuntimeException") ))
		{
			return get_type_RuntimeException();
		}
	}
	::System::String ^ cts_name = to_cts_name( uno_name );
	// if the struct is an instantiated polymorphic struct then we create the simple struct name
	// For example:
	// void func ([in] PolyStruct<boolean> arg);
	//PolyStruct<boolean> will be converted to PolyStruct
	polymorphicStructNameToStructName( & cts_name);

	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (nullptr == ret_type)
	{
		Reference< reflection::XCompoundTypeDescription > xBaseType(
			xType->getBaseType(), UNO_QUERY );
		::System::Type ^ base_type = (xBaseType.is()
									  ? get_type( xBaseType )
									  : ::System::Object::typeid);
		Emit::TypeBuilder ^ type_builder =
			m_module_builder->DefineType(
				cts_name,
				(TypeAttributes) (TypeAttributes::Public |
								  TypeAttributes::BeforeFieldInit |
								  TypeAttributes::AnsiClass),
				base_type );


		// insert to be completed
		struct_entry ^ entry = gcnew struct_entry();
		xType->acquire();
		entry->m_xType = xType.get();
		entry->m_type_builder = type_builder;
		entry->m_base_type = base_type;
		m_incomplete_structs->Add( cts_name, entry );

		// type is incomplete
		ret_type = type_builder;
	}

	//In case of an instantiated polymorphic struct we want to return a
	//uno.PolymorphicType (inherits Type) rather then Type. This is needed for constructing
	//the service code. We can only do that if the struct is completed.
	if (m_generated_structs[ cts_name ])
	{
		Reference< reflection::XStructTypeDescription> xStructTypeDesc(
			xType, UNO_QUERY);

		if (xStructTypeDesc.is())
		{
			Sequence< Reference< reflection::XTypeDescription > > seqTypeArgs = xStructTypeDesc->getTypeArguments();
			sal_Int32 numTypes = seqTypeArgs.getLength();
			if (numTypes > 0)
			{
				//it is an instantiated polymorphic struct
				::System::String ^ sCliName = mapUnoTypeName(ustring_to_String(xType->getName()));
				ret_type = ::uno::PolymorphicType::GetType(ret_type, sCliName);
			}
		}
	}
	return ret_type;
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XInterfaceTypeDescription2 > const & xType )
{
	OUString uno_name( xType->getName() );
	if (uno_name.equalsAsciiL(
			RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ))
	{
		return ::System::Object::typeid;
	}

	::System::String ^ cts_name = to_cts_name( xType->getName() );
	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (nullptr == ret_type)
	{
		Emit::TypeBuilder ^ type_builder;

		TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public |
												TypeAttributes::Interface |
												TypeAttributes::Abstract |
												TypeAttributes::AnsiClass);

		std::vector<Reference<reflection::XInterfaceTypeDescription2> > vecBaseTypes;
		Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes =
			xType->getBaseTypes();
		if (seqBaseTypes.getLength() > 0)
		{
			for (int i = 0; i < seqBaseTypes.getLength(); i++)
			{
				Reference<reflection::XInterfaceTypeDescription2> xIfaceTd =
					resolveInterfaceTypedef(seqBaseTypes[i]);

				if (xIfaceTd->getName().equalsAsciiL(
						RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False)
				{
					vecBaseTypes.push_back(xIfaceTd);
				}
			}

			cli::array< ::System::Type ^ > ^ base_interfaces =
				  gcnew cli::array< ::System::Type ^ >( vecBaseTypes.size() );

			typedef std::vector<Reference<reflection::XInterfaceTypeDescription2> >::const_iterator it;
			int index = 0;
			for (it i = vecBaseTypes.begin(); i != vecBaseTypes.end(); i++, index++)
				base_interfaces[ index ] = get_type( *i );
			type_builder = m_module_builder->DefineType(
				cts_name, attr, nullptr, base_interfaces );
		}
		else
		{
			::System::Console::WriteLine(
				"warning: IDL interface {0} is not derived from "
				"com.sun.star.uno.XInterface!",
				ustring_to_String( uno_name ) );

			type_builder = m_module_builder->DefineType( cts_name, attr );
		}

		// insert to be completed
		iface_entry ^ entry = gcnew iface_entry();
		xType->acquire();
		entry->m_xType = xType.get();
		entry->m_type_builder = type_builder;
		m_incomplete_ifaces->Add( cts_name, entry );

		// type is incomplete
		ret_type = type_builder;
	}
	return ret_type;
}


//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XServiceTypeDescription2 > const & xType )
{
	if (xType->isSingleInterfaceBased() == sal_False)
		return nullptr;

	System::String ^ cts_name = to_cts_name( xType->getName() );
	System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (ret_type != nullptr)
		return ret_type;

	TypeAttributes attr = (TypeAttributes) (TypeAttributes::Public |
											TypeAttributes::Sealed |
											TypeAttributes::BeforeFieldInit |
											TypeAttributes::AnsiClass);

	Emit::TypeBuilder ^ type_builder = m_module_builder->DefineType(
		cts_name, attr);

	// insert to be completed
	service_entry ^ entry = gcnew service_entry();
	xType->acquire();
	entry->m_xType = xType.get();
	entry->m_type_builder = type_builder;
	m_incomplete_services->Add(cts_name,entry );

	return type_builder;
}

::System::Type ^ TypeEmitter::get_type(
	Reference<reflection::XSingletonTypeDescription2 > const & xType )
{
	if (xType->isInterfaceBased() == sal_False)
		return nullptr;

	::System::String ^ cts_name = to_cts_name( xType->getName() );
	::System::Type ^ ret_type = get_type( cts_name, false /* no exc */ );
	if (ret_type != nullptr)
		return ret_type;

	TypeAttributes attr = static_cast<TypeAttributes>(
		TypeAttributes::Public |
		TypeAttributes::Sealed |
		TypeAttributes::BeforeFieldInit |
		TypeAttributes::AnsiClass);

	Emit::TypeBuilder ^ type_builder = m_module_builder->DefineType(
		cts_name, attr);

	// insert to be completed
	singleton_entry ^ entry = gcnew singleton_entry();
	xType->acquire();
	entry->m_xType = xType.get();
	entry->m_type_builder = type_builder;
	m_incomplete_singletons->Add(cts_name,entry );

	return type_builder;

}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::complete_iface_type( iface_entry ^ entry )
{
	Emit::TypeBuilder ^ type_builder = entry->m_type_builder;
	reflection::XInterfaceTypeDescription2 * xType = entry->m_xType;

	Sequence<Reference< reflection::XTypeDescription > > seqBaseTypes( xType->getBaseTypes() );
	if (seqBaseTypes.getLength() > 0)
	{
		for (int i = 0; i < seqBaseTypes.getLength(); i++)
		{
			//make sure we get the interface rather then a typedef
			Reference<reflection::XInterfaceTypeDescription2> aBaseType =
				resolveInterfaceTypedef( seqBaseTypes[i]);

			if (aBaseType->getName().equalsAsciiL(
					RTL_CONSTASCII_STRINGPARAM("com.sun.star.uno.XInterface") ) == sal_False)
			{
				::System::String ^ basetype_name = to_cts_name( aBaseType->getName() );
				iface_entry ^ base_entry = dynamic_cast< iface_entry ^ >(
					m_incomplete_ifaces[ basetype_name ] );
				if (nullptr != base_entry)
				{
				// complete uncompleted base type first
					complete_iface_type( base_entry );
				}
			}
		}
	}

	Sequence<
		Reference< reflection::XInterfaceMemberTypeDescription > > seq_members(
			xType->getMembers() );
	Reference< reflection::XInterfaceMemberTypeDescription > const * members =
		seq_members.getConstArray();
	sal_Int32 members_length = seq_members.getLength();
	for ( sal_Int32 members_pos = 0;
		  members_pos < members_length; ++members_pos )
	{
		Reference<
			reflection::XInterfaceMemberTypeDescription > const & xMember =
			members[ members_pos ];
		Sequence< Reference< reflection::XTypeDescription > > seq_exceptions;
		Emit::MethodBuilder ^ method_builder;

		const MethodAttributes c_method_attr = (MethodAttributes)
			(MethodAttributes::Public |
			 MethodAttributes::Abstract |
			 MethodAttributes::Virtual |
			 MethodAttributes::NewSlot |
			 MethodAttributes::HideBySig);
//#if defined(_MSC_VER) && (_MSC_VER < 1400)
//			 MethodAttributes::Instance);
//#else
//		 Instance);
//#endif

		if (TypeClass_INTERFACE_METHOD == xMember->getTypeClass())
		{
			Reference< reflection::XInterfaceMethodTypeDescription > xMethod(
				xMember, UNO_QUERY_THROW );

			Sequence<
				Reference< reflection::XMethodParameter > > seq_parameters(
					xMethod->getParameters() );
			sal_Int32 params_length = seq_parameters.getLength();
			cli::array< ::System::Type ^ > ^ param_types =
				  gcnew cli::array< ::System::Type ^ >( params_length );
			Reference< reflection::XMethodParameter > const * parameters =
				seq_parameters.getConstArray();
			// first determine all types
			//Make the first param type as return type
			sal_Int32 params_pos = 0;
			for ( ; params_pos < params_length; ++params_pos )
			{
				Reference< reflection::XMethodParameter > const & xParam =
					parameters[ params_pos ];
				::System::Type ^ param_type = get_type( xParam->getType() );
				::System::String ^ param_type_name = param_type->FullName;
				if (xParam->isOut())
				{
					param_type = get_type(
						::System::String::Concat(
							param_type_name, "&" ), true );
				}
				param_types[ xParam->getPosition() ] = param_type;
			}


			// create method
//			 if (tb)
//				 method_builder = type_builder->DefineMethod(
//				 ustring_to_String( xMethod->getMemberName() ),
//				 c_method_attr, tb,
//				 param_types );
//			 else
				method_builder = type_builder->DefineMethod(
					ustring_to_String( xMethod->getMemberName() ),
					c_method_attr, get_type( xMethod->getReturnType() ),
					param_types );
			// then define parameter infos
			params_pos = 0;
			for ( ; params_pos < params_length; ++params_pos )
			{
				Reference< reflection::XMethodParameter > const & xParam =
					parameters[ params_pos ];
				long param_flags = 0;
				if (xParam->isIn())
					param_flags |= (long)ParameterAttributes::In;
				if (xParam->isOut())
					param_flags |= (long)ParameterAttributes::Out;
				OSL_ASSERT( 0 != param_flags );
				method_builder->DefineParameter(
					xParam->getPosition() +1 /* starts with 1 */,
					(ParameterAttributes) param_flags,
					ustring_to_String( xParam->getName() ) );
			}
			//Apply attribute TypeParametersAttribute to return value if it
			//is a parameterized Type. Currently only structs can have parameters.
			Reference<reflection::XStructTypeDescription> xReturnStruct(
				xMethod->getReturnType(), UNO_QUERY);

			if (xReturnStruct.is())
			{
				Sequence<Reference<reflection::XTypeDescription> > seq_type_args =
					xReturnStruct->getTypeArguments();
				if (seq_type_args.getLength() != 0)
				{
					//get th ctor of the attribute
					cli::array< ::System::Type ^ > ^ arCtor = {::System::Type::GetType("System.Type[]")};
					//Get the arguments for the attribute's ctor
					Reference<reflection::XTypeDescription> const * arXTypeArgs =
						seq_type_args.getConstArray();
					int numTypes = seq_type_args.getLength();
					cli::array< ::System::Type ^ > ^ arCtsTypes = gcnew cli::array< ::System::Type ^ >( numTypes );
					for (int i = 0; i < numTypes; i++)
						arCtsTypes[i] = get_type(arXTypeArgs[i]);
					cli::array< ::System::Object ^ > ^ arArgs = {arCtsTypes};

					Emit::CustomAttributeBuilder ^ attrBuilder =
						gcnew Emit::CustomAttributeBuilder(
							::uno::TypeArgumentsAttribute::typeid
							->GetConstructor( arCtor),
							arArgs);

					method_builder->SetCustomAttribute(attrBuilder);
				}
			}

			//define UNO exception attribute (exceptions)--------------------------------------
			Emit::CustomAttributeBuilder ^ attrBuilder =
				get_iface_method_exception_attribute(xMethod);
			if (attrBuilder != nullptr)
				method_builder->SetCustomAttribute(attrBuilder);

			// oneway attribute
			if (xMethod->isOneway())
			{
				cli::array< ::System::Type ^ > ^ arCtorOneway = gcnew cli::array< ::System::Type ^ >( 0 );
				cli::array< ::System::Object ^ > ^ arArgs = gcnew cli::array< ::System::Object ^ >( 0 );
				Emit::CustomAttributeBuilder ^ attrBuilder =
					gcnew Emit::CustomAttributeBuilder(
						::uno::OnewayAttribute::typeid->GetConstructor( arCtorOneway),
						arArgs);
				method_builder->SetCustomAttribute(attrBuilder);
			}
		}
		else // attribute
		{
			OSL_ASSERT(
				TypeClass_INTERFACE_ATTRIBUTE == xMember->getTypeClass() );
			Reference<
				reflection::XInterfaceAttributeTypeDescription2 > xAttribute(
					xMember, UNO_QUERY_THROW );

			const MethodAttributes c_property_method_attr = (MethodAttributes)
				((int)c_method_attr | (int)MethodAttributes::SpecialName);

			::System::Type ^ attribute_type = get_type( xAttribute->getType() );
			cli::array< ::System::Type ^ > ^ parameters =
				  gcnew cli::array< ::System::Type ^ >( 0 );

			Emit::PropertyBuilder ^ property_builder =
				type_builder->DefineProperty(
					ustring_to_String( xAttribute->getMemberName() ),
					PropertyAttributes::None,
					attribute_type, parameters );

			//set BoundAttribute, if necessary
			if (xAttribute->isBound())
			{
				ConstructorInfo ^ ctorBoundAttr =
					::uno::BoundAttribute::typeid->GetConstructor(
						gcnew cli::array< System::Type ^ >( 0 ));
				Emit::CustomAttributeBuilder ^ attrBuilderBound =
					gcnew Emit::CustomAttributeBuilder(
						ctorBoundAttr, gcnew cli::array< ::System::Object ^ >( 0 ));
				property_builder->SetCustomAttribute(attrBuilderBound);
			}

			// getter
			Emit::MethodBuilder ^ method_builder =
				type_builder->DefineMethod(
					ustring_to_String( OUSTR("get_") +
									   xAttribute->getMemberName() ),
					c_property_method_attr, attribute_type, parameters );

			//define UNO exception attribute (exceptions)--------------------------------------
			Emit::CustomAttributeBuilder ^ attrBuilder =
				get_exception_attribute(xAttribute->getGetExceptions());
			if (attrBuilder != nullptr)
				method_builder->SetCustomAttribute(attrBuilder);

			property_builder->SetGetMethod( method_builder );

			if (! xAttribute->isReadOnly())
			{
				// setter
				parameters = gcnew cli::array< ::System::Type ^ >( 1 );
				parameters[ 0 ] = attribute_type;
				method_builder =
					type_builder->DefineMethod(
						ustring_to_String( OUSTR("set_") +
										   xAttribute->getMemberName() ),
						c_property_method_attr, nullptr, parameters );
				// define parameter info
				method_builder->DefineParameter(
					1 /* starts with 1 */, ParameterAttributes::In, "value" );
				//define UNO exception attribute (exceptions)--------------------------------------
				Emit::CustomAttributeBuilder ^ attrBuilder =
					get_exception_attribute(xAttribute->getSetExceptions());
				if (attrBuilder != nullptr)
					method_builder->SetCustomAttribute(attrBuilder);

				property_builder->SetSetMethod( method_builder );
			}
		}
	}

	// remove from incomplete types map
	::System::String ^ cts_name = type_builder->FullName;
	m_incomplete_ifaces->Remove( cts_name );
	xType->release();

	if (g_verbose)
	{
		::System::Console::WriteLine(
			"> emitting interface type {0}", cts_name );
	}
	return type_builder->CreateType();
}

::System::Type ^ TypeEmitter::complete_struct_type( struct_entry ^ entry )
{
	 OSL_ASSERT(entry);
	::System::String ^ cts_name = entry->m_type_builder->FullName;

	//Polymorphic struct, define uno.TypeParametersAttribute
	//A polymorphic struct cannot have a basetype.
	//When we create the template of the struct then we have no exact types
	//and the name does not contain a parameter list
	Sequence< OUString > seq_type_parameters;
	Reference< reflection::XStructTypeDescription> xStructTypeDesc(
		entry->m_xType, UNO_QUERY);
	if (xStructTypeDesc.is())
	{
		seq_type_parameters = xStructTypeDesc->getTypeParameters();
		int numTypes = 0;
		if ((numTypes = seq_type_parameters.getLength()) > 0)
		{
			cli::array< ::System::Object ^ > ^ aArg = gcnew cli::array< ::System::Object ^ >( numTypes );
			for (int i = 0; i < numTypes; i++)
				aArg[i] = ustring_to_String(seq_type_parameters.getConstArray()[i]);
			cli::array< ::System::Object ^ > ^ args = {aArg};

			cli::array< ::System::Type ^ > ^ arTypesCtor =
			{::System::Type::GetType("System.String[]")};
			Emit::CustomAttributeBuilder ^ attrBuilder =
				gcnew Emit::CustomAttributeBuilder(
				::uno::TypeParametersAttribute::typeid->GetConstructor(arTypesCtor),
				args);
			entry->m_type_builder->SetCustomAttribute(attrBuilder);
		}
	}

	// optional: lookup base type whether generated entry of this session
	struct_entry ^ base_type_entry = nullptr;
	if (nullptr != entry->m_base_type)
	{
		//ToDo maybe get from incomplete structs
		base_type_entry =
			dynamic_cast< struct_entry ^ >(
				m_generated_structs[ entry->m_base_type->FullName ] );
	}

		// members
	Sequence< Reference< reflection::XTypeDescription > > seq_members(
		entry->m_xType->getMemberTypes() );
	Sequence< OUString > seq_member_names( entry->m_xType->getMemberNames() );
	sal_Int32 members_length = seq_members.getLength();
	OSL_ASSERT( seq_member_names.getLength() == members_length );
	//check if we have a XTypeDescription for every member. If not then the user may
	//have forgotten to specify additional rdbs with the --extra option.
	Reference< reflection::XTypeDescription > const * pseq_members =
			seq_members.getConstArray();
	OUString const * pseq_member_names =
		seq_member_names.getConstArray();
	for (int i = 0; i < members_length; i++)
	{
		const OUString sType(entry->m_xType->getName());
		const OUString sMemberName(pseq_member_names[i]);
		if ( ! pseq_members[i].is())
			throw RuntimeException(OUSTR("Missing type description . Check if you need to " \
			"specify additional RDBs with the --extra option. Type missing for: ") + sType +
			OUSTR("::") + sMemberName,0);
	}

	sal_Int32 all_members_length = 0;
	sal_Int32 member_pos;
	sal_Int32 type_param_pos = 0;

	// collect base types; wrong order
	::System::Collections::ArrayList ^ base_types_list =
			gcnew ::System::Collections::ArrayList( 3 /* initial capacity */ );
	for (::System::Type ^ base_type_pos = entry->m_base_type;
		! base_type_pos->Equals( ::System::Object::typeid );
		base_type_pos = base_type_pos->BaseType )
	{
		base_types_list->Add( base_type_pos );
		if (base_type_pos->Equals( ::System::Exception::typeid ))
		{
			// special Message member
			all_members_length += 1;
			break; // don't include System.Exception base classes
		}
		else
		{
			//ensure the base type is complete. Otherwise GetFields won't work
			get_complete_struct(base_type_pos->FullName);
			all_members_length +=
				base_type_pos->GetFields(
				(BindingFlags) (BindingFlags::Instance |
				BindingFlags::Public |
				BindingFlags::DeclaredOnly) )
				->Length;
		}
	}

	// create all_members arrays; right order
	cli::array< ::System::String ^ > ^ all_member_names =
		gcnew cli::array< ::System::String ^ >( all_members_length + members_length );
	cli::array< ::System::Type ^ > ^ all_param_types =
		gcnew cli::array< ::System::Type ^ >( all_members_length + members_length );
	member_pos = 0;
	for ( sal_Int32 pos = base_types_list->Count; pos--; )
	{
		::System::Type ^ base_type = safe_cast< ::System::Type ^ >(
			base_types_list[ pos ] );
		if (base_type->Equals( ::System::Exception::typeid ))
		{
			all_member_names[ member_pos ] = "Message";
			all_param_types[ member_pos ] = ::System::String::typeid;
			++member_pos;
		}
		else
		{
			::System::String ^ base_type_name = base_type->FullName;

			//ToDo m_generated_structs?
			struct_entry ^ entry =
				dynamic_cast< struct_entry ^ >(
				m_generated_structs[ base_type_name ] );
			if (nullptr == entry)
			{
				// complete type
				cli::array< FieldInfo ^ > ^ fields =
					base_type->GetFields(
					(BindingFlags) (BindingFlags::Instance |
					BindingFlags::Public |
					BindingFlags::DeclaredOnly) );
				sal_Int32 len = fields->Length;
				for ( sal_Int32 pos = 0; pos < len; ++pos )
				{
					FieldInfo ^ field = fields[ pos ];
					all_member_names[ member_pos ] = field->Name;
					all_param_types[ member_pos ] = field->FieldType;
					++member_pos;
				}
			}
			else // generated during this session:
				// members may be incomplete ifaces
			{
				sal_Int32 len = entry->m_member_names->Length;
				for ( sal_Int32 pos = 0; pos < len; ++pos )
				{
					all_member_names[ member_pos ] =
						entry->m_member_names[ pos ];
					all_param_types[ member_pos ] =
						entry->m_param_types[ pos ];
					++member_pos;
				}
			}
		}
	}
	OSL_ASSERT( all_members_length == member_pos );

	// build up entry
//	struct_entry ^ entry = gcnew struct_entry();
	entry->m_member_names = gcnew cli::array< ::System::String ^ >( members_length );
	entry->m_param_types = gcnew cli::array< ::System::Type ^ >( members_length );

	// add members
	cli::array< Emit::FieldBuilder ^ > ^ members = gcnew cli::array< Emit::FieldBuilder ^ >( members_length );
	//Reference< reflection::XTypeDescription > const * pseq_members =
	//	seq_members.getConstArray();
	//OUString const * pseq_member_names =
	//	seq_member_names.getConstArray();

	int curParamIndex = 0; //count the fields which have parameterized types
	for ( member_pos = 0; member_pos < members_length; ++member_pos )
	{
		::System::String ^ field_name =
			ustring_to_String( pseq_member_names[ member_pos ] );
		::System::Type ^ field_type;
		//Special handling of struct parameter types
		bool bParameterizedType = false;
		if (pseq_members[ member_pos ]->getTypeClass() == TypeClass_UNKNOWN)
		{
			bParameterizedType = true;
			if (type_param_pos < seq_type_parameters.getLength())
			{
				field_type = ::System::Object::typeid;
				type_param_pos++;
			}
			else
			{
				throw RuntimeException(
					OUSTR("unexpected member type in ") + entry->m_xType->getName(),
					Reference< XInterface >() );
			}
		}
		else
		{
			field_type =
				get_type( pseq_members[ member_pos ] );
		}
		members[ member_pos ] =
			entry->m_type_builder->DefineField(
			field_name, field_type, FieldAttributes::Public );

		//parameterized type (polymorphic struct) ?
		if (bParameterizedType && xStructTypeDesc.is())
		{
			//get the name
			OSL_ASSERT(seq_type_parameters.getLength() > curParamIndex);
			::System::String ^ sTypeName = ustring_to_String(
				seq_type_parameters.getConstArray()[curParamIndex++]);
			cli::array< ::System::Object ^ > ^ args = {sTypeName};
			//set ParameterizedTypeAttribute
			cli::array< ::System::Type ^ > ^ arCtorTypes = {::System::String::typeid};

			Emit::CustomAttributeBuilder ^ attrBuilder =
				gcnew Emit::CustomAttributeBuilder(
				::uno::ParameterizedTypeAttribute::typeid
				->GetConstructor(arCtorTypes),
				args);

			members[member_pos]->SetCustomAttribute(attrBuilder);
		}
		// add to all_members
		all_member_names[ all_members_length + member_pos ] = field_name;
		all_param_types[ all_members_length + member_pos ] = field_type;
		// add to entry
		entry->m_member_names[ member_pos ] = field_name;
		entry->m_param_types[ member_pos ] = field_type;
	}
	all_members_length += members_length;

	// default .ctor
	Emit::ConstructorBuilder ^ ctor_builder =
		entry->m_type_builder->DefineConstructor(
		c_ctor_method_attr, CallingConventions::Standard,
		gcnew cli::array< ::System::Type ^ >( 0 ) );
	Emit::ILGenerator ^ code = ctor_builder->GetILGenerator();
	code->Emit( Emit::OpCodes::Ldarg_0 );
	code->Emit(
		Emit::OpCodes::Call,
		nullptr == base_type_entry
		? entry->m_base_type->GetConstructor( gcnew cli::array< ::System::Type ^ >( 0 ) )
		: base_type_entry->m_default_ctor );
	// default initialize members
	for ( member_pos = 0; member_pos < members_length; ++member_pos )
	{
		FieldInfo ^ field = members[ member_pos ];
		::System::Type ^ field_type = field->FieldType;
		//			::System::Type ^ new_field_type = m_module_builder->GetType(field_type->FullName, false);
		// default initialize:
		// string, type, enum, sequence, struct, exception, any
		if (field_type->Equals( ::System::String::typeid ))
		{
			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit( Emit::OpCodes::Ldstr, "" );
			code->Emit( Emit::OpCodes::Stfld, field );
		}
		else if (field_type->Equals( ::System::Type::typeid ))
		{
			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit(
				Emit::OpCodes::Ldtoken, ::System::Void::typeid );
			code->Emit(
				Emit::OpCodes::Call, m_method_info_Type_GetTypeFromHandle );
			code->Emit( Emit::OpCodes::Stfld, field );
		}
		else if (field_type->IsArray)
		{
			//Find the value type. In case of sequence<sequence< ... > > find the actual value type
			::System::Type ^ value = field_type;
			while ((value = value->GetElementType())->IsArray);
			//If the value type is a struct then make sure it is fully created.
			get_complete_struct(value->FullName);

			code->Emit( Emit::OpCodes::Ldarg_0 );
			code->Emit( Emit::OpCodes::Ldc_I4_0 );
			code->Emit(
				Emit::OpCodes::Newarr, field_type->GetElementType() );
			code->Emit( Emit::OpCodes::Stfld, field );
		}
		else if (field_type->IsValueType)
		{
			if (field_type->FullName->Equals( "uno.Any" ))
			{
				code->Emit( Emit::OpCodes::Ldarg_0 );
				code->Emit( Emit::OpCodes::Ldsfld, ::uno::Any::typeid->GetField("VOID"));
				code->Emit( Emit::OpCodes::Stfld, field );
			}
		}
		else if (field_type->IsClass)
		{
			/* may be XInterface */
			if (! field_type->Equals( ::System::Object::typeid ))
			{
				// struct, exception
				//make sure the struct is already complete.
				get_complete_struct(field_type->FullName);
				code->Emit( Emit::OpCodes::Ldarg_0 );
				code->Emit(
					Emit::OpCodes::Newobj,
					//GetConstructor requires that the member types of the object which is to be constructed are already known.
					field_type->GetConstructor(
					gcnew cli::array< ::System::Type ^ >( 0 ) ) );
				code->Emit( Emit::OpCodes::Stfld, field );
			}
		}
	}
	code->Emit( Emit::OpCodes::Ret );
	entry->m_default_ctor = ctor_builder;

	// parameterized .ctor including all base members
	ctor_builder = entry->m_type_builder->DefineConstructor(
		c_ctor_method_attr, CallingConventions::Standard, all_param_types );
	for ( member_pos = 0; member_pos < all_members_length; ++member_pos )
	{
		ctor_builder->DefineParameter(
			member_pos +1 /* starts with 1 */, ParameterAttributes::In,
			all_member_names[ member_pos ] );
	}
	code = ctor_builder->GetILGenerator();
	// call base .ctor
	code->Emit( Emit::OpCodes::Ldarg_0 ); // push this
	sal_Int32 base_members_length = all_members_length - members_length;
	cli::array< ::System::Type ^ > ^ param_types =
		gcnew cli::array< ::System::Type ^ >( base_members_length );
	for ( member_pos = 0; member_pos < base_members_length; ++member_pos )
	{
		emit_ldarg( code, member_pos +1 );
		param_types[ member_pos ] = all_param_types[ member_pos ];
	}
	code->Emit(
		Emit::OpCodes::Call,
		nullptr == base_type_entry
		? entry->m_base_type->GetConstructor( param_types )
		: base_type_entry->m_ctor );
	// initialize members
	for ( member_pos = 0; member_pos < members_length; ++member_pos )
	{
		code->Emit( Emit::OpCodes::Ldarg_0 ); // push this
		emit_ldarg( code, member_pos + base_members_length +1 );
		code->Emit( Emit::OpCodes::Stfld, members[ member_pos ] );
	}
	code->Emit( Emit::OpCodes::Ret );
	entry->m_ctor = ctor_builder;

	if (g_verbose)
	{
		::System::Console::WriteLine(
			"> emitting {0} type {1}",
			TypeClass_STRUCT == entry->m_xType->getTypeClass()
			? "struct"
			: "exception",
			cts_name);
	}
	// new entry
	m_generated_structs->Add(cts_name, entry );
	::System::Type ^ ret_type = entry->m_type_builder->CreateType();

	// remove from incomplete types map
	m_incomplete_structs->Remove( cts_name );
	entry->m_xType->release();

	if (g_verbose)
	{
		::System::Console::WriteLine(
			"> emitting struct type {0}", cts_name);
	}
	return ret_type;
}

//Examples of generated code
// 		public static XWeak constructor1(XComponentContext ctx)
// 		{
// 			XMultiComponentFactory factory = ctx.getServiceManager();
// 			if (factory == null)
// 				throw new com.sun.star.uno.DeploymentException("bla", null);
// 			return (XWeak) factory.createInstanceWithContext("service_specifier", ctx);
// 		}
// 		public static XWeak constructor2(XComponentContext ctx, int a, int b, Any c)
// 		{
// 			XMultiComponentFactory factory = ctx.getServiceManager();
// 			if (factory == null)
// 				throw new com.sun.star.uno.DeploymentException("bla", null);
// 			Any[] arAny = new Any[3];
// 			arAny[0] = new Any(typeof(int), a);
// 			arAny[1] = new Any(typeof(int), b);
//			arAny[2] = new Any(c.Type, c.Value);
// 			return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", arAny, ctx);
// 		}
// Notice that a any parameter is NOT wrapped by another any. Instead the new any is created with the type and value
// of the parameter.

// 		public static XWeak constructor3(XComponentContext ctx, params Any[] c)
// 		{
// 			XMultiComponentFactory factory = ctx.getServiceManager();
// 			if (factory == null)
// 				throw new com.sun.star.uno.DeploymentException("bla", null);
// 			return (XWeak) factory.createInstanceWithArgumentsAndContext("service_specifier", c, ctx);
//		}
::System::Type ^ TypeEmitter::complete_service_type(service_entry ^ entry)
{
	Emit::TypeBuilder ^ type_builder = entry->m_type_builder;
	reflection::XServiceTypeDescription2 * xServiceType = entry->m_xType;

	//Create the private default constructor
	Emit::ConstructorBuilder ^ ctor_builder =
		type_builder->DefineConstructor(
			(MethodAttributes) (MethodAttributes::Private |
								MethodAttributes::HideBySig |
								MethodAttributes::SpecialName |
								MethodAttributes::RTSpecialName),
			CallingConventions::Standard, nullptr);

	Emit::ILGenerator ^ ilGen = ctor_builder->GetILGenerator();
	ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this
	ilGen->Emit(
			Emit::OpCodes::Call,
			type_builder->BaseType->GetConstructor(gcnew cli::array< ::System::Type ^ >( 0 )));
	ilGen->Emit( Emit::OpCodes::Ret );


	//Create the service constructors.
	//obtain the interface which makes up this service, it is the return
	//type of the constructor functions
	Reference<reflection::XInterfaceTypeDescription2> xIfaceType(
		xServiceType->getInterface(), UNO_QUERY);
	if (xIfaceType.is () == sal_False)
		xIfaceType = resolveInterfaceTypedef(xServiceType->getInterface());
	System::Type ^ retType = get_type(xIfaceType);

	//Create the ConstructorInfo for a DeploymentException
	::System::Type ^ typeDeploymentExc =
		  get_type("unoidl.com.sun.star.uno.DeploymentException", true);

	cli::array< ::System::Type ^ > ^ arTypeCtor = {::System::String::typeid,
										 ::System::Object::typeid};
	::System::Reflection::ConstructorInfo ^ ctorDeploymentException  =
		  typeDeploymentExc->GetConstructor(arTypeCtor);

	Sequence<Reference<reflection::XServiceConstructorDescription> >  seqCtors =
		xServiceType->getConstructors();

	::System::Type ^ type_uno_exception = get_type("unoidl.com.sun.star.uno.Exception", true);

	for (int i = seqCtors.getLength() - 1; i >= 0; i--)
	{
		bool bParameterArray = false;
		::System::Type ^ typeAny = ::uno::Any::typeid;
		const Reference<reflection::XServiceConstructorDescription> & ctorDes =
			seqCtors[i];
		//obtain the parameter types
		Sequence<Reference<reflection::XParameter> > seqParams =
			ctorDes->getParameters();
		Reference<reflection::XParameter> const * arXParams = seqParams.getConstArray();
		sal_Int32 cParams = seqParams.getLength();
		cli::array< ::System::Type ^ > ^ arTypeParameters = gcnew cli::array< ::System::Type ^ >( cParams + 1 );
		arTypeParameters[0] = get_type("unoidl.com.sun.star.uno.XComponentContext", true);
		for (int iparam = 0; iparam != cParams; iparam++)
		{
			if (arXParams[iparam]->isRestParameter())
				arTypeParameters[iparam + 1] = cli::array< ::uno::Any >::typeid;
			else
				arTypeParameters[iparam + 1] = get_type(arXParams[iparam]->getType());
		}
		//The array arTypeParameters can contain:
		//System.Type and uno.PolymorphicType.
		//Passing PolymorphicType to MethodBuilder.DefineMethod will cause a problem.
		//The exception will read something like no on information for parameter # d
		//Maybe we need no override another Type method in PolymorphicType ...
		//Until we have figured this out, we will create another array of System.Type which
		//we pass on to DefineMethod.
		cli::array< ::System::Type ^ > ^ arParamTypes = gcnew cli::array< ::System::Type ^ >( cParams + 1 );
//		arParamTypes[0] = get_type("unoidl.com.sun.star.uno.XComponentContext", true);
		for (int i = 0; i < cParams + 1; i++)
		{
			::uno::PolymorphicType ^ pT = dynamic_cast< ::uno::PolymorphicType ^ >(arTypeParameters[i]);
			if (pT)
				arParamTypes[i] = pT->OriginalType;
			else
				arParamTypes[i] = arTypeParameters[i];
		}
		//define method
		System::String ^ ctorName;
		if (ctorDes->isDefaultConstructor())
			ctorName = gcnew ::System::String("create");
		else
			ctorName = ustring_to_String(ctorDes->getName());
		Emit::MethodBuilder ^ method_builder = type_builder->DefineMethod(
			ctorName,
			static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig |
										  MethodAttributes::Static),
			retType,
//			arTypeParameters);
			arParamTypes);

		//define UNO exception attribute (exceptions)--------------------------------------
		Emit::CustomAttributeBuilder ^ attrBuilder = get_service_exception_attribute(ctorDes);
		if (attrBuilder != nullptr)
			method_builder->SetCustomAttribute(attrBuilder);

		//-------------------------------------------------------------
		//define parameter attributes (paramarray), names etc.
		//The first parameter is the XComponentContext, which cannot be obtained
		//from reflection.
		//The context is not part of the idl description
		method_builder->DefineParameter(
			1, ParameterAttributes::In, "the_context");

		cli::array< Emit::ParameterBuilder ^ > ^ arParameterBuilder =
			gcnew cli::array< Emit::ParameterBuilder ^ >( cParams );
		for (int iparam = 0; iparam != cParams; iparam++)
		{
			Reference<reflection::XParameter> const & aParam = arXParams[iparam];
			::System::String ^ sParamName = ustring_to_String(aParam->getName());

			arParameterBuilder[iparam] = method_builder->DefineParameter(
				iparam + 2, ParameterAttributes::In, sParamName);

			if (aParam->isRestParameter())
			{
				bParameterArray = true;
				//set the ParameterArrayAttribute
				::System::Reflection::ConstructorInfo ^ ctor_info =
					System::ParamArrayAttribute::typeid->GetConstructor(
						gcnew cli::array< ::System::Type ^ >( 0 ));
				Emit::CustomAttributeBuilder ^ attr_builder =
					gcnew Emit::CustomAttributeBuilder(ctor_info, gcnew cli::array< ::System::Object ^ >( 0 ));
				arParameterBuilder[iparam]->SetCustomAttribute(attr_builder);
				break;
			}
		}

		Emit::ILGenerator ^ ilGen = method_builder->GetILGenerator();

		//Define locals ---------------------------------
		//XMultiComponentFactory
		Emit::LocalBuilder ^ local_factory =
			ilGen->DeclareLocal(
				get_type("unoidl.com.sun.star.lang.XMultiComponentFactory", true));

		//The return type
		Emit::LocalBuilder ^ local_return_val =
			ilGen->DeclareLocal(retType);

		//Obtain the XMultiComponentFactory and throw an exception if we do not get one
		ilGen->Emit(Emit::OpCodes::Ldarg_0);

		::System::Reflection::MethodInfo ^ methodGetServiceManager = get_type(
			"unoidl.com.sun.star.uno.XComponentContext", true)
				->GetMethod("getServiceManager");
		ilGen->Emit(Emit::OpCodes::Callvirt, methodGetServiceManager);
		ilGen->Emit(Emit::OpCodes::Stloc, local_factory);
		ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
		Emit::Label label1 = ilGen->DefineLabel();
		ilGen->Emit(Emit::OpCodes::Brtrue, label1);
		//The string for the exception
		::System::Text::StringBuilder ^ strbuilder = gcnew ::System::Text::StringBuilder(256);
		strbuilder->Append("The service ");
		strbuilder->Append(to_cts_name(xServiceType->getName()));
		strbuilder->Append(" could not be created. The context failed to supply the service manager.");

		ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());
		ilGen->Emit(Emit::OpCodes::Ldarg_0);
		ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
		ilGen->Emit(Emit::OpCodes::Throw);
		ilGen->MarkLabel(label1);

		//We create a try/ catch around the createInstanceWithContext, etc. functions
		//There are 3 cases
		//1. function do not specify exceptions. Then RuntimeExceptions are retrhown and other
		//   exceptions produce a DeploymentException.
		//2. function specify Exception. Then all exceptions fly through
		//3. function specifies exceptions but no Exception. Then these are rethrown
		//   and other exceptions, except RuntimeException, produce a deployment exception.
		//In case there are no parameters we call
		//XMultiComponentFactory.createInstanceWithContext

		::System::Collections::ArrayList ^ arExceptionTypes =
			  get_service_ctor_method_exceptions_reduced(ctorDes->getExceptions());
		if (arExceptionTypes->Contains(
				type_uno_exception) == false)
		{
			ilGen->BeginExceptionBlock();
		}
		if (cParams == 0)
		{
			ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
			ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
			ilGen->Emit(Emit::OpCodes::Ldarg_0);

			::System::Reflection::MethodInfo ^ methodCreate =
					local_factory->LocalType->GetMethod("createInstanceWithContext");
			ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
		}
		else if(bParameterArray)
		{
			//Service constructor with parameter array
			ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
			ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
			ilGen->Emit(Emit::OpCodes::Ldarg_1);
			ilGen->Emit(Emit::OpCodes::Ldarg_0);
			::System::Reflection::MethodInfo ^ methodCreate =
					local_factory->LocalType->GetMethod("createInstanceWithArgumentsAndContext");
			ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
		}
		else
		{
			// Any param1, Any param2, etc.
			// For each parameter,except the component context, and parameter array
			// and Any is created.
			cli::array< Emit::LocalBuilder ^ > ^ arLocalAny = gcnew cli::array< Emit::LocalBuilder ^ >( cParams );

			for (int iParam = 0; iParam < cParams; iParam ++)
			{
				arLocalAny[iParam] = ilGen->DeclareLocal(typeAny);
			}

			//Any[]. This array is filled with the created Anys which contain the parameters
			//and the values contained in the parameter array
			Emit::LocalBuilder ^ local_anyParams =
				ilGen->DeclareLocal(cli::array< ::uno::Any >::typeid);

			//Create the Any for every argument, except for the parameter array
			//arLocalAny contains the LocalBuilder for all these parameters.
			//we call the ctor Any(Type, Object)
			//If the parameter is an Any then the Any is created with Any(param.Type, param.Value);
			cli::array< ::System::Type ^ > ^ arTypesCtorAny = {::System::Type::typeid,
													::System::Object::typeid};
			::System::Reflection::ConstructorInfo ^ ctorAny =
				typeAny->GetConstructor( arTypesCtorAny);
			::System::Reflection::MethodInfo ^ methodAnyGetType =
				typeAny->GetProperty("Type")->GetGetMethod();
			::System::Reflection::MethodInfo ^ methodAnyGetValue =
				typeAny->GetProperty("Value")->GetGetMethod();
			for (int i = 0; i < arLocalAny->Length; i ++)
			{
				//check if the parameter is a polymorphic struct
				::uno::PolymorphicType ^polyType = dynamic_cast< ::uno::PolymorphicType ^ >(arTypeParameters[i+1]);
				//arTypeParameters[i+1] = polyType->OriginalType;
				if (polyType)
				{
					//It is a polymorphic struct
					//Load the uninitialized local Any on which we will call the ctor
					ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
					// Call PolymorphicType PolymorphicType::GetType(Type t, String polyName)
					// Prepare the first parameter
					ilGen->Emit(Emit::OpCodes::Ldtoken, polyType->OriginalType);
					cli::array< ::System::Type ^ > ^ arTypeParams = {::System::RuntimeTypeHandle::typeid};
					ilGen->Emit(Emit::OpCodes::Call,
								::System::Type::typeid->GetMethod(
									"GetTypeFromHandle", arTypeParams));
					// Prepare the second parameter
					ilGen->Emit(Emit::OpCodes::Ldstr, polyType->PolymorphicName);
					// Make the actual call
					cli::array< ::System::Type ^ > ^ arTypeParam_GetType = {
						::System::Type::typeid, ::System::String::typeid };
					ilGen->Emit(Emit::OpCodes::Call,
					::uno::PolymorphicType::typeid->GetMethod(gcnew System::String("GetType"),
						arTypeParam_GetType));

					//Stack is: localAny, PolymorphicType
					//Call Any::Any(Type, Object)
					//Prepare the second parameter for the any ctor
					ilGen->Emit(Emit::OpCodes::Ldarg, i + 1);
					// if the parameter is a value type then we need to box it, because
					// the Any ctor takes an Object
					if (arTypeParameters[i+1]->IsValueType)
						ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]);
					ilGen->Emit(Emit::OpCodes::Call, ctorAny);
				}
				else if (arTypeParameters[i+1] == typeAny)
				{
					//Create the call new Any(param.Type,param,Value)
					//Stack must be Any,Type,Value
					//First load the Any which is to be constructed
					ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
					//Load the Type, which is obtained by calling param.Type
					ilGen->Emit(Emit::OpCodes::Ldarga, i + 1);
					ilGen->Emit(Emit::OpCodes::Call, methodAnyGetType);
					//Load the Value, which is obtained by calling param.Value
					ilGen->Emit(Emit::OpCodes::Ldarga, i + 1);
					ilGen->Emit(Emit::OpCodes::Call, methodAnyGetValue);
					//Call the Any ctor.
					ilGen->Emit(Emit::OpCodes::Call, ctorAny);
				}
				else
				{
					ilGen->Emit(Emit::OpCodes::Ldloca, arLocalAny[i]);
					ilGen->Emit(Emit::OpCodes::Ldtoken, arTypeParameters[i+1]);

					cli::array< ::System::Type ^ > ^ arTypeParams = {::System::RuntimeTypeHandle::typeid};
					ilGen->Emit(Emit::OpCodes::Call,
								::System::Type::typeid->GetMethod(
									"GetTypeFromHandle", arTypeParams));
					ilGen->Emit(Emit::OpCodes::Ldarg, i + 1);
					// if the parameter is a value type then we need to box it, because
					// the Any ctor takes an Object
					if (arTypeParameters[i+1]->IsValueType)
						ilGen->Emit(Emit::OpCodes::Box, arTypeParameters[i+1]);
					ilGen->Emit(Emit::OpCodes::Call, ctorAny);
				}
			}

			//Create the Any[] that is passed to the
			//createInstanceWithContext[AndArguments] function
			ilGen->Emit(Emit::OpCodes::Ldc_I4, arLocalAny->Length);
			ilGen->Emit(Emit::OpCodes::Newarr, typeAny);
			ilGen->Emit(Emit::OpCodes::Stloc, local_anyParams);

			//Assign all Anys created from the parameters
			//array to the Any[]
			for (int i = 0; i < arLocalAny->Length; i++)
			{
				ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams);
				ilGen->Emit(Emit::OpCodes::Ldc_I4, i);
				ilGen->Emit(Emit::OpCodes::Ldelema, typeAny);
				ilGen->Emit(Emit::OpCodes::Ldloc, arLocalAny[i]);
				ilGen->Emit(Emit::OpCodes::Stobj, typeAny);
			}
			// call createInstanceWithContextAndArguments
			ilGen->Emit(Emit::OpCodes::Ldloc, local_factory);
			ilGen->Emit(Emit::OpCodes::Ldstr, ustring_to_String(xServiceType->getName()));
			ilGen->Emit(Emit::OpCodes::Ldloc, local_anyParams);
			ilGen->Emit(Emit::OpCodes::Ldarg_0);
			::System::Reflection::MethodInfo ^ methodCreate =
					local_factory->LocalType->GetMethod("createInstanceWithArgumentsAndContext");
			ilGen->Emit(Emit::OpCodes::Callvirt, methodCreate);
		}
		//cast the object returned by the functions createInstanceWithContext or
		//createInstanceWithArgumentsAndContext to the interface type
		ilGen->Emit(Emit::OpCodes::Castclass, retType);
		ilGen->Emit(Emit::OpCodes::Stloc, local_return_val);

		//catch exceptions thrown by createInstanceWithArgumentsAndContext and createInstanceWithContext
		if (arExceptionTypes->Contains(type_uno_exception) == false)
		{
			// catch (unoidl.com.sun.star.uno.RuntimeException) {throw;}
			ilGen->BeginCatchBlock(get_type("unoidl.com.sun.star.uno.RuntimeException", true));
			ilGen->Emit(Emit::OpCodes::Pop);
			ilGen->Emit(Emit::OpCodes::Rethrow);

			//catch and rethrow all other defined Exceptions
			for (int i = 0; i < arExceptionTypes->Count; i++)
			{
				::System::Type ^ excType = safe_cast< ::System::Type ^ >(
					arExceptionTypes[ i ]);
				if (excType->IsInstanceOfType(
						get_type("unoidl.com.sun.star.uno.RuntimeException", true)))
				{// we have a catch for RuntimeException already defined
					continue;
				}

				//catch Exception and rethrow
				ilGen->BeginCatchBlock(excType);
				ilGen->Emit(Emit::OpCodes::Pop);
				ilGen->Emit(Emit::OpCodes::Rethrow);
			}
			//catch (unoidl.com.sun.star.uno.Exception) {throw DeploymentException...}
			ilGen->BeginCatchBlock(type_uno_exception);

			//Define the local variable that keeps the exception
			 Emit::LocalBuilder ^ local_exception = ilGen->DeclareLocal(
				 type_uno_exception);

			 //Store the exception
			 ilGen->Emit(Emit::OpCodes::Stloc, local_exception);

			//prepare the construction of the exception
			 strbuilder = gcnew ::System::Text::StringBuilder(256);
			 strbuilder->Append("The context (com.sun.star.uno.XComponentContext) failed to supply the service ");
			 strbuilder->Append(to_cts_name(xServiceType->getName()));
			 strbuilder->Append(": ");

			 ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());

			//add to the string the Exception.Message
			ilGen->Emit(Emit::OpCodes::Ldloc, local_exception);
			ilGen->Emit(Emit::OpCodes::Callvirt,
						type_uno_exception->GetProperty("Message")->GetGetMethod());
			cli::array< ::System::Type ^ > ^ arConcatParams = {System::String::typeid,
												  System::String::typeid};
			ilGen->Emit(Emit::OpCodes::Call,
						System::String::typeid->GetMethod("Concat", arConcatParams));
			//load context argument
			ilGen->Emit(Emit::OpCodes::Ldarg_0);
			ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
			ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc);

			ilGen->EndExceptionBlock();
		}


		//Check if the service instance was created and throw a exception if not.
		Emit::Label label_service_created = ilGen->DefineLabel();
		ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val);
		ilGen->Emit(Emit::OpCodes::Brtrue_S, label_service_created);

		strbuilder = gcnew ::System::Text::StringBuilder(256);
		strbuilder->Append("The context (com.sun.star.uno.XComponentContext) failed to supply the service ");
		strbuilder->Append(to_cts_name(xServiceType->getName()));
		strbuilder->Append(".");
		ilGen->Emit(Emit::OpCodes::Ldstr, strbuilder->ToString());
		ilGen->Emit(Emit::OpCodes::Ldarg_0);
		ilGen->Emit(Emit::OpCodes::Newobj, ctorDeploymentException);
		ilGen->Emit(Emit::OpCodes::Throw);//Exception(typeDeploymentExc);

		ilGen->MarkLabel(label_service_created);
		ilGen->Emit(Emit::OpCodes::Ldloc, local_return_val);
		ilGen->Emit(Emit::OpCodes::Ret);

	}
	// remove from incomplete types map
	::System::String ^ cts_name = type_builder->FullName;
	m_incomplete_services->Remove( cts_name );
	xServiceType->release();
	if (g_verbose)
	{
		::System::Console::WriteLine(
			"> emitting service type {0}", cts_name );
	}
	return type_builder->CreateType();
}


Emit::CustomAttributeBuilder ^ TypeEmitter::get_service_exception_attribute(
	const Reference<reflection::XServiceConstructorDescription> & ctorDes )
{
	return get_exception_attribute(ctorDes->getExceptions());
}

Emit::CustomAttributeBuilder ^ TypeEmitter::get_iface_method_exception_attribute(
	const Reference< reflection::XInterfaceMethodTypeDescription >& xMethod )
{

	const Sequence<Reference<reflection::XTypeDescription> > seqTD = xMethod->getExceptions();
	int len = seqTD.getLength();
	Sequence<Reference<reflection::XCompoundTypeDescription> > seqCTD(len);
	Reference<reflection::XCompoundTypeDescription> * arCTD = seqCTD.getArray();
	for (int i = 0; i < len; i++)
		arCTD[i] = Reference<reflection::XCompoundTypeDescription>(seqTD[i], UNO_QUERY_THROW);
	return get_exception_attribute(seqCTD);
}

Emit::CustomAttributeBuilder ^ TypeEmitter::get_exception_attribute(

	const Sequence<Reference< reflection::XCompoundTypeDescription > >& seq_exceptionsTd )
{
	Emit::CustomAttributeBuilder ^ attr_builder = nullptr;

	Reference< reflection::XCompoundTypeDescription > const * exceptions =
		seq_exceptionsTd.getConstArray();

	cli::array< ::System::Type ^ > ^ arTypesCtor = {::System::Type::GetType("System.Type[]")};
	ConstructorInfo ^ ctor_ExceptionAttribute =
		::uno::ExceptionAttribute::typeid->GetConstructor(arTypesCtor);

	sal_Int32 exc_length = seq_exceptionsTd.getLength();
	if (exc_length != 0) // opt
	{
		cli::array< ::System::Type ^ > ^ exception_types =
			  gcnew cli::array< ::System::Type ^ >( exc_length );
		for ( sal_Int32 exc_pos = 0; exc_pos < exc_length; ++exc_pos )
		{
			Reference< reflection::XCompoundTypeDescription > const & xExc =
				exceptions[ exc_pos ];
			exception_types[ exc_pos ] = get_type( xExc );
		}
		cli::array< ::System::Object ^ > ^ args = {exception_types};
		attr_builder = gcnew Emit::CustomAttributeBuilder(
			ctor_ExceptionAttribute, args );
	}
	return attr_builder;
}


::System::Type ^ TypeEmitter::complete_singleton_type(singleton_entry ^ entry)
{
	Emit::TypeBuilder ^ type_builder = entry->m_type_builder;
	reflection::XSingletonTypeDescription2 * xSingletonType = entry->m_xType;
	::System::String ^ sSingletonName = to_cts_name(xSingletonType->getName());

	//Create the private default constructor
	Emit::ConstructorBuilder ^ ctor_builder =
		type_builder->DefineConstructor(
			static_cast<MethodAttributes>(MethodAttributes::Private |
										  MethodAttributes::HideBySig |
										  MethodAttributes::SpecialName |
										  MethodAttributes::RTSpecialName),
			CallingConventions::Standard, nullptr);

	Emit::ILGenerator ^ ilGen = ctor_builder->GetILGenerator();
	ilGen->Emit( Emit::OpCodes::Ldarg_0 ); // push this
	ilGen->Emit(
			Emit::OpCodes::Call,
			type_builder->BaseType->GetConstructor(gcnew cli::array< ::System::Type ^ >( 0 )));
	ilGen->Emit( Emit::OpCodes::Ret );


	//obtain the interface which makes up this service, it is the return
	//type of the constructor functions
	Reference<reflection::XInterfaceTypeDescription2> xIfaceType(
		xSingletonType->getInterface(), UNO_QUERY);
	if (xIfaceType.is () == sal_False)
		xIfaceType = resolveInterfaceTypedef(xSingletonType->getInterface());
	System::Type ^ retType = get_type(xIfaceType);

	//define method
	cli::array< ::System::Type ^ > ^ arTypeParameters = {get_type("unoidl.com.sun.star.uno.XComponentContext", true)};
	Emit::MethodBuilder ^ method_builder = type_builder->DefineMethod(
		gcnew System::String("get"),
		static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::HideBySig |
									  MethodAttributes::Static),
		retType,
		arTypeParameters);


//		 method_builder->SetCustomAttribute(get_service_ctor_method_attribute(ctorDes));

	//The first parameter is the XComponentContext, which cannot be obtained
	//from reflection.
	//The context is not part of the idl description
	method_builder->DefineParameter(1, ParameterAttributes::In, "the_context");


	ilGen = method_builder->GetILGenerator();
	//Define locals ---------------------------------
	// Any, returned by XComponentContext.getValueByName
	Emit::LocalBuilder ^ local_any =
		ilGen->DeclareLocal(::uno::Any::typeid);

	//Call XContext::getValueByName
	ilGen->Emit(Emit::OpCodes::Ldarg_0);
	// build the singleton name : /singleton/unoidl.com.sun.star.XXX
	::System::Text::StringBuilder ^ sBuilder =
		  gcnew ::System::Text::StringBuilder("/singletons/");
	sBuilder->Append(sSingletonName);
	ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString());

	::System::Reflection::MethodInfo ^ methodGetValueByName =
		  get_type("unoidl.com.sun.star.uno.XComponentContext", true)->GetMethod("getValueByName");
	ilGen->Emit(Emit::OpCodes::Callvirt, methodGetValueByName);
	ilGen->Emit(Emit::OpCodes::Stloc_0);

	//Contains the returned Any a value?
	ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any);
	::System::Reflection::MethodInfo ^ methodHasValue =
		  ::uno::Any::typeid->GetMethod("hasValue");
	ilGen->Emit(Emit::OpCodes::Call, methodHasValue);

	//If not, then throw an DeploymentException
	Emit::Label label_singleton_exists = ilGen->DefineLabel();
	ilGen->Emit(Emit::OpCodes::Brtrue_S, label_singleton_exists);
	sBuilder = gcnew ::System::Text::StringBuilder(
		"Component context fails to supply singleton ");
	sBuilder->Append(sSingletonName);
	sBuilder->Append(" of type ");
	sBuilder->Append(retType->FullName);
	sBuilder->Append(".");
	ilGen->Emit(Emit::OpCodes::Ldstr, sBuilder->ToString());
	ilGen->Emit(Emit::OpCodes::Ldarg_0);
	cli::array< ::System::Type ^ > ^ arTypesCtorDeploymentException = {
		::System::String::typeid, ::System::Object::typeid};
	ilGen->Emit(Emit::OpCodes::Newobj,
				get_type("unoidl.com.sun.star.uno.DeploymentException",true)
				->GetConstructor(arTypesCtorDeploymentException));
	ilGen->Emit(Emit::OpCodes::Throw);
	ilGen->MarkLabel(label_singleton_exists);

	//Cast the singleton contained in the Any to the expected interface and return it.
	ilGen->Emit(Emit::OpCodes::Ldloca_S, local_any);
	ilGen->Emit(Emit::OpCodes::Call, ::uno::Any::typeid->GetProperty("Value")->GetGetMethod());
	ilGen->Emit(Emit::OpCodes::Castclass, retType);
	ilGen->Emit(Emit::OpCodes::Ret);

	// remove from incomplete types map
	::System::String ^ cts_name = type_builder->FullName;
	m_incomplete_singletons->Remove( cts_name );
	xSingletonType->release();
	if (g_verbose)
	{
		::System::Console::WriteLine(
			"> emitting singleton type {0}", cts_name );
	}
	return type_builder->CreateType();
}


//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_type(
	Reference< reflection::XTypeDescription > const & xType )
{
	switch (xType->getTypeClass())
	{
	case TypeClass_VOID:
		return ::System::Void::typeid;
	case TypeClass_CHAR:
		return ::System::Char::typeid;
	case TypeClass_BOOLEAN:
		return ::System::Boolean::typeid;
	case TypeClass_BYTE:
		return ::System::Byte::typeid;
	case TypeClass_SHORT:
		return ::System::Int16::typeid;
	case TypeClass_UNSIGNED_SHORT:
		return ::System::UInt16::typeid;
	case TypeClass_LONG:
		return ::System::Int32::typeid;
	case TypeClass_UNSIGNED_LONG:
		return ::System::UInt32::typeid;
	case TypeClass_HYPER:
		return ::System::Int64::typeid;
	case TypeClass_UNSIGNED_HYPER:
		return ::System::UInt64::typeid;
	case TypeClass_FLOAT:
		return ::System::Single::typeid;
	case TypeClass_DOUBLE:
		return ::System::Double::typeid;
	case TypeClass_STRING:
		return ::System::String::typeid;
	case TypeClass_TYPE:
		return ::System::Type::typeid;
	case TypeClass_ANY:
		return ::uno::Any::typeid;
	case TypeClass_ENUM:
		return get_type( Reference< reflection::XEnumTypeDescription >(
							 xType, UNO_QUERY_THROW ) );
	case TypeClass_TYPEDEF:
		// unwind typedefs
		return get_type(
			Reference< reflection::XIndirectTypeDescription >(
				xType, UNO_QUERY_THROW )->getReferencedType() );
	case TypeClass_STRUCT:
	case TypeClass_EXCEPTION:
		return get_type(
			Reference< reflection::XCompoundTypeDescription >(
				xType, UNO_QUERY_THROW ) );
	case TypeClass_SEQUENCE:
	{
		::System::Type ^ element_type = get_type(
			Reference< reflection::XIndirectTypeDescription >(
				xType, UNO_QUERY_THROW )->getReferencedType() );
		::System::Type ^ retType = get_type(
			::System::String::Concat(
				element_type->FullName, "[]" ), true );

		::uno::PolymorphicType ^ pt = dynamic_cast< ::uno::PolymorphicType ^ >(element_type);
		if (pt)
		{
			::System::String ^ sName = ::System::String::Concat(pt->PolymorphicName, "[]");
			retType = ::uno::PolymorphicType::GetType(retType, sName);
		}
		return retType;
	}
	case TypeClass_INTERFACE:
		return get_type(
			Reference< reflection::XInterfaceTypeDescription2 >(
				xType, UNO_QUERY_THROW ) );
	case TypeClass_CONSTANT:
		return get_type(
			Reference< reflection::XConstantTypeDescription >(
				xType, UNO_QUERY_THROW ) );
	case TypeClass_CONSTANTS:
		return get_type(
			Reference< reflection::XConstantsTypeDescription >(
				xType, UNO_QUERY_THROW ) );
	case TypeClass_SERVICE:
		return get_type(
			Reference< reflection::XServiceTypeDescription2 >(
				xType, UNO_QUERY_THROW) );
	case TypeClass_SINGLETON:
		return get_type(
			Reference< reflection::XSingletonTypeDescription2 >(
				xType, UNO_QUERY_THROW) );
	case TypeClass_MODULE:
		// ignore these
		return nullptr;
	default:
		throw RuntimeException(
			OUSTR("unexpected type ") + xType->getName(),
			Reference< XInterface >() );
	}
}

//______________________________________________________________________________
::System::Type ^ TypeEmitter::get_complete_struct( ::System::String ^ sName)
{
	struct_entry ^ pStruct = safe_cast< struct_entry ^ >(
		m_incomplete_structs[ sName ]);
	if (pStruct)
	{
		complete_struct_type(pStruct);
	}
	//get_type will ask the module builder for the type or otherwise all known assemblies.
	return get_type(sName, true);
}
TypeEmitter::~TypeEmitter()
{
	while (true)
	{
		::System::Collections::IDictionaryEnumerator ^ enumerator =
			  m_incomplete_ifaces->GetEnumerator();
		if (! enumerator->MoveNext())
			break;
		complete_iface_type(
			safe_cast< iface_entry ^ >( enumerator->Value ) );
	}

	while (true)
	{
		::System::Collections::IDictionaryEnumerator ^ enumerator =
			  m_incomplete_structs->GetEnumerator();
		if (! enumerator->MoveNext())
			break;
		complete_struct_type(
			safe_cast< struct_entry ^ >( enumerator->Value ) );
	}


	while (true)
	{
		::System::Collections::IDictionaryEnumerator ^ enumerator =
			  m_incomplete_services->GetEnumerator();
		if (! enumerator->MoveNext())
			break;
		complete_service_type(
			safe_cast< service_entry ^ >( enumerator->Value ) );
	}

	while (true)
	{
		::System::Collections::IDictionaryEnumerator ^ enumerator =
			  m_incomplete_singletons->GetEnumerator();
		if (! enumerator->MoveNext())
			break;
		complete_singleton_type(
			safe_cast< singleton_entry ^ >( enumerator->Value ) );
	}
}
//______________________________________________________________________________
TypeEmitter::TypeEmitter(
	::System::Reflection::Emit::ModuleBuilder ^ module_builder,
	cli::array< ::System::Reflection::Assembly ^ > ^ extra_assemblies )
	: m_module_builder( module_builder ),
	  m_extra_assemblies( extra_assemblies ),
	  m_method_info_Type_GetTypeFromHandle( nullptr ),
	  m_type_Exception( nullptr ),
	  m_type_RuntimeException( nullptr ),
	  m_incomplete_ifaces( gcnew ::System::Collections::Hashtable() ),
	  m_resolving( gcnew ::System::Collections::Hashtable() ),
	  m_incomplete_structs( gcnew ::System::Collections::Hashtable() ),
	  m_incomplete_services(gcnew ::System::Collections::Hashtable() ),
	  m_incomplete_singletons(gcnew ::System::Collections::Hashtable() ),
	  m_generated_structs( gcnew ::System::Collections::Hashtable() )
{
	cli::array< ::System::Type ^ > ^ param_types = gcnew cli::array< ::System::Type ^ >( 1 );
	param_types[ 0 ] = ::System::RuntimeTypeHandle::typeid;
	m_method_info_Type_GetTypeFromHandle =
		::System::Type::typeid
		  ->GetMethod( "GetTypeFromHandle", param_types );
}

::System::Collections::ArrayList ^ TypeEmitter::get_service_ctor_method_exceptions_reduced(
	const Sequence<Reference<reflection::XCompoundTypeDescription> > & seqExceptionsTd)
{
	if (seqExceptionsTd.getLength() == 0)
		return gcnew ::System::Collections::ArrayList();

	::System::Collections::ArrayList ^ arTypes = gcnew ::System::Collections::ArrayList();
	for (int i = 0; i < seqExceptionsTd.getLength(); i++)
		arTypes->Add(get_type(to_cts_name(seqExceptionsTd[i]->getName()), true));

	int start = 0;
	while (true)
	{
		bool bRemove = false;
		for (int i = start; i < arTypes->Count; i++)
		{
			::System::Type ^ t = safe_cast< ::System::Type ^ >(arTypes[ i ]);
			for (int j = 0; j < arTypes->Count; j++)
			{
				if (t->IsSubclassOf(safe_cast< ::System::Type ^ >(arTypes[ j ])))
				{
					arTypes->RemoveAt(i);
					bRemove = true;
					break;
				}
			}
			if (bRemove)
				break;
			start++;
		}

		if (bRemove == false)
			break;
	}
	return arTypes;
}


css::uno::Reference< css::reflection::XInterfaceTypeDescription2 >
resolveInterfaceTypedef(
	const css::uno::Reference<css::reflection::XTypeDescription>& type)
{
	Reference<reflection::XInterfaceTypeDescription2>
		xIfaceTd(type, UNO_QUERY);

	if (xIfaceTd.is())
		return xIfaceTd;

	Reference<reflection::XIndirectTypeDescription> xIndTd(
		type, UNO_QUERY);
	if (xIndTd.is() == sal_False)
		throw css::uno::Exception(
			OUSTR("resolveInterfaceTypedef was called with an invalid argument"), 0);

	return resolveInterfaceTypedef(xIndTd->getReferencedType());
}


}
