// **********************************************************************
//
// 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>

#ifdef WIN32
#   include <direct.h>
#endif

#ifdef HAVE_FSTREAM
#   include <fstream>
#else
#   include <fstream.h>
#endif

#include <GenJava.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>

// ----------------------------------------------------------------------
// Special Java "Pretty-Print" class member implementation
// ----------------------------------------------------------------------

const char* IdlJavaGenerator::PrettyPrint::header_ =
"// **********************************************************************\n"
"//\n"
"// Generated by the ORBacus IDL to Java Translator\n"
"//\n"
"// Copyright (c) 1999\n"
"// Object Oriented Concepts, Inc.\n"
"// Billerica, MA, USA\n"
"//\n"
"// All Rights Reserved\n"
"//\n"
"// **********************************************************************";

IdlJavaGenerator::PrettyPrint::PrettyPrint(IdlStringSeq*& fileNameSeq,
					   const char* prog,
					   const char* name,
					   const char* package,
					   const char* dir,
					   unsigned int num)
    : IdlPrettyPrint(out_, num)
{
    //
    // Create directories and construct the directory path
    //
    path_ = CORBA_string_dup(dir);
    CORBA_String_var str = CORBA_string_dup(package);
    char* s = str.inout();
    char* tok = 0;
    const char* sep = ".";
    while((tok = strtok(s, sep)))
    {
	s = 0;

	if(strlen(tok))
	{
	    if(strlen(path_) > 0)
		path_ += '/';
	    
	    path_ += tok;

#ifdef WIN32
	    _mkdir((const char*)path_);
#else
	    mkdir((const char*)path_, S_IRWXU | S_IRWXG | S_IRWXO);
#endif
	}
    }

    //
    // Create complete file name path
    //
    if(strlen(path_) > 0)
	path_ += '/';
    path_ += name;
    path_ += ".java";

    //
    // Create the file
    //
    out_.open(path_);

    //
    // Write header and package
    //
    if(good())
    {
	fileNameSeq -> append(path_);

	*this << header_;
	*this << '\n';
	*this << "\n// Version: " << OBVersion;
	*this << "\n// License: " << OBLicense;

	if(package && strlen(package) > 0)
	{
	    this -> sep();
	    *this << "\npackage " << package << ';';
	}
    }
    else
    {
	cerr << prog << ": can't open \"" << path_
	     << "\": " << strerror(errno) << endl;
    }
}

// ----------------------------------------------------------------------
// Print header comment
// ----------------------------------------------------------------------

void
IdlJavaGenerator::comment(const char* s, IdlPrettyPrint& out)
{
    out.ignoreNextSep(false);
    out.sep();
    out << "\n//";
    out << "\n// " << s;
    out << "\n//";
    out.ignoreNextSep(true);
}

// ----------------------------------------------------------------------
// Print documentation comment
// ----------------------------------------------------------------------

void
IdlJavaGenerator::docComment(const char* id, IdlPrettyPrint& out)
{
    if(!noComments_)
    {
	for(CORBA_ULong i = 0 ; i < commentSeq_.length() ; i++)
	{
	    if(strcmp(id, commentSeq_[i].id) == 0)
	    {
		out << "\n/**";

		const char* s = commentSeq_[i].comment;

		while(*s)
		{
		    static const char* ex = "@exception";
		    if(strncmp(s, ex, strlen(ex)) == 0)
		    {
			out << ex;
			s += strlen(ex);
			
			while(*s == ' ' || *s == '\t')
			{
			    out << *s;
			    s++;
			}

			const char* s2 = s;

			while(*s2 != ' ' && *s2 != '\t' &&
			      *s2 != '\n' && *s2 != '\0')
			{
			    s2++;
			}

			if((*s2 == ' ' || *s2 == '\t') && (s2 > s))
			{
			    CORBA_String_var name = CORBA_string_alloc(s2 - s);
			    strncpy(name.inout(), s, s2 - s);
			    name[s2 - s] = '\0';

			    CORBA_Contained_var contained =
				repository_ -> lookup_id(id);

			    if(!CORBA_is_nil(contained))
			    {
				CORBA_Container_var container =
				    contained -> defined_in();

				if(!CORBA_is_nil(container))
				{
				    do
				    {
					try
					{
					    contained =
						container -> lookup(name);
					}
					catch(const CORBA_INTF_REPOS&)
					{
					    contained =
						CORBA_Contained::_nil();

					    break;
					}

					if(CORBA_is_nil(contained))
					{
					    CORBA_Contained_var c =
						CORBA_Contained::
						_narrow(container);
					    
					    if(CORBA_is_nil(c))
						break;
					    
					    container = c -> defined_in();
					}
				    }
				    while(CORBA_is_nil(contained));

				    if(!CORBA_is_nil(contained))
					name = getAbsolute(contained);
				}
			    }

			    out << name;

			    out << *s2;
			    s = s2 + 1;
			}

			continue;
		    }

		    if(*s == '\n')
			out << "\n *";
		    else
			out << *s;
			
		    s++;
		}

		out << "*/";

		break;
	    }
	}
    }
}

