// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/CORBA.h>
#include <Types.h>
#include <Util.h>
#include <GenUtil.h>
#include <GenCPP.h>

// ----------------------------------------------------------------------
// Generate code for the header file, general part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusH(CORBA_Container_ptr container,
			       IdlPrettyPrint& out)
{
    //
    // Get scope and prefix
    // (prefix needed if alternative module mapping is used)
    //
    CORBA_String_var scope;
    CORBA_String_var pre;
    getScopeAndPrefix(container, scope.out(), pre.out());

    //
    // Get container contents descriptions
    //
    CORBA_Container::DescriptionSeq_var seq =
	container -> describe_contents(CORBA_dk_all, true, -1);

    // ------------------------------------------------------------
    // Pass 1: Declare interface classes
    // ------------------------------------------------------------

    CORBA_ULong i, j;

    for(i = 0 ; i < seq -> length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Interface)
	{
	    //
	    // Interface
	    //
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    out.sep();
	    out << "\nclass " << pre << name << ';';
	    out << "\ntypedef " << pre << name << "* "
		<< pre << name << "_ptr;";
	    out << "\ntypedef " << pre << name << "* "
		<< pre << name << "Ref;";
	    out << "\nvoid OBDuplicate(" << pre << name << "_ptr);";
	    out << "\nvoid OBRelease(" << pre << name << "_ptr);";
	    out << "\ntypedef OBObjVar< " << pre << name << " > "
		<< pre << name << "_var;";
	}
    }

    // ------------------------------------------------------------
    // Pass 2: Do the rest
    // ------------------------------------------------------------

    for(i = 0 ; i < seq -> length() ; i++)
    {
	//
	// Get container
	//
	CORBA_Container_var cont =
	    CORBA_Container::_narrow(seq[i].contained_object);

	switch(seq[i].kind)
	{
	case CORBA_dk_Constant:
	{
	    //
	    // Constant
	    //
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);
	    
	    out.sep();
	    out << '\n';

	    if(strlen(dllImport_) > 0)
		out << dllImport_ << ' ';

	    if(container -> def_kind() != CORBA_dk_Interface)
		out << "extern ";
	    else
		out << "static ";

	    CORBA_String_var preName = pre;
	    preName += name;

	    CORBA_String_var s = getTypeString(scope, desc -> type,
					       GetTypeConst, false, preName);
	    out << s << ';';

	    break;
	}

	case CORBA_dk_Module:
	{
	    //
	    // Module
	    //
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    // Don't add this here!!!
	    // if(!check(desc -> id))
	    //     continue;

 	    comment(desc -> id, out);

	    out.sep();

	    assert(!CORBA_is_nil(cont));
	    genCPlusPlusH(cont, out);

	    break;
	}

	case CORBA_dk_Interface:
	{
	    //
	    // Interface
	    //
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);
	    
	    out.sep();
	    out << "\nclass " << pre << name << " : ";

	    unsigned int indent = out.getIndent();
	    out.setIndent(out.getPos());

	    if(desc -> base_interfaces.length() > 0)
	    {
		for(j = 0 ; j < desc -> base_interfaces.length() ; j++)
		{
		    const char* id = desc -> base_interfaces[j];
		    CORBA_ScopedName_var absolute = getAbsolute(id);

		    if(j > 0)
			out << ",\n";

		    if(!noVirtual_)
			out << "virtual ";

		    out << "public " << absolute;
		}
	    }
	    else
	    {
		if(!noVirtual_)
		    out << "virtual ";

		out << "public CORBA_Object";
	    }

	    out.setIndent(indent);

	    out.start();

	    out << '\n' << pre << name << "(const " << pre << name << "&);";
	    out << "\nvoid operator=(const " << pre << name << "&);";

	    out.sep();
	    out.dec();
	    if(!local_)
		out << "\nprotected:";
	    else
		out << "\npublic:";
	    out.inc();
	    out.sep();
	    out << '\n' << pre << name << "() { }";
	    if(!local_)
	    {
		out.sep();
		out.dec();
		out << "\npublic:";
		out.inc();
	    }

	    out.sep();
	    out << "\nstatic inline " << pre << name << "_ptr\n_duplicate("
		<< pre << name << "_ptr p)";
	    out.start();
	    out << "\nif(p)";
	    out.inc();
	    out << "\np -> _OB_incRef();";
	    out.dec();
	    out << "\nreturn p;";
	    out.end();

	    out.sep();
	    out << "\nstatic inline " << pre << name << "_ptr\n_nil()";
	    out.start();
	    out << "\nreturn 0;";
	    out.end();

	    out.sep();
	    // out << "\nvirtual CORBA_Boolean _is_a(const char*);";
	    out << "\nstatic " << pre << name
		<< "_ptr _narrow(CORBA_Object_ptr);";
	    out << "\nvirtual void* _OB_narrowHelp(const char*) const;";
	    out << "\nvirtual const char* _OB_typeId() const;";

	    if(!local_)
	    {
		out.sep();
		out << "\nfriend void OBUnmarshal("
		    << pre << name << "_ptr&, const CORBA_Octet*&, bool);";
	    }

	    if(!noTC_)
	    {
		out.sep();
		out << "\nfriend CORBA_Boolean operator>>=(const CORBA_Any&, "
		    << pre << name << "_ptr&);";
	    }

	    assert(!CORBA_is_nil(cont));
	    genCPlusPlusH(cont, out);

	    out.end();
	    out << ';';

	    if(!noTC_)
	    {
		out.sep();

		out << '\n';
		
		if(strlen(dllImport_) > 0)
		    out << dllImport_ << ' ';

		if(container -> def_kind() != CORBA_dk_Interface)
		    out << "extern OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
		else
		    out << "static OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
	    }

	    break;
	}

	case CORBA_dk_Alias:
	{
	    //
	    // Alias
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    CORBA_TypeCode_var origType = desc -> type -> content_type();
	    CORBA_TypeCode_var origOrigType = OBGetOrigType(origType);

	    static const char* extPtr = "_ptr";
	    static const char* extRef = "Ref";
	    static const char* extVar = "_var";
	    static const char* extSlice = "_slice";
	    static const char* extForAny = "_forany";

	    CORBA_String_var normPtr = pre;
	    normPtr += name;

	    CORBA_String_var namePtr = pre;
	    namePtr += name;
	    namePtr += extPtr;

	    CORBA_String_var nameRef = pre;
	    nameRef += name;
	    nameRef += extRef;

	    CORBA_String_var nameVar = pre;
	    nameVar += name;
	    nameVar += extVar;

	    CORBA_String_var nameSlice = pre;
	    nameSlice += name;
	    nameSlice += extSlice;

	    CORBA_String_var nameForAny = pre;
	    nameForAny += name;
	    nameForAny += extForAny;

	    CORBA_String_var norm = getTypeString(scope, origType,
						  GetTypeNormal,
						  false, normPtr);
	    CORBA_String_var ptr = getTypeString(scope, origType,
						 GetTypePtr,
						 false, namePtr);
	    CORBA_String_var ref = getTypeString(scope, origType,
						 GetTypeRef,
						 false, nameRef);
	    CORBA_String_var var = getTypeString(scope, origType,
						 GetTypeVar,
						 false, nameVar);
	    CORBA_String_var slice = getTypeString(scope, origType,
						   GetTypeSlice,
						   false, nameSlice);
	    CORBA_String_var forAny = getTypeString(scope, origType,
						    GetTypeForAny,
						    false, nameForAny);

	    out.sep();

	    if(strncmp("???", norm, 3) != 0)
		out << "\ntypedef " << norm << ';';

	    if(strncmp("???", ptr, 3) != 0)
		out << "\ntypedef " << ptr << ';';

	    if(strncmp("???", slice, 3) != 0)
		out << "\ntypedef " << slice << ';';

	    if(strncmp("???", var, 3) != 0)
		out << "\ntypedef " << var << ';';

	    if(strncmp("???", forAny, 3) != 0)
		out << "\ntypedef " << forAny << ';';

	    CORBA_String_var externStr = CORBA_string_dup("\n");
	    CORBA_String_var inlineStr = CORBA_string_dup("\n");

	    if(strlen(dllImport_) > 0)
	    {
		externStr += dllImport_;
		externStr += ' ';
	    }

	    if(container -> def_kind() != CORBA_dk_Interface)
	    {
		externStr += "extern ";
		inlineStr += "inline ";
	    }
	    else
	    {
		externStr += "static ";
		inlineStr += "static inline ";
	    }

	    if(!noTC_)
		out << externStr << "OBTypeCodeConst " << pre << "_tc_"
		    << name << ';';

	    if(origOrigType -> kind() == CORBA_tk_array)
	    {
		bool variable = IdlIsVariable(origOrigType);
		CORBA_TypeCode_var contentType;
		CORBA_ULong length;
		getArrayType(origOrigType, contentType.out(), length);
		CORBA_String_var cont = getTypeString(scope, contentType,
						      GetTypeArray, true);

		out.sep();
		out << inlineStr << nameSlice << "*\n" << pre << name
		    << "_alloc()";
		out.start();
		out << "\nreturn ";
		if(length != origOrigType -> length())
		    out << '(' << nameSlice << "*) ";
		out << "new " << cont << '[' << length << "];";
		out.end();

		out.sep();
		out << inlineStr << nameSlice << "*\n" << pre << name
		    << "_dup(const " << nameSlice << "* s)";
		out.start();
		out << '\n' << nameSlice << "* to = ";
		if(length != origOrigType -> length())
		    out << '(' << nameSlice << "*) ";
		out << "new " << cont << '[' << length << "];";
		if(variable)
		{
		    out << "\nfor(CORBA_ULong i = 0 ; i < " << length
			<< " ; i++)";
		    out.inc();
		    if(length != origOrigType -> length())
			out << "\n((" << cont << "*)to)[i] = "
			    << "((" << cont << "*)s)[i];";
		    else
			out << "\nto[i] = s[i];";
		    out.dec();
		}
		else
		{
		    out << "\nmemcpy(to, s, " << length
			<< " * sizeof(" << cont << "));";
		}
		out << "\nreturn to;";
		out.end();

		out.sep();
		out << inlineStr << "void\n" << pre << name
		    << "_copy(const " << nameSlice << "* s, "
		    << nameSlice << "* to)";
		out.start();
		if(variable)
		{
		    out << "\nfor(CORBA_ULong i = 0 ; i < " << length
			<< " ; i++)";
		    out.inc();
		    if(length != origOrigType -> length())
			out << "\n((" << cont << "*)to)[i] = "
			    << "((" << cont << "*)s)[i];";
		    else
			out << "\nto[i] = s[i];";
		    out.dec();
		}
		else
		{
		    out << "\nmemcpy(to, s, " << length
			<< " * sizeof(" << cont << "));";
		}
		out.end();

		out.sep();
		out << inlineStr << "void\n" << pre << name
		    << "_free(" << nameSlice << "* s)";
		out.start();
		out << "\ndelete [] ";
		if(length != origOrigType -> length())
		    out << '(' << cont << "*)";
		out << "s;";
		out.end();

		out.sep();
		out.direct("\n#ifdef HAVE_VCPLUSPLUS_BUGS");

		out.sep();
		out << inlineStr << nameSlice << "*\n" << pre << name
		    << "_dup(" << nameSlice << "* s)";
		out.start();
		out << "\nreturn " << pre << name << "_dup((const "
		    << nameSlice << "*) s);";
		out.end();

		out.sep();
		out << inlineStr << "void\n" << pre << name
		    << "_copy(" << nameSlice << "* s, "
		    << nameSlice << "* to)";
		out.start();
		out << '\n' << pre << name << "_copy((const "
		    << nameSlice << "*) s, to);";
		out.end();

		out.sep();
		out.direct("\n#endif");	// HAVE_VCPLUSPLUS_BUGS
	    }

	    break;
	}

	case CORBA_dk_Enum:
	{
	    //
	    // Enum
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    out.sep();
	    out << "\nenum " << pre << name;
	    out.start();

	    for(j = 0 ; j < desc -> type -> member_count() ; j++)
	    {
		CORBA_Identifier_var memberName =
		    desc -> type -> member_name(j);
		memberName = fixKwd(memberName);
		out << '\n' << pre << memberName;
		if(j < desc -> type -> member_count() - 1)
		    out << ',';
	    }
	    
	    out.end();
	    out << ';';

	    if(!noTC_)
	    {
		out.sep();

		out << '\n';
		
		if(strlen(dllImport_) > 0)
		    out << dllImport_ << ' ';

		if(container -> def_kind() != CORBA_dk_Interface)
		    out << "extern OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
		else
		    out << "static OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
	    }

	    break;
	}

	case CORBA_dk_Struct:
	case CORBA_dk_Exception:
	{
	    CORBA_RepositoryId_var id;
	    CORBA_Identifier_var name;
	    CORBA_TypeCode_var type;
	    
	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		//
		// Struct
		//
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }
	    else
	    {
		//
		// Exception
		//
		CORBA_ExceptionDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }

	    if(!check(id))
		continue;

	    bool variable = IdlIsVariable(type);

	    comment(id, out);

	    out.sep();
	    out << "\nstruct " << pre << name;
	    if(seq[i].kind == CORBA_dk_Exception)
		out << " : public CORBA_UserException";

	    out.start();

	    if(variable)
	    {
		bool hasFixed = false;
		for(j = 0 ; j < type -> member_count() ; j++)
		{
		    CORBA_TypeCode_var tc = type -> member_type(j);
		    if(!IdlIsVariable(tc))
		    {
			hasFixed = true;
			break;
		    }
		}
		if(hasFixed)
		{
		    out.direct("\n#ifdef OB_CLEAR_MEM");
		    out << '\n' << pre << name << "();";
		    out.direct("\n#else");
		    out << '\n' << pre << name << "() { }";
		    out.direct("\n#endif"); // OB_CLEAR_MEM
		}
		else
		{
		    out << '\n' << pre << name << "() { }";
		}

		out << '\n' << pre << name << "(const "
		    << pre << name << "&);";

		if(seq[i].kind == CORBA_dk_Exception &&
		   type -> member_count() > 0)
		{
		    out << '\n' << pre << name << '(';
		    unsigned int indent = out.getIndent();
		    out.setIndent(out.getPos());
		    for(j = 0 ; j < type -> member_count() ; j++)
		    {
			CORBA_TypeCode_var memberType = type -> member_type(j);
			
			CORBA_String_var s = getTypeString(scope, memberType,
							   GetTypeIn);
			
			if(j > 0)
			    out << ",\n";
			
			out << s;
		    }
		    out << ");";
		    out.setIndent(indent);
		}

		out << '\n';
		if(seq[i].kind == CORBA_dk_Exception)
		    out << "virtual ";
                out << '~' << pre << name << "() { }";

		out << '\n' << pre << name << "& operator=(const "
		    << pre << name << "&);";

		if(seq[i].kind == CORBA_dk_Exception)
		{
		    out.sep();
		    out << "\nvirtual void _raise() const { throw *this; }";
		    out.sep();
		    out << "\nstatic " << pre << name
			<< "* _narrow(CORBA_Exception*);";
		    out.direct("\n#ifdef HAVE_NO_RTTI");
		    out << "\nvirtual void* "
			<< "_OB_narrowHelp(const char*) const;";
		    out.direct("\n#endif"); // HAVE_NO_RTTI
		    out << "\nvirtual const char* _OB_typeId() const;";
		    out << "\nvirtual CORBA_Exception* _OB_clone() const;";
		}

		if(type -> member_count() > 0)
		    out.sep();
	    }

	    for(j = 0 ; j < type -> member_count() ; j++)
	    {
		CORBA_TypeCode_var memberType = type -> member_type(j);
		CORBA_Identifier_var memberName = type -> member_name(j);
		memberName = fixKwd(memberName);

		CORBA_String_var str = getTypeString(scope, memberType,
						     GetTypeStruct,
						     false, memberName);
		out << '\n' << str << ';';
	    }

	    out.end();
	    out << ';';

	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		out.sep();
		if(variable)
		{
		    out << "\ntypedef OBVarVar< " << pre << name
			<< " > " << pre << name << "_var;";
		}
		else
		{
		    out << "\ntypedef OBFixVar< " << pre << name
			<< " > " << pre << name << "_var;";
		}
	    }

	    if(!noTC_)
	    {
		out.sep();

		out << '\n';
		
		if(strlen(dllImport_) > 0)
		    out << dllImport_ << ' ';

		if(container -> def_kind() != CORBA_dk_Interface)
		    out << "extern OBTypeCodeConst " << pre
			<< "_tc_" << name << ';';
		else
		    out << "static OBTypeCodeConst " << pre
			<< "_tc_" << name << ';';
	    }
		
	    break;
	}

	case CORBA_dk_Union:
	{
	    //
	    // Union
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    CORBA_TypeCode_var discType = desc -> type -> discriminator_type();
	    CORBA_String_var disc = getTypeString(scope, discType,
						  GetTypeNormal);

	    IdlUnionMemberInfoSeq_var infoSeq = IdlGetUnionInfo(desc -> type);
	    for(j = 0 ; j < infoSeq -> length() ; j++)
		infoSeq[j].name = fixKwd(infoSeq[j].name);

	    bool variable = IdlIsVariable(desc -> type);

	    comment(desc -> id, out);

	    out.sep();
	    out << "\nclass " << pre << name;
	    out.start();

	    out << "\nunion";
	    out.start();
	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];
		if(CORBA_is_nil(info.type))
		    continue;

		CORBA_String_var norm =
		    getTypeString(scope, info.type, GetTypeNormal);
		
		CORBA_TypeCode_var origMemberType =
		    OBGetOrigType(info.type);

		switch(origMemberType -> kind())
		{
		case CORBA_tk_null:
		case CORBA_tk_void:
		case CORBA_tk_except:
		    assert(false);
		    break;
		    
		case CORBA_tk_short:
		case CORBA_tk_long:
		case CORBA_tk_ushort:
		case CORBA_tk_ulong:
		case CORBA_tk_float:
		case CORBA_tk_double:
		case CORBA_tk_boolean:
		case CORBA_tk_char:
		case CORBA_tk_octet:
		case CORBA_tk_enum:
		case CORBA_tk_struct:
		case CORBA_tk_union:
		case CORBA_tk_sequence:
		case CORBA_tk_any:
		    if(IdlIsVariable(origMemberType))
			out << '\n' << norm << "* " << info.name << ';';
		    else
			out << '\n' << norm << ' ' << info.name << ';';
		    break;
		    
		case CORBA_tk_TypeCode:
		case CORBA_tk_Principal:
		case CORBA_tk_objref:
		    out << '\n' << norm << "_ptr " << info.name << ';';
		    break;
		    
		case CORBA_tk_string:
		    out << "\nchar* " << info.name << ';';
		    break;
		    
		case CORBA_tk_array:
		{
		    CORBA_String_var s;
		    if(IdlIsVariable(origMemberType))
			s = getTypeString(scope, info.type, GetTypeReturn,
					  false, info.name);
		    else
			s = getTypeString(scope, info.type, GetTypeNormal,
					  false, info.name);

		    out << '\n' << s << ';';
		    break;
		}
		
		case CORBA_tk_alias:
		    assert(false);
		    break;
		}
	    }
	    out.end();
	    out << " _ob_v_;";

	    out.sep();
	    if(variable)
		out << "\nbool _ob_i_;";
	    out << '\n' << disc << " _ob_d_;";

	    out.sep();
	    if(variable)
		out << "\nvoid _OB_remove();";
	    out << "\nbool _OB_check(" << disc << ") const;";

	    out.sep();
	    out.dec();
	    out << "\npublic:";
	    out.inc();

	    if(variable)
	    {
		out.sep();
		out.direct("\n#ifdef OB_CLEAR_MEM");
		out << '\n' << pre << name << "();";
		out.direct("\n#else");
		out << '\n' << pre << name << "() : _ob_i_(false) { }";
		out.direct("\n#endif"); // OB_CLEAR_MEM
		out << '\n' << pre << name << "(const " << pre << name
		    << "&);";
		out << "\n~" << pre << name << "() { _OB_remove(); }";
		
		out.sep();
		out << '\n' << pre << name << "& operator=(const "
		    << pre << name << "&);";
	    }

	    out.sep();
	    out << "\nvoid _d(" << disc << ");";
	    out << '\n' << disc << " _d() const;";

	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];

		if(CORBA_is_nil(info.type))
		{
		    out.sep();
		    out << "\nvoid _default();";
		}
		else
		{
		    CORBA_String_var norm =
			getTypeString(scope, info.type, GetTypeNormal);

		    CORBA_TypeCode_var origMemberType =
			OBGetOrigType(info.type);

		    switch(origMemberType -> kind())
		    {
		    case CORBA_tk_null:
		    case CORBA_tk_void:
		    case CORBA_tk_except:
			assert(false);
			break;
			
		    case CORBA_tk_short:
		    case CORBA_tk_long:
		    case CORBA_tk_ushort:
		    case CORBA_tk_ulong:
		    case CORBA_tk_float:
		    case CORBA_tk_double:
		    case CORBA_tk_boolean:
		    case CORBA_tk_char:
		    case CORBA_tk_octet:
		    case CORBA_tk_enum:
			out.sep();
			out << "\nvoid " << info.name << '(' << norm << ");";
			out << '\n' << norm << ' ' << info.name
			    << "() const;";
			break;
			
		    case CORBA_tk_struct:
		    case CORBA_tk_union:
		    case CORBA_tk_sequence:
		    case CORBA_tk_any:
			out.sep();
			out << "\nvoid " << info.name << "(const " << norm
			    << "&);";
			out << "\nconst " << norm << "& " << info.name
			    << "() const;";
			out << '\n' << norm << "& " << info.name << "();";
			break;
			
		    case CORBA_tk_TypeCode:
		    case CORBA_tk_Principal:
		    case CORBA_tk_objref:
			out.sep();
			out << "\nvoid " << info.name << '(' << norm
			    << "_ptr);";
			out << '\n' << norm << "_ptr " << info.name
			    << "() const;";
			break;
			
		    case CORBA_tk_string:
			out.sep();
			out << "\nvoid " << info.name << "(char*);";
			out << "\nvoid " << info.name << "(const char*);";
			out << "\nvoid " << info.name
			    << "(const CORBA_String_var&);";
			out << "\nconst char* " << info.name << "() const;";
			break;
			
		    case CORBA_tk_array:
		    {
			CORBA_String_var slice;
			
			if(info.type -> kind() == CORBA_tk_alias)
			{
			    slice = getTypeString(scope, info.type,
						  GetTypeSlice);
			}
			else
			{
			    const char* sl = "_slice";
			    slice = CORBA_string_alloc(1 + strlen(info.name)
						       + strlen(sl));
			    strcpy(slice.inout(), "_");
			    strcat(slice.inout(), info.name);
			    strcat(slice.inout(), sl);
			    
			    CORBA_String_var sliceDef =
				getTypeString(scope, info.type, GetTypeSlice,
					      true, slice);
			    
			    out.sep();
			    out << "\ntypedef " << sliceDef << ';';
			}
			
			out.sep();
			out << "\nvoid " << info.name << '(' << slice << "*);";
			out << '\n' << slice << "* " << info.name << "();";
			out << "\nconst " << slice << "* " << info.name
			    << "() const;";
			
			break;
		    }
		    
		    case CORBA_tk_alias:
			assert(false);
			break;
		    }
		}
	    }

	    if(!local_)
	    {
		out.sep();
		out << "\nfriend void OBMarshal(const " << pre << name
		    << "&, CORBA_Octet*&);";
		out << "\nfriend void OBMarshalCount(const " << pre << name
		    << "&, CORBA_ULong&);";
		out << "\nfriend void OBUnmarshal(" << pre << name
		    << "&, const CORBA_Octet*&, bool);";
	    }

	    out.end();
	    out << ';';

	    out.sep();
	    if(variable)
	    {
		out << "\ntypedef OBVarVar< " << pre << name
		    << " > " << pre << name << "_var;";
	    }
	    else
	    {
		out << "\ntypedef OBFixVar< " << pre << name
		    << " > " << pre << name << "_var;";
	    }

	    if(!noTC_)
	    {
		out.sep();

		out << '\n';
		
		if(strlen(dllImport_) > 0)
		    out << dllImport_ << ' ';

		if(container -> def_kind() != CORBA_dk_Interface)
		    out << "extern OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
		else
		    out << "static OBTypeCodeConst " << pre << "_tc_"
			<< name << ';';
	    }

	    break;
	}

	case CORBA_dk_Attribute:
	{
	    //
	    // Attribute
	    //
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    CORBA_String_var ret = getTypeString(scope, desc -> type,
						 GetTypeReturn);

	    out.sep();
	    if(local_)
		out << "\nvirtual " << ret << ' ' << pre << name << "() = 0;";
	    else
		out << "\nvirtual " << ret << ' ' << pre << name << "();";
	    
	    if(desc -> mode == CORBA_ATTR_NORMAL)
	    {
		CORBA_String_var in = getTypeString(scope, desc -> type,
						    GetTypeIn);

		if(local_)
		    out << "\nvirtual void " << pre << name << '(' << in
			<< ") = 0;";
		else
		    out << "\nvirtual void " << pre << name << '(' << in
			<< ");";
	    }

	    break;
	}

	case CORBA_dk_Operation:
	{
	    //
	    // Operation
	    //
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    CORBA_String_var ret =
		getTypeString(scope, desc -> result, GetTypeReturn);
	    
	    out.sep();
	    out << "\nvirtual " << ret << ' ' << pre << name << "(";
	    
	    unsigned int indent = out.getIndent();
	    out.setIndent(out.getPos());

	    for(j = 0 ; j < desc -> parameters.length() ; j++)
	    {
		GetType tt;
		switch(desc -> parameters[j].mode)
		{
		case CORBA_PARAM_IN:
		    tt = GetTypeIn;
		    break;

		case CORBA_PARAM_INOUT:
		    tt = GetTypeInOut;
		    break;

		case CORBA_PARAM_OUT:
		    tt = GetTypeOut;
		    break;
		}

		CORBA_String_var argName = fixKwd(desc -> parameters[j].name);

		CORBA_String_var s =
		    getTypeString(scope, desc -> parameters[j].type, tt,
				  false, argName);

		if(j > 0)
		    out << ",\n";

		out << s;
	    }

	    if(desc -> contexts.length() > 0)
	    {
		if(desc -> parameters.length() > 0)
		    out << ",\n";
		
		out << "CORBA_Context_ptr";
	    }

	    if(local_)
		out << ") = 0;";
	    else
		out << ");";

	    out.setIndent(indent);

	    break;
	}

	default:
	    break;
	}
    }
}

