// **********************************************************************
//
// 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 HAVE_FSTREAM
#   include <fstream>
#else
#   include <fstream.h>
#endif

#include <GenHTML.h>

#ifdef HAVE_NO_STRCASECMP
#   define strcasecmp stricmp
#else
#   ifdef HAVE_STRINGS_H
#       include <strings.h> // On some platforms, strcasecmp is strings.h
#   endif
#endif

//
// The top-level file name (without ".html")
//
const char* IdlHTMLGenerator::top_ = "_top_";

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

int
IdlHTMLGenerator::genHTML(CORBA_Container_ptr container, IdlPrettyPrint& out)
{
    //
    // Get scope
    //
    CORBA_String_var scope;
    getScope(container, scope.out());

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

    CORBA_ULong i, j;

    //
    // Create name and description list
    //
    IdlStringSeq nameSeq;
    CORBA_Container::DescriptionSeq seq;
    for(i = 0; i < allSeq -> length() ; i++)
    {
	const char* name;

	switch(allSeq[i].kind)
	{
	case CORBA_dk_Attribute:
	{
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Constant:
	{
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Exception:
	{
	    CORBA_ExceptionDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Interface:
	{
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Module:
	{
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Operation:
	{
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	case CORBA_dk_Typedef:
	case CORBA_dk_Alias:
	case CORBA_dk_Struct:
	case CORBA_dk_Union:
	case CORBA_dk_Enum:
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = allSeq[i].value >>= desc;
	    assert(b);
	    name = desc -> name;
	    break;
	}

	default:
	    continue;
	}

	seq.append(allSeq[i]);
	nameSeq.append(name);
    }

    //
    // Sort name and description lists (bubblesort)
    //
    if(!noSort_)
    {
	for(i = 0 ; i < nameSeq.length() ; i++)
	{
	    for(j = i ; j < nameSeq.length() ; j++)
	    {
		if(!ignoreCase_)
		{
		    if(strcmp(nameSeq[i], nameSeq[j]) > 0)
		    {
			CORBA_String_var name = nameSeq[i]._retn();
			nameSeq[i] = nameSeq[j]._retn();
			nameSeq[j] = name._retn();

			CORBA_Container::Description desc = seq[i];
			seq[i] = seq[j];
			seq[j] = desc;
		    }
		}
		else
		{
		    if(strcasecmp(nameSeq[i], nameSeq[j]) > 0)
		    {
			CORBA_String_var name = nameSeq[i]._retn();
			nameSeq[i] = nameSeq[j]._retn();
			nameSeq[j] = name._retn();
			
			CORBA_Container::Description desc = seq[i];
			seq[i] = seq[j];
			seq[j] = desc;
		    }
		}
	    }
	}
    }

    bool first;

    // ------------------------------------------------------------
    // Pass 1: Index generation
    // ------------------------------------------------------------

    out << "\n<hr>";

    //
    // Module index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Module)
	{
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Module Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

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

	    if(first)
	    {
		out << "\n<h2>Interface Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Attribute index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Attribute)
	{
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Attribute Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Operation index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Operation)
	{
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);
	    
	    if(first)
	    {
		out << "\n<h2>Operation Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Constant index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Constant)
	{
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Constant Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Exception index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Exception)
	{
	    CORBA_ExceptionDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);
	    
	    if(first)
	    {
		out << "\n<h2>Exception Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Struct index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Struct)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Struct Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Union index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Union)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Union Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Enum index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Enum)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Enum Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    //
    // Alias index
    //
    first = true;
    for(i = 0 ; i < seq.length() ; i++)
    {
	if(seq[i].kind == CORBA_dk_Alias)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<h2>Alias Index</h2>\n<dl>";
		first = false;
	    }

	    intro(desc -> id, desc -> name, out);
	}
    }
    if(!first)
	out << "\n</dl>";

    // ------------------------------------------------------------
    // Pass 2: Description generation
    // ------------------------------------------------------------
     
    int status = 0;

    //
    // Module description
    //
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Module)
	{
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    //
	    // HTML file for the interface
	    //
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
	    CORBA_String_var path = fixAbsolute(absolute);
	    PrettyPrint out(prog_, path, outDir_);
	    if(!out.good())
		return 1;

	    //
	    // Get container
	    //
	    CORBA_Container_var cont =
		CORBA_Container::_narrow(seq[i].contained_object);
	    assert(!CORBA_is_nil(cont));

	    //
	    // Generate code
	    //
	    out << "\n<h1>Module " << absolute << "</h1>";

	    comment(desc -> id, out);

	    status = genHTML(cont, out);
	}
    }

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

	    //
	    // HTML file for the interface
	    //
	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
	    CORBA_String_var path = fixAbsolute(absolute);
	    PrettyPrint out(prog_, path, outDir_);
	    if(!out.good())
		return 1;

	    //
	    // Get container
	    //
	    CORBA_Container_var cont =
		CORBA_Container::_narrow(seq[i].contained_object);
	    assert(!CORBA_is_nil(cont));

	    //
	    // Generate code
	    //
            out << "\n<h1>Interface " << absolute << "</h1>";
	    out << "\n<dl>\n<dt>interface <b>" << desc -> name << "</b>";
 
            if(desc -> base_interfaces.length() > 0)
            {
                out << "\n<dt>inherits from ";
 
                for(j = 0 ; j < desc -> base_interfaces.length() ; j++)
                {
                    CORBA_ScopedName_var baseAbsolute =
			getAbsolute(desc -> base_interfaces[j]);

                    CORBA_String_var baseLink =
			getLink(desc -> base_interfaces[j]);

                    if(j > 0)
                        out << ", ";
 
                    out << "<a href=\"" << baseLink << "\">"
			<< baseAbsolute << "</a>";
                 }
	    }

	    out << "\n</dl>";

	    comment(desc -> id, out);
    
	    status = genHTML(cont, out);
 	}
    }

    //
    // Attribute Description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Attribute)
	{
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Attributes</h2>";
		first = false;
	    }

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << '\n';
	    if(desc -> mode == CORBA_ATTR_READONLY)
		out << "readonly ";

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

	    out << "attribute " << ret << ' ' << desc -> name << ';';

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Operation description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Operation)
	{
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);
	    
	    if(first)
	    {
		out << "\n<hr>\n<h2>Operations</h2>";
		first = false;
	    }

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << '\n';

	    if(desc -> mode == CORBA_OP_ONEWAY)
		out << "oneway ";

	    CORBA_String_var ret = getTypeString(scope, desc -> result);
	    
	    out << ret << ' ' << desc -> 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 s =
		    getTypeString(scope, desc -> parameters[j].type, tt,
				  desc -> parameters[j].name);

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

		out << s;
	    }

	    out << ')';

	    out.setIndent(indent);

	    if(desc -> contexts.length() > 0)
	    {
		out.inc();
		out << "\ncontext(";

		for(j = 0 ; j < desc -> contexts.length() ; j++)
		{
		    if(j > 0)
			out << ", ";

		    out << "\"" << desc -> contexts[j] << "\"";
		}

		out << ')';
		out.dec();
	    }

	    if(desc -> exceptions.length())
	    {
		out.inc();
		out << "\nraises(";

		unsigned int indent = out.getIndent();
		out.setIndent(out.getPos());
		    
		for(j = 0 ; j < desc -> exceptions.length() ; j++)
		{
		    if(j)
			out << ",\n";
			
		    CORBA_String_var str =
			getTypeString(scope, desc -> exceptions[j].type);
			
		    out << str;
		}
		
		out << ')';

		out.setIndent(indent);
		out.dec();
	    }

	    out << ';';

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Constant description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Constant)
	{
	    CORBA_ConstantDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Constants</h2>";
		first = false;
	    }

	    CORBA_ScopedName_var absolute = getAbsolute(desc -> id);
	    
	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    CORBA_String_var s = getTypeString(scope, desc -> type,
					       GetTypeNormal, desc -> name);

	    out << "\nconst " << s << " = ";

	    CORBA_TypeCode_var tc = desc -> value.type();
	    tc = OBGetOrigType(tc);

	    switch(tc -> kind())
	    {
	    case CORBA_tk_short:
	    {
		CORBA_Short v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_ushort:
	    {
		CORBA_UShort v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_long:
	    {
		CORBA_Long v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_ulong:
	    {
		CORBA_ULong v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_float:
	    {
		CORBA_Float v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_double:
	    {
		CORBA_Double v;
		CORBA_Boolean b = desc -> value >>= v;
		assert(b);
		out << v;
		break;
	    }

	    case CORBA_tk_string:
	    {
		char* v;
		CORBA_ULong l = tc -> length();
		CORBA_Any::to_string to(v, l);
		CORBA_Boolean b = desc -> value >>= to;
		assert(b);
		CORBA_String_var s = CORBA_string_dup(v);
		IdlAddEscapes(s.inout(), true);
		out << s;
		break;
	    }

	    case CORBA_tk_char:
	    {
		CORBA_Char v;
		CORBA_Boolean b = desc -> value >>= CORBA_Any::to_char(v);
		assert(b);
		CORBA_String_var s;
		if(v == '\0')
		    s = CORBA_string_dup("\\0");
		else
		{
		    s = CORBA_string_alloc(1);
		    s[0] = v;
		    s[1] = '\0';
		    IdlAddEscapes(s.inout(), false);
		}
		out << "'" << s << "'";
		break;
	    }

	    case CORBA_tk_boolean:
	    {
		CORBA_Boolean v;
		CORBA_Boolean b = desc -> value >>= CORBA_Any::to_boolean(v);
		assert(b);
		out << (v ? "TRUE" : "FALSE");
		break;
	    }

	    default:
		assert(false);
		break;
	    }

	    out << ';';

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Struct description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Struct)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Structs</h2>";
		first = false;
	    }

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << "\nstruct " << desc -> name;

	    out.start();

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

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

	    out.end();
	    out << ';';
		
	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Exception description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Exception)
	{
	    CORBA_ExceptionDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Exceptions</h2>";
		first = false;
	    }

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << "\nexception " << desc -> name;

	    out.start();

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

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

	    out.end();
	    out << ';';
		
	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Union description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Union)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Unions</h2>";
		first = false;
	    }

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

	    IdlUnionMemberInfoSeq_var infoSeq = IdlGetUnionInfo(desc -> type);

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << "\nunion " << desc -> name;
	    out << " switch(" << disc << ')';
	    out.start();
	    for(j = 0 ; j < infoSeq -> length() ; j++)
	    {
		IdlUnionMemberInfo& info = infoSeq[j];

		printUnionLabels(info, out, discType);

		if(!CORBA_is_nil(info.type))
		{
		    CORBA_String_var norm =
			getTypeString(scope, info.type, GetTypeNormal,
				      info.name);

		    out << ' ' << norm << ';';
		}
	    }

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

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Enum description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Enum)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Enums</h2>";
		first = false;
	    }

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << "\nenum " << desc -> name;
	    out.start();

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

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    //
    // Alias description
    //
    first = true;
    for(i = 0 ; i < seq.length() && status == 0 ; i++)
    {
	if(seq[i].kind == CORBA_dk_Alias)
	{
	    CORBA_TypeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(first)
	    {
		out << "\n<hr>\n<h2>Aliases</h2>";
		first = false;
	    }

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

	    CORBA_String_var norm = getTypeString(scope, origType,
						  GetTypeNormal,
						  desc -> name);

	    out << "\n<dl>\n<dt><b><a name=\"" << desc -> name << "\">"
		<< desc -> name << "</a></b></dt>\n<dd>";
	    out << "\n<pre>";

	    out << "\ntypedef " << norm << ';';

	    out << "\n</pre>";

	    comment(desc -> id, out);

	    out << "\n</dd>\n</dl>";
	}
    }

    return status;
}

// ----------------------------------------------------------------------
// IDL code generator constructor and destructor
// ----------------------------------------------------------------------

IdlHTMLGenerator::IdlHTMLGenerator(const char* prog,
				   CORBA_Repository_ptr rep,
				   const IdlCommentSeq& commentSeq,
				   const char* outDir,
				   bool noSort, bool ignoreCase)
    : prog_(prog),
      repository_(CORBA_Repository::_duplicate(rep)),
      commentSeq_(commentSeq),
      noSort_(noSort),
      ignoreCase_(ignoreCase),
      outDir_(outDir)
{
    keywordSeq_.append(keyException_);
    keywordSeq_.append(keyMember_);
    keywordSeq_.append(keyParam_);
    keywordSeq_.append(keyReturn_);
    keywordSeq_.append(keySee_);
    keywordSeq_.append(keySince_);
    keywordSeq_.append(keyAuthor_);
    keywordSeq_.append(keyVersion_);
}

// ----------------------------------------------------------------------
// Generate HTML code
// ----------------------------------------------------------------------

int
IdlHTMLGenerator::gen()
{
    PrettyPrint out(prog_, top_, outDir_);

    out << "\n<h1>Top-Level Module</h1>";

    return genHTML(repository_, out);
}