// ----------------------------------------------------------------------
// Precede Java keywords and reserved names by an underscore
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::fixName(const char* abs)
{
    assert_nca(abs, OBNCANullString);

    if(*abs == '\0')
	return CORBA_string_dup("");

    static const char* kwds[] =
    {
	"abstract", "boolean", "break", "byte",
	"case", "catch", "char", "class", "const",
	"continue", "default", "do", "double", "else",
	"extends", "final", "finally", "float", "for",
	"goto", "if", "implements", "import", "instanceof",
	"int", "interface", "long", "native", "new",
	"package", "private", "protected", "public",
	"return", "short", "static", "super", "switch",
	"synchronized", "this", "throw", "throws",
	"transient", "try", "void", "volatile", "while",
	"null", "false", "true",
	"clone", "equals", "finalize", "getClass", "hashCode",
	"notify", "notifyAll", "toString", "wait",
	0
    };

    static const char* reserved[] =
    {
	"Helper", "Holder", "Package", "Operations",
	0
    };

    CORBA_String_var right = (const char*)"";
    const char* s = strchr(abs, ':');
    if(s)
    {
	assert(s[1] == ':');
	right = fixName(s + 2);
    }

    CORBA_String_var result;
    CORBA_ULong len = s ? s - abs : strlen(abs);

    CORBA_ULong i;
    for(i = 0 ; kwds[i] != 0 ; i++)
	if(strlen(kwds[i]) == len && strncmp(kwds[i], abs, len) == 0)
	{
	    result = CORBA_string_alloc(len + 1);
	    result[0] = '_';
	    strncpy(&result[1], abs, len);
	    result[len + 1] = '\0';
	    break;
	}

    CORBA_ULong j;
    for(j = 0 ; reserved[j] != 0 ; j++)
    {
	CORBA_ULong rlen = strlen(reserved[j]);
	if(len > rlen && strncmp(reserved[j], abs + len - rlen, rlen) == 0)
	{
	    result = CORBA_string_alloc(len + 1);
	    result[0] = '_';
	    strncpy(&result[1], abs, len);
	    result[len + 1] = '\0';
	    break;
	}
    }

    if(kwds[i] == 0 && reserved[j] == 0)
    {
	result = CORBA_string_alloc(len);
	strncpy(result.inout(), abs, len);
	result[len] = '\0';
    }

    if(s)
    {
	result += ".";
	result += right;
    }

    return result._retn();
}