// ----------------------------------------------------------------------
// Generate code for the header file, CORBA namespace part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusHGlobalNamespace(CORBA_Container_ptr container,
					      IdlPrettyPrint& out)
{
    //
    // Get scope and prefix
    // (prefix needed if alternative module mapping is used)
    //
    CORBA_String_var scope;
    CORBA_String_var pre;
    getScopeAndPrefix(container, scope.out(), pre.out());

    //
    // Get container contents descriptions
    //
    CORBA_Container::DescriptionSeq_var seq =
	container -> describe_contents(CORBA_dk_all, true, -1);

    CORBA_ULong i;

    for(i = 0 ; i < seq -> length() ; i++)
    {
	switch(seq[i].kind)
	{
	case CORBA_dk_Interface:
	{
	    //
	    // Interface
	    //
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    //
	    // release and is_nil
	    //
	    out.sep();
    	    out << "\ninline void\nCORBA_release(" << absolute << "_ptr p)";
	    out.start();
	    out << "\nif(p)";
	    out.inc();
	    out << "\np -> _OB_decRef();";
	    out.dec();
	    out.end();

	    out.sep();
    	    out << "\ninline CORBA_Boolean\nCORBA_is_nil(" << absolute
		<< "_ptr p)";
	    out.start();
	    out << "\nreturn p == 0;";
	    out.end();

	    if(!local_)
	    {
		//
		// CDR
		//
		out.sep();
		out << "\ninline void\nOBMarshal(" << absolute
		    << "_ptr p, CORBA_Octet*& oct)";
		out.start();
		out << "\nOBMarshal((CORBA_Object_ptr)p, oct);";
		out.end();
		
		out.sep();
		out << "\ninline void\nOBMarshalCount(" << absolute
		    << "_ptr p, CORBA_ULong& count)";
		out.start();
		out << "\nOBMarshalCount((CORBA_Object_ptr)p, count);";
		out.end();
		
		out.sep();
		out << "\nvoid OBUnmarshal(" << absolute
		    << "_ptr&, const CORBA_Octet*&, bool);";
	    }
	    
	    if(!noTC_)
	    {
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid operator<<=(CORBA_Any&, "
		    << absolute << "_ptr);";
		out << "\nvoid operator<<=(CORBA_Any&, "
		    << absolute << "_ptr*);";
		out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
		    << absolute << "_ptr&);";

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
		    << absolute << "_ptr val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
		    << absolute << "_ptr* val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline CORBA_Boolean";
		out << "\noperator>>=(const CORBA_Any_var& any, "
		    << absolute << "_ptr& val)";
		out.start();
		out << "\nreturn any.in() >>= val;";
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Enum:
	{
	    //
	    // Enum
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    if(!local_)
	    {
		//
		// CDR
		//
		out.sep();
		out << "\ninline void\nOBMarshal(" << absolute
		    << " val, CORBA_Octet*& oct)";
		out.start();
		out << "\nOBMarshal((CORBA_ULong)val, oct);";
		out.end();
		
		out.sep();
		out << "\ninline void\nOBMarshalCount(" << absolute
		    << ", CORBA_ULong& count)";
		out.start();
		out << "\nOBMarshalCount((CORBA_ULong)0, count);";
		out.end();
		
		out.sep();
		out << "\ninline void\nOBUnmarshal(" << absolute
		    << "& val, const CORBA_Octet*& coct, bool swap)";
		out.start();
		out << "\nCORBA_ULong v;";
		out << "\nOBUnmarshal(v, coct, swap);";
		out << "\nval = (" << absolute << ")v;";
		out.end();
	    }

	    if(!noTC_)
	    {
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid operator<<=(CORBA_Any&, " << absolute << ");";
		out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
		    << absolute << "&);";
	    }
		
	    break;
	}

	case CORBA_dk_Struct:
	case CORBA_dk_Exception:
	{
	    CORBA_RepositoryId_var id;
	    CORBA_Identifier_var name;
	    CORBA_TypeCode_var type;
	    
	    if(seq[i].kind == CORBA_dk_Struct)
	    {
		//
		// Struct
		//
		CORBA_TypeDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }
	    else
	    {
		//
		// Exception
		//
		CORBA_ExceptionDescription* desc;
		CORBA_Boolean b = seq[i].value >>= desc;
		assert(b);

		name = fixKwd(desc -> name);
		id = desc -> id;
		type = desc -> type;
	    }

	    if(!check(id))
		continue;

	    CORBA_ScopedName_var absolute = getAbsolute(id);

	    comment(id, out);

	    if(!local_)
	    {
		//
		// CDR
		//
		out.sep();
		out << "\nvoid OBMarshal(const " << absolute
		    << "&, CORBA_Octet*&);";
		out << "\nvoid OBMarshalCount(const " << absolute
		    << "&, CORBA_ULong&);";
		out << "\nvoid OBUnmarshal(" << absolute
		    << "&, const CORBA_Octet*&, bool);";
	    }

	    if(!noTC_)
	    {
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid operator<<=(CORBA_Any&, " << absolute << "*);";
		out << "\nvoid operator<<=(CORBA_Any&, const "
		    << absolute << "&);";
		out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
		    << absolute << "*&);";

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
		    << absolute << "* val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, const "
		    << absolute << "& val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline CORBA_Boolean";
		out << "\noperator>>=(const CORBA_Any_var& any, "
		    << absolute << "*& val)";
		out.start();
		out << "\nreturn any.in() >>= val;";
		out.end();
	    }

	    break;
	}

	case CORBA_dk_Union:
	{
	    //
	    // Union
	    //
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);

	    comment(desc -> id, out);

	    if(!local_)
	    {
		//
		// CDR
		//
		out.sep();
		out << "\nvoid OBMarshal(const " << absolute
		    << "&, CORBA_Octet*&);";
		out << "\nvoid OBMarshalCount(const " << absolute
		    << "&, CORBA_ULong&);";
		out << "\nvoid OBUnmarshal(" << absolute
		    << "&, const CORBA_Octet*&, bool);";
	    }

	    if(!noTC_)
	    {
		//
		// Any insertion and extraction
		//
		out.sep();
		out << "\nvoid operator<<=(CORBA_Any&, " << absolute << "*);";
		out << "\nvoid operator<<=(CORBA_Any&, const " << absolute
		    << "&);";
		out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
		    << absolute << "*&);";

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
		    << absolute << "* val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, const "
		    << absolute << "& val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline CORBA_Boolean";
		out << "\noperator>>=(const CORBA_Any_var& any, "
		    << absolute << "*& val)";
		out.start();
		out << "\nreturn any.in() >>= val;";
		out.end();
	    }

	    break;
	}

	default:
	    break;
	}

	//
	// Check for recursion
	//
	CORBA_Container_var cont =
	    CORBA_Container::_narrow(seq[i].contained_object);
	if(!CORBA_is_nil(cont))
	    genCPlusPlusHGlobalNamespace(cont, out);
    }
}

// ----------------------------------------------------------------------
// Generate code for the header file, anonymous types part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusHAnonTypes(IdlPrettyPrint& out, const char* macro)
{
    CORBA_ULong i;

    for(i = 0 ; i < anonTCSeq_.length() ; i++)
    {
	CORBA_TypeCode_var type = OBGetOrigType(anonTCSeq_[i]);

	//
	// Sequences
	//
	if(type -> kind() == CORBA_tk_sequence)
	{
	    if(!isInLibrary(type) || !noTC_)
	    {
		//
		// Get absolute name
		//
		CORBA_ScopedName_var absolute =
		    getTypeString("", type, GetTypeNormal, true);
		
		comment(absolute, out);
		
		CORBA_String_var anon = IdlGetAnonName(absolute);
		out.sep();
		out.direct("\n#ifndef ");
		out << "OB_use_" << anon;
		out.direct("\n#define ");
		out << "OB_use_" << anon;
		out.direct("\n#define ");
		out << "OB_use_" << anon << "_from_" << macro;

		if(!isInLibrary(type))
		{
		    if(!local_)
		    {
			//
			// CDR functions
			//
			out.sep();
			out << "\nvoid OBMarshal(const "
			    << absolute << "&, CORBA_Octet*&);";
			out << "\nvoid OBMarshalCount(const "
			    << absolute << "&, CORBA_ULong&);";
			out << "\nvoid OBUnmarshal("
			    << absolute << "&, const CORBA_Octet*&, bool);";
		    }
		}
		
		if(!noTC_)
		{
		    //
		    // Any insertion and extraction
		    //
		    out.sep();
		    out << "\nvoid operator<<=(CORBA_Any&, " << absolute
			<< "*);";
		    out << "\nvoid operator<<=(CORBA_Any&, const " << absolute
			<< "&);";
		    out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
			<< absolute << "*&);";
		    
		    out.sep();
		    out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
			<< absolute << "* val)";
		    out.start();
		    out << "\nany.inout() <<= val;";
		    out.end();
		    
		    out.sep();
		    out << "\ninline void\noperator<<=(CORBA_Any_var& any, "
			<< "const " << absolute << "& val)";
		    out.start();
		    out << "\nany.inout() <<= val;";
		    out.end();
		    
		    out.sep();
		    out << "\ninline CORBA_Boolean";
		    out << "\noperator>>=(const CORBA_Any_var& any, "
			<< absolute << "*& val)";
		    out.start();
		    out << "\nreturn any.in() >>= val;";
		    out.end();
		}
		
		out.sep();
		out.direct("\n#endif"); // OB_use_...
	    }
	}

	//
	// Arrays
	//
	if(type -> kind() == CORBA_tk_array)
	{
	    //
	    // Get absolute name
	    //
	    CORBA_ScopedName_var absolute =
		getTypeString("", type, GetTypeNormal, true);

	    comment(absolute, out);
	    
	    CORBA_String_var anon = IdlGetAnonName(absolute);
	    out.sep();
	    out.direct("\n#ifndef ");
	    out << "OB_use_" << anon;
	    out.direct("\n#define ");
	    out << "OB_use_" << anon;
	    out.direct("\n#define ");
	    out << "OB_use_" << anon << "_from_" << macro;
	    
	    //
	    // Create slice typedef
	    //
	    CORBA_String_var nameSlice = CORBA_string_dup("OBSlice_");
	    nameSlice += anon;

	    CORBA_ScopedName_var slice = getTypeString("", type, GetTypeSlice,
						       true, nameSlice);
	    out.sep();
	    out << "\ntypedef " << slice << ';';

	    if(!local_)
	    {
		//
		// CDR functions
		//
		out.sep();
		out << "\nvoid OBMarshal_" << anon << "(const "
		    << nameSlice << "*, CORBA_Octet*&);";
		out << "\nvoid OBMarshalCount_" << anon << "(const "
		    << nameSlice << "*, CORBA_ULong&);";
		out << "\nvoid OBUnmarshal_" << anon << '(' << nameSlice
		    << "*, const CORBA_Octet*&, bool);";
		
		out.sep();
		out.direct("\n#ifdef HAVE_VCPLUSPLUS_BUGS");
		out.sep();
		out << "\ninline void\nOBMarshal_" << anon << "("
		    << nameSlice << "* s, CORBA_Octet*& oct)";
		out.start();
		out << "\nOBMarshal_" << anon << "((const " << nameSlice
		    << "*)s, oct);";
		out.end();
		
		out.sep();
		out << "\ninline void\nOBMarshalCount_" << anon << "("
		    << nameSlice << "* s, CORBA_ULong& count)";
		out.start();
		out << "\nOBMarshalCount_" << anon << "((const " << nameSlice
		    << "*)s, count);";
		out.end();
		
		out.sep();
		out.direct("\n#endif"); // HAVE_VCPLUSPLUS_BUGS
	    }

	    //
	    // alloc, dup, copy, free
	    //
	    out.sep();
	    out << '\n' << nameSlice << "* OBAlloc_" << anon << "();";
	    out << '\n' << nameSlice << "* OBDup_" << anon << "(const "
		<< nameSlice << "*);";
	    out << "\nvoid OBCopy_" << anon << "(const "
		<< nameSlice << "*, " << nameSlice << "*);";
	    out << "\nvoid OBFree_" << anon << '(' << nameSlice << "*);";

	    out.sep();
	    out.direct("\n#ifdef HAVE_VCPLUSPLUS_BUGS");

	    out.sep();
	    out << "\ninline " << nameSlice << "*\nOBDup_" << anon << "("
		<< nameSlice << "* s)";
	    out.start();
	    out << "\nreturn OBDup_" << anon << "((const "
		<< nameSlice << "*) s);";
	    out.end();

	    out.sep();
	    out << "\ninline void\nOBCopy_" << anon << "("
		<< nameSlice << "* s, " << nameSlice << "* to)";
	    out.start();
	    out << "\nOBCopy_" << anon << "((const "
		<< nameSlice << "*) s, to);";
	    out.end();

	    out.sep();
	    out.direct("\n#endif"); // HAVE_VCPLUSPLUS_BUGS

	    if(!noTC_)
	    {
		//
		// Any insertion and extraction
		//
		CORBA_String_var forAny =
		    getTypeString("", type, GetTypeForAny, true);
		
		out.sep();
		out << "\nvoid operator<<=(CORBA_Any&, const "
		    << forAny << "&);";
		out << "\nCORBA_Boolean operator>>=(const CORBA_Any&, "
		    << forAny << "&);";

		out.sep();
		out << "\ninline void\noperator<<=(CORBA_Any_var& any, const "
		    << forAny << "& val)";
		out.start();
		out << "\nany.inout() <<= val;";
		out.end();

		out.sep();
		out << "\ninline CORBA_Boolean";
		out << "\noperator>>=(const CORBA_Any_var& any, "
		    << forAny << "& val)";
		out.start();
		out << "\nreturn any.in() >>= val;";
		out.end();
	    }
		
	    out.sep();
	    out.direct("\n#endif"); // OB_use_...
	}
    }
}