// ----------------------------------------------------------------------
// Create type string
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::getTypeString(const char* package, CORBA_TypeCode_ptr type,
				GetType gt)
{
    //
    // Get result
    //
    CORBA_String_var result = CORBA_string_dup("???");
    if(gt == GetTypeHelper && type -> kind() == CORBA_tk_alias)
    {
	//
	// Helper classes are available for all aliases
	//
	result = getAbsolute(type -> id());
	result += "Helper";
	removePackage(package, result.inout());
	return result._retn();
    }
    else
    {
	CORBA_TypeCode_var origType = OBGetOrigType(type);
	CORBA_TCKind kind = origType -> kind();
	switch(kind)
	{
	case CORBA_tk_void:
	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_string:
	{
	    // **************************************************
	    // Basic types
	    // **************************************************
	    
	    switch(gt)
	    {
	    case GetTypeHolder:
	    {
		static const char* names[] =
		{
		    "???",
		    "org.omg.CORBA.ShortHolder", "org.omg.CORBA.IntHolder",
		    "org.omg.CORBA.ShortHolder", "org.omg.CORBA.IntHolder",
		    "org.omg.CORBA.FloatHolder", "org.omg.CORBA.DoubleHolder",
		    "org.omg.CORBA.BooleanHolder", "org.omg.CORBA.CharHolder",
		    "org.omg.CORBA.ByteHolder",
		    "???", "???", "???", "???", "???", "???", "???",
		    "org.omg.CORBA.StringHolder"
		};
		result = names[(int)kind - (int)CORBA_tk_void];
		break;
	    }
	    
	    case GetTypeHelper:
	    case GetTypeStub:
		result = CORBA_string_dup("???");
		break;

	    case GetTypeNormal:
	    {
		static const char* names[] =
		{
		    "void",
		    "short", "int",
		    "short", "int",
		    "float", "double",
		    "boolean",
		    "char",
		    "byte",
		    "???", "???", "???", "???", "???", "???", "???",
		    "String"
		};
		result = names[(int)kind - (int)CORBA_tk_void];
		break;
	    }
	    }
	    
	    break;
	}
	
	case CORBA_tk_any:
	{
	    // **************************************************
	    // The any type
	    // **************************************************

	    switch(gt)
	    {
	    case GetTypeHolder:
		result = CORBA_string_dup("org.omg.CORBA.AnyHolder");
		break;
		
	    case GetTypeHelper:
	    case GetTypeStub:
		result = CORBA_string_dup("???");
		break;

	    case GetTypeNormal:
		result = CORBA_string_dup("org.omg.CORBA.Any");
		break;
	    }
	    
	    break;
	}
	
	case CORBA_tk_TypeCode:
	case CORBA_tk_Principal:
	case CORBA_tk_objref:
	{
	    // **************************************************
	    // Object references (including pseudo object refereces)
	    // **************************************************
	    
	    if(kind == CORBA_tk_TypeCode)
	    {
		switch(gt)
		{
		case GetTypeHelper:
		case GetTypeStub:
		    result = CORBA_string_dup("???");
		    break;

		case GetTypeNormal:
		case GetTypeHolder:
		    result = CORBA_string_dup("org.omg.CORBA.TypeCode");
		    break;
		}
	    }
	    else if(kind == CORBA_tk_Principal)
	    {
		switch(gt)
		{
		case GetTypeHelper:
		case GetTypeStub:
		    result = CORBA_string_dup("???");
		    break;

		case GetTypeNormal:
		case GetTypeHolder:
		    result = CORBA_string_dup("org.omg.CORBA.Principal");
		    break;
		}
	    }
	    else if(kind == CORBA_tk_objref)
	    {
		if(strcmp(origType -> id(), "IDL:omg.org/CORBA/Object:1.0")
		   == 0)
		{
		    switch(gt)
		    {
		    case GetTypeHelper:
		    case GetTypeStub:
			result = CORBA_string_dup("???");
			break;
			
		    case GetTypeNormal:
		    case GetTypeHolder:
			result = CORBA_string_dup("org.omg.CORBA.Object");
			break;
		    }
		}
		else
		{
		    CORBA_String_var s = getAbsolute(origType -> id());
		    removePackage(package, s.inout());
		    
		    switch(gt)
		    {
		    case GetTypeHelper:
			result = s;
			result += "Helper";
			break;

		    case GetTypeStub:
		    {
			const char* p = strrchr(s.inout(), '.');

			if(p)
			{
			    p++;
			    assert(*p);
			    result = CORBA_string_alloc(p - s.in());
			    strncpy(result.inout(), s, p - s.in());
			    result[p - s.in()] = '\0';
			    result += "StubFor";
			    result += p;
			}
			else
			{
			    result = CORBA_string_dup("StubFor");
			    result += s;
			}

			break;
		    }
			
		    case GetTypeNormal:
		    case GetTypeHolder:
			result = s;
			break;
		    }
		}
	    }
	    
	    if(gt == GetTypeHolder)
		result += "Holder";
	    
	    break;
	}
	
	case CORBA_tk_struct:
	case CORBA_tk_union:
	case CORBA_tk_except:
	case CORBA_tk_enum:
	{
	    // **************************************************
	    // Structs, unions, exceptions, enums
	    // **************************************************
	    
	    CORBA_String_var s = getAbsolute(origType -> id());
	    removePackage(package, s.inout());
	    result = s;
	    
	    switch(gt)
	    {
	    case GetTypeHelper:
		result += "Helper";
		break;

	    case GetTypeHolder:
		result += "Holder";
		break;

	    case GetTypeStub:
		result = CORBA_string_dup("???");
		break;
			
	    case GetTypeNormal:
		break;
	    }

	    break;
	}
	
	case CORBA_tk_sequence:
	case CORBA_tk_array:
	{
	    // **************************************************
	    // Sequences and arrays
	    // **************************************************
	    
	    switch(gt)
	    {
	    case GetTypeHelper:
		if(type -> kind() == CORBA_tk_alias)
		{
		    CORBA_String_var s = getAbsolute(type -> id());
		    removePackage(package, s.inout());
		    s += "Helper";
		    result = s;
		}
		break;

	    case GetTypeHolder:
		if(type -> kind() == CORBA_tk_alias)
		{
		    CORBA_String_var s = getAbsolute(type -> id());
		    removePackage(package, s.inout());
		    s += "Holder";
		    result = s;
		}
		break;

	    case GetTypeStub:
		result = CORBA_string_dup("???");
		break;
			
	    case GetTypeNormal:
	    {
		CORBA_TypeCode_var contentType = origType -> content_type();
		result = getTypeString(package, contentType, gt);
		result += "[]";
		break;
	    }
	    }
	    
	    break;
	}
	
	case CORBA_tk_alias:
	case CORBA_tk_null:
	    assert(false);
	    break;
	}
    }

    return result._retn();
}

// ----------------------------------------------------------------------
// Check if code needs to be generated for a specific repository id
// ----------------------------------------------------------------------

bool
IdlJavaGenerator::check(const char* id)
{
    if(!partial_)
	return true;

    for(CORBA_ULong i = 0 ; i < idSeq_.length() ; i++)
	if(strcmp(id, idSeq_[i]) == 0)
	    return true;

    return false;
}

// ----------------------------------------------------------------------
// Get package from package options
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::getPackageFromOptions(const char* id)
{
    CORBA_String_var package = CORBA_string_dup("");

    //
    // First handle "--prefix-package"
    //
    for(CORBA_ULong i = 0 ; i < prefixPackageSeq_.length() ; i++)
    {
	if(strncmp(prefixPackageSeq_[i].prefix, id,
		   strlen(prefixPackageSeq_[i].prefix)) == 0)
	{
	    package = prefixPackageSeq_[i].package;
	    break;
	}
    }

    //
    // Now handle "--package"
    //
    if(package.in() == 0 || strlen(package) == 0)
	if(strlen(package_))
	    package = package_;
    
    //
    // Handle automatic package generation
    //
    if(package.in() == 0 || strlen(package) == 0)
	if(autoPackage_)
	    package = getPackageFromPrefix(id);

    return package._retn();
}

// ----------------------------------------------------------------------
// Get absolute name
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::getAbsolute(const char* id)
{
    for(CORBA_ULong i = 0 ; i < absSeq_.length() ; i += 2)
    {
	if(strcmp(absSeq_[i], id) == 0)
	    return CORBA_string_dup(absSeq_[i + 1]);
    }
    
    CORBA_Contained_var contained = repository_ -> lookup_id(id);
    assert(!CORBA_is_nil(contained));
    
    CORBA_ULong len = absSeq_.length();
    absSeq_.length(len + 2);
    absSeq_[len] = id;
    absSeq_[len + 1] = getAbsolute(contained);
    return CORBA_string_dup(absSeq_[len + 1]);
}

char*
IdlJavaGenerator::getAbsolute(CORBA_Contained_ptr contained)
{
    CORBA_RepositoryId_var id = contained -> id();
    CORBA_String_var package = getPackageFromOptions(id);
    return getAbsolutePackage(contained, package);
}

char*
IdlJavaGenerator::getAbsolutePackage(CORBA_Contained_ptr contained,
				     const char* package)
{
    CORBA_Identifier_var name = contained -> name();
    name = fixName(name);

    CORBA_Container_var container = contained -> defined_in();
    CORBA_Contained_var contained2 = CORBA_Contained::_narrow(container);

    if(CORBA_is_nil(contained2))
    {
 	if(package && strlen(package))
	{
	    char* result = CORBA_string_alloc(strlen(package) + 1 +
					      strlen(name));
	    strcpy(result, package);
	    strcat(result, ".");
	    strcat(result, name);
	    return result;
	}
	else
	{
	    if(contained -> def_kind() == CORBA_dk_Module)
	    {
		return CORBA_string_dup(name);
	    }
	    else
	    {
		CORBA_RepositoryId_var id = contained -> id();
		cerr << prog_ << ": warning: no package for `" << id
		     << "' (using `defaultpkg')" << endl;

		static const char* s = "defaultpkg.";
		char* result = CORBA_string_alloc(strlen(s) + strlen(name));
		strcpy(result, s);
		strcat(result, name);
		return result;
	    }
	}
    }
    else
    {
	CORBA_String_var s = getAbsolutePackage(contained2, package);

	if(contained2 -> def_kind() == CORBA_dk_Interface)
	{
	    CORBA_DefinitionKind k = contained -> def_kind();
	    if(k == CORBA_dk_Alias || k == CORBA_dk_Enum ||
	       k == CORBA_dk_Struct || k == CORBA_dk_Exception ||
	       k == CORBA_dk_Union)
	    {
		s += "Package";
	    }
	}
	
	char* result = CORBA_string_alloc(strlen(s) + 1 + strlen(name));
	strcpy(result, s);
	strcat(result, ".");
	strcat(result, name);
	return result;
    }
}

// ----------------------------------------------------------------------
// Get package name
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::getPackage(const char* id)
{
    for(CORBA_ULong i = 0 ; i < pkgSeq_.length() ; i += 2)
    {
	if(strcmp(pkgSeq_[i], id) == 0)
	    return CORBA_string_dup(pkgSeq_[i + 1]);
    }
    
    CORBA_Contained_var contained = repository_ -> lookup_id(id);
    assert(!CORBA_is_nil(contained));
    
    CORBA_ULong len = pkgSeq_.length();
    pkgSeq_.length(len + 2);
    pkgSeq_[len] = id;
    pkgSeq_[len + 1] = getPackage(contained);
    return CORBA_string_dup(pkgSeq_[len + 1]);
}

char*
IdlJavaGenerator::getPackage(CORBA_Contained_ptr contained)
{
    CORBA_RepositoryId_var id = contained -> id();
    CORBA_String_var package = getPackageFromOptions(id);
    return getPackagePackage(contained, package);
}

char*
IdlJavaGenerator::getPackagePackage(CORBA_Contained_ptr contained,
				    const char* package)
{
    CORBA_Container_var container = contained -> defined_in();
    CORBA_Contained_var contained2 = CORBA_Contained::_narrow(container);

    if(CORBA_is_nil(contained2))
    {
 	if(package && strlen(package))
	{
	    return CORBA_string_dup(package);
	}
	else
	{
	    if(contained -> def_kind() == CORBA_dk_Module)
	    {
		return CORBA_string_dup("");
	    }
	    else
	    {
		CORBA_RepositoryId_var id = contained -> id();
		cerr << prog_ << ": warning: no package for `" << id
		     << "' (using `defaultpkg')" << endl;

		return CORBA_string_dup("defaultpkg");
	    }
	}
    }
    else
    {
	if(contained2 -> def_kind() == CORBA_dk_Module)
	{
	    return getAbsolutePackage(contained2, package);
	}
	else if(contained2 -> def_kind() == CORBA_dk_Interface)
	{
	    CORBA_DefinitionKind k = contained -> def_kind();
	    if(k == CORBA_dk_Alias || k == CORBA_dk_Enum ||
	       k == CORBA_dk_Struct || k == CORBA_dk_Exception ||
	       k == CORBA_dk_Union)
	    {
		CORBA_String_var s = getAbsolutePackage(contained2, package);
		s += "Package";
		return s._retn();
	    }
	    else
	    {
		return getPackagePackage(contained2, package);
	    }
	}
	else
	{
	    return getPackagePackage(contained2, package);
	}
    }
}

// ----------------------------------------------------------------------
// Build package name from prefix in repository id
// ----------------------------------------------------------------------

char*
IdlJavaGenerator::getPackageFromPrefix(const char* id)
{
    CORBA_String_var package = CORBA_string_dup("");

    if(strchr(id, '/') && strncmp(id, "IDL:", 4) == 0)
    {
	CORBA_String_var str = CORBA_string_dup(id + 4);
	*strchr(str.inout(), '/') = '\0';
	char* s = str.inout();
	const char* tok;

	while((tok = strtok(s, ".")))
	{
	    s = 0;
	    if(strlen(package) > 0)
	    {
		CORBA_String_var newPackage =
		    CORBA_string_alloc(strlen(tok) + 1 + strlen(package));
		strcpy(newPackage.inout(), tok);
		strcat(newPackage.inout(), ".");
		strcat(newPackage.inout(), package);
		package = newPackage;
	    }
	    else
		package = CORBA_string_dup(tok);
	}
    }

    return package._retn();
}

// ----------------------------------------------------------------------
// Convert strings with escape sequences
// ----------------------------------------------------------------------

void
IdlJavaGenerator::addEscapes(char*& str, bool addQuotes)
{
    char* s = str;
    CORBA_String_var result;

    if(addQuotes)
	result += '"';

    while(*s)
    {
	switch(*s)
	{
	case '\n':
	    result += "\\n";
	    break;

	case '\t':
	    result += "\\t";
	    break;

	case '\b':
	    result += "\\b";
	    break;

	case '\r':
	    result += "\\r";
	    break;

	case '\f':
	    result += "\\f";
	    break;

	case '\\':
	    result += "\\\\";
	    break;

	case '\'':
	    result += "\\'";
	    break;

	case '"':
	    result += "\\\"";
	    break;

	default:
	    if(isprint(*s))
		result += *s;
	    else
	    {
		CORBA_Char c = *s;
		char str[5];
		sprintf(str, "\\%.3o", c);
		result += str;
	    }
	    break;
	}
	
	s++;
    }

    if(addQuotes)
	result += '"';

    CORBA_string_free(str);
    str = result._retn();
}

// ----------------------------------------------------------------------
// Remove package from absolute name
// ----------------------------------------------------------------------

void
IdlJavaGenerator::removePackage(const char* package, char*& absolute)
{
    assert_nca(package, OBNCANullString);
    assert_nca(absolute, OBNCANullString);

/*
    if(strlen(absolute) > strlen(package) && strlen(package) > 0)
    {
	assert(package[strlen(package) - 1] != '.');

	if(strncmp(package, absolute, strlen(package)) == 0 &&
	   absolute[strlen(package)] == '.')
	{
	    char* a = CORBA_string_dup(absolute + strlen(package) + 1);
	    CORBA_string_free(absolute);
	    absolute = a;
	}
    }
*/
    if(strlen(absolute) > strlen(package) && strlen(package) > 0)
    {
	assert(package[strlen(package) - 1] != '.');

	const char* s = strrchr(absolute, '.');
	if(s)
	{
	    unsigned int len = s - absolute;
	    if(strlen(package) == len && strncmp(package, absolute, len) == 0)
	    {
		char* a = CORBA_string_dup(s + 1);
		CORBA_string_free(absolute);
		absolute = a;
	    }
	}
    }
}

// ----------------------------------------------------------------------
// Get union label sequence
// ----------------------------------------------------------------------

IdlStringSeq*
IdlJavaGenerator::getUnionLabelSeq(const char* package,
				   CORBA_TypeCode_ptr discType,
				   const IdlUnionMemberInfo& info)
{
    CORBA_TypeCode_var origDiscType = OBGetOrigType(discType);
    IdlStringSeq_var seq = new IdlStringSeq;
    CORBA_ULong i;

    switch(origDiscType -> kind())
    {
    case CORBA_tk_short:
    case CORBA_tk_ushort:

	for(i = 0 ; i < info.pLabels.length() ; i++)
	{
	    CORBA_String_var label = CORBA_string_dup("(short)");
	    label += info.pLabels[i];
	    seq -> append(label);
	}

	for(i = 0 ; i < info.nLabels.length() ; i++)
	{
	    CORBA_String_var label = CORBA_string_dup("(short)");
	    label += '-';
	    label += info.nLabels[i];
	    seq -> append(label);
	}

	break;
	
    case CORBA_tk_long:
    case CORBA_tk_ulong:

	for(i = 0 ; i < info.pLabels.length() ; i++)
	{
	    CORBA_String_var label = CORBA_string_dup("");
	    label += info.pLabels[i];
	    seq -> append(label);
	}

	for(i = 0 ; i < info.nLabels.length() ; i++)
	{
	    CORBA_String_var label = CORBA_string_dup("-");
	    label += info.nLabels[i];
	    seq -> append(label);
	}

	break;
	
    case CORBA_tk_char:

	for(i = 0 ; i < info.pLabels.length() ; i++)
	{
	    CORBA_String_var s;
	    if((char)info.pLabels[i] == '\0')
		s = CORBA_string_dup("\\0");
	    else
	    {
		s = CORBA_string_alloc(1);
		s[0] = (char)info.pLabels[i];
		s[1] = '\0';
		addEscapes(s.inout(), false);
	    }

	    CORBA_String_var label = CORBA_string_dup("'");
	    label += s;
	    label += '\'';
	    seq -> append(label);
	}

	assert(info.nLabels.length() == 0);
	
	break;
	
    case CORBA_tk_boolean:

	for(i = 0 ; i < info.pLabels.length() ; i++)
	{
	    CORBA_String_var label = CORBA_string_dup("");
	    label += info.pLabels[i];
	    seq -> append(label);
	}

	assert(info.nLabels.length() == 0);
	
	break;
	
    case CORBA_tk_enum:
    {
	CORBA_String_var disc = getTypeString(package, origDiscType);

	for(i = 0 ; i < info.pLabels.length() ; i++)
	{
	    CORBA_Identifier_var memberName =
		origDiscType -> member_name(info.pLabels[i]);
	    memberName = fixName(memberName);

	    CORBA_String_var label = disc;
	    label += "._";
	    label += memberName;
	    seq -> append(label);
	}

	assert(info.nLabels.length() == 0);

	break;
    }

    default:
	assert(false);
	break;
    }

    return seq._retn();
}

// ----------------------------------------------------------------------
// Get holder class for a union member
// ----------------------------------------------------------------------

char *
IdlJavaGenerator::getUnionMemberHolder(CORBA_TypeCode_ptr tc)
{
    CORBA_String_var result;

    switch(tc -> kind())
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
	assert(false);
	break;

    case CORBA_tk_short:
    case CORBA_tk_ushort:
	result = CORBA_string_dup("org.omg.CORBA.ShortHolder");
	break;

    case CORBA_tk_long:
    case CORBA_tk_ulong:
	result = CORBA_string_dup("org.omg.CORBA.IntHolder");
	break;

    case CORBA_tk_float:
	result = CORBA_string_dup("org.omg.CORBA.FloatHolder");
	break;

    case CORBA_tk_double:
	result = CORBA_string_dup("org.omg.CORBA.DoubleHolder");
	break;

    case CORBA_tk_boolean:
	result = CORBA_string_dup("org.omg.CORBA.BooleanHolder");
	break;

    case CORBA_tk_char:
	result = CORBA_string_dup("org.omg.CORBA.CharHolder");
	break;

    case CORBA_tk_octet:
	result = CORBA_string_dup("org.omg.CORBA.ByteHolder");
	break;

    case CORBA_tk_alias:
	assert(false);
	break;

    default:
	result = CORBA_string_dup("");
	break;
    }

    return result._retn();
}

// ----------------------------------------------------------------------
// Determines if the typecode is a primitive (or immutable) type
// ----------------------------------------------------------------------

bool
IdlJavaGenerator::isPrimitiveMemberType(CORBA_TypeCode_ptr tc)
{
    bool result;

    switch(tc -> kind())
    {
    case CORBA_tk_null:
    case CORBA_tk_void:
	assert(false);
	break;

    case CORBA_tk_short:
    case CORBA_tk_ushort:
    case CORBA_tk_long:
    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_string:
    case CORBA_tk_TypeCode:
    case CORBA_tk_Principal:
    case CORBA_tk_objref:
	result = true;
	break;

    default:
	result = false;
	break;
    }

    return result;
}

