/****************************************************************************/
/* Copyright (c) 2000 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : IdlToCpp.cc                                                   */
/* Author   : Tom O'Reilly                                                  */
/* Project  :                                                               */
/* Version  : 1.0                                                           */
/* Created  : 02/07/2000                                                    */
/* Modified :                                                               */
/* Archived :                                                               */
/****************************************************************************/
/* Modification History:                                                    */
/****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "IdlToCpp.h"
#include "Stack.h"

#define dprintf if (debug) fprintf
#define MethodReturnElementName "returnVal"

IdlToCpp::IdlToCpp(Interface *interface)
{
  _interface = interface;
}


IdlToCpp::~IdlToCpp()
{
}


int IdlToCpp::generateStubHeader(FILE *output)
{
  char buf[512];
  char *ptr;

  _level = 0;

  printGeneratorComment(output);

  sprintf(buf, "#ifndef __%s_H\n", stubName(_interface));
  print(output, buf);

  sprintf(buf, "#define __%s_H\n\n", stubName(_interface));
  print(output, buf);

  print(output, "#include \"TaskInterface.h\"\n\n");

  for (int k = 0; k < _interface->referencedInterfaces.size(); k++) {
    Interface *interface;
    _interface->referencedInterfaces.get(k, &interface);
    sprintf(buf, "#include \"%s.h\"\n", interface->name());     
    print(output, buf);
  }

  print(output, "\n");

  sprintf(buf, "#define %sServerName \"%sServer\"\n\n", 
	  _interface->name(), _interface->name());
  print(output, buf);

  printComments(output, _interface);

  // Declare class
  if (_interface->parentClass) {
    sprintf(buf, "class %s : public %s {\n\n", 
	    stubName(_interface), _interface->parentClass->name());
  }
  else {
    sprintf(buf, "class %s : public TaskInterface {\n\n", 
	    stubName(_interface));
  }

  print(output, buf);

  // Print class body
  _level++;

  int i, j;

  sprintf(buf, "friend class %s;\n\n", skeletonName(_interface));
  print(output, buf);

  print(output, "public:\n\n");

  if (_interface->structures.size())
    print(output, "// Forward declarations of public structures\n");

  Structure *structure;
  for (i = 0; i < _interface->structures.size(); i++) {
    _interface->structures.get(i, &structure);
    sprintf(buf, "%s %s;\n", typeMnem(StructureType), structure->name());
    print(output, buf);
  }
  print(output, "\n");

  // Print public enumerations
  Enumeration *enumeration;
  for (i = 0; i < _interface->enumerations.size(); i++) {
    _interface->enumerations.get(i, &enumeration);
    printEnumeration(output, enumeration);
  }
  print(output, "\n");

  // Print public Sequence typedefs
  Sequence *sequence;
  for (i = 0; i < _interface->sequences.size(); i++) {
    _interface->sequences.get(i, &sequence);

    printSequence(output, sequence);
  }
  print(output, "\n");

  // Print public structures
  for (i = 0; i < _interface->structures.size(); i++) {
    _interface->structures.get(i, &structure);
    printStructure(output, structure);
  }    

  // Declare constructors/destructor
  sprintf(buf, "%s(const char *name, int timeout = 10);\n\n",
	  stubName(_interface));

  print(output, buf);

  sprintf(buf, 
	  "%s(const char *name, const char *serverName, int timeout = 10);\n\n",
	  stubName(_interface));

  print(output, buf);

  sprintf(buf, "~%s();\n\n", stubName(_interface));
  print(output, buf);

  // Print public methods
  Method *method;
  Method::Argument *argument;

  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    printComments(output, method);

    // Generate method signature
    strcpy(buf, methodSignature(method));
    strcat(buf, ";\n\n");
    print(output, buf);
  }

  print(output, "\n");
  print(output, "protected:\n\n");

  // Determine starting value for "method codes" of this class.
  int startCode = 0;
  Context *context = _interface->parentClass;
  while (context) {
    Interface *interface = (Interface *)context;
    startCode += interface->methods.size(); 
    context = context->parentClass;
  }

  print(output, "// Message codes for each method\n");
  sprintf(buf, "enum %sMsgCode {\n", _interface->name());
  print(output, buf);
  _level++;

  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    sprintf(buf, "%s", msgCodeName(method));

    if (i == 0 && startCode != 0) {
      char *ptr = buf + strlen(buf);
      sprintf(ptr, " = %d", startCode);
    }

    if (i < _interface->methods.size() - 1)
      strcat(buf, ",");

    strcat(buf, "\n");

    print(output, buf);
  }
  _level--;
  print(output, "};\n\n");

  print(output, "// Define message structure for each method\n");
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    sprintf(buf, "struct %s : Request, Reply {\n", msgStructTypeName(method));

    print(output, buf);
    _level++;

    const char *typeName;

    if (method->returnObject->dataType() != VoidType) {

      sprintf(buf, "%s %s;\n", typeMnem(method->returnObject), 
					MethodReturnElementName);

      print(output, buf);
    }

    Method::Argument *argument;
    for (j = 0; j < method->arguments.size(); j++) {

      method->arguments.get(j, &argument);

      sprintf(buf, "%s %s;\n",
	      typeMnem(argument->dataDefinition), argument->name());

      print(output, buf);
    }
    _level--;
    print(output, "\n");
    sprintf(buf, "} %s;\n\n", msgStructInstanceName(method));
    print(output, buf);
  }
  
  // End of class
  _level--;
  print(output, "};\n\n");
  print(output, "#endif\n\n");
  return 0;
}


int IdlToCpp::generateStub(FILE *output)
{
  _level = 0;

  printGeneratorComment(output);

  char buf[512];
  sprintf(buf, "#include \"%s.h\"\n\n", stubName(_interface));
  print(output, buf);
  int i, j;

  // Print constructor and destuctor implementations
  sprintf(buf, "%s::%s(const char *name, int timeout)\n",
	  stubName(_interface), stubName(_interface));

  print(output, buf);

  const char *parentClassName;
  if (_interface->parentClass)
    parentClassName = _interface->parentClass->name();
  else
    parentClassName = "TaskInterface";

  sprintf(buf, "  :  %s(name, %sServerName, timeout)\n{\n", 
	  parentClassName, _interface->name());

  print(output, buf);

  _level++;
  // sprintf(buf, "setServerName(%sServerName);\n", _interface->name());
  //  print(output, buf);
  _level--;
  print(output, "}\n\n");


  sprintf(buf, 
	  "%s::%s(const char *name, const char *serverName, int timeout)\n",
	  stubName(_interface), stubName(_interface));

  print(output, buf);

  if (_interface->parentClass)
    parentClassName = _interface->parentClass->name();
  else
    parentClassName = "TaskInterface";

  sprintf(buf, "  :  %s(name, serverName, timeout)\n{\n", 
	  parentClassName);

  print(output, buf);

  print(output, "}\n\n");



  sprintf(buf, "%s::~%s()\n{\n}\n\n",
	  stubName(_interface), stubName(_interface));

  print(output, buf);

  // Print individual method implementations
  Method *method;
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    // Generate method signature
    strcpy(buf, methodSignature(method, stubName(_interface)));
    strcat(buf, "\n{\n");
    print(output, buf);
    _level++;


    Method::Argument *argument;

    // Copy input arguments to appropriate message fields
    print(output, "// Copy any input args to appropriate message fields\n");
    for (j = 0; j < method->arguments.size(); j++) {
      method->arguments.get(j, &argument);

      if (argument->io() == Method::Out)
	continue;

      if (passByReference(argument)) {

	switch (argument->dataDefinition->dataType()) {

	case StructureType:
	  
	  sprintf(buf, "memcpy(&%s.%s, %s, sizeof(%s));\n",
		  msgStructInstanceName(method), 
		  argument->name(),
		  argument->name(), 
		  typeMnem(argument->dataDefinition));
	  break;

	  
	default:
	  sprintf(buf, "%s.%s = *%s;\n", 
		  msgStructInstanceName(method),
		  argument->name(),
		  argument->name());

	}
      }
      else {
	if (argument->dataDefinition->dataType() == SequenceType) {
	  sprintf(buf, "memcpy(&%s.%s, %s, sizeof(%s));\n",
		  msgStructInstanceName(method), 
		  argument->name(),
		  argument->name(), 
		  typeMnem(argument->dataDefinition));
	}
	else {
	  sprintf(buf, "%s.%s = %s;\n", 
		  msgStructInstanceName(method),
		  argument->name(),
		  argument->name());
	}
      }

      print(output, buf);
    }

    print(output, "\n");

    // Set message code
    print(output, "// Set message code and send message\n");
    sprintf(buf, "%s.code = %s;\n\n", 
	    msgStructInstanceName(method),
	    msgCodeName(method));

    print(output, buf);

    sprintf(buf, "send(&%s, sizeof(%s),\n",
	    msgStructInstanceName(method),
	    msgStructTypeName(method));

    print(output, buf);

    sprintf(buf, "     &%s, sizeof(%s));\n\n",
	    msgStructInstanceName(method),
	    msgStructTypeName(method));

    print(output, buf);

    // Copy output fields of message to output args of method
    print(output, 
	  "// Copy any output fields of msg to appropriate output args\n");
    for (j = 0; j < method->arguments.size(); j++) {
      method->arguments.get(j, &argument);

      if (argument->io() == Method::In)
	continue;

      if (!primitiveType(argument->dataDefinition->dataType())) {
	sprintf(buf, "memcpy(%s, &%s.%s, sizeof(%s));\n",
		argument->name(), 
		msgStructInstanceName(method), 
		argument->name(),
		typeMnem(argument->dataDefinition));
      }
      else {
	sprintf(buf, "*%s = %s.%s;\n", 
		argument->name(),
		msgStructInstanceName(method),
		argument->name());
      }
      print(output, buf);
    }

    print(output, "\n");

    if (method->returnObject->dataType() != VoidType) {
      sprintf(buf, "return %s.%s;\n",
	      msgStructInstanceName(method),
	      MethodReturnElementName);

      print(output, buf);
    }
    else
      print(output, "return;\n");

    // Done with method
    _level--;
    print(output, "}\n\n\n");
  }
  return 0;
}


int IdlToCpp::generateSkeletonHeader(FILE *output)
{
  char buf[512];
  char *ptr;

  _level = 0;

  printGeneratorComment(output);

  sprintf(buf, "#ifndef __%s_H\n", skeletonName(_interface));
  print(output, buf);

  sprintf(buf, "#define __%s_H\n\n", skeletonName(_interface));
  print(output, buf);

  print(output, "#include \"TaskServer.h\"\n");

  sprintf(buf, "#include \"%s.h\"\n", stubName(_interface));
  print(output, buf);


  if (_interface->parentClass) {
    sprintf(buf, "#include \"%s_SK.h\"\n", _interface->parentClass->name());
    print(output, buf);
  }
  
  print(output, "\n");

  // Declare class

  if (_interface->parentClass) {
    sprintf(buf, "class %s : public %s_SK {\n\n", 
	    skeletonName(_interface), _interface->parentClass->name());
  }
  else {
    sprintf(buf, "class %s : public TaskServer {\n\n", 
	    skeletonName(_interface));
  }

  print(output, buf);

  // Print class body
  _level++;

  int i, j;

  print(output, "public:\n\n");

  // Print constructor and destuctor 
  print(output, "// Constructor for server with default name\n");
  sprintf(buf, "%s();\n\n", skeletonName(_interface));
  print(output, buf);
  print(output, "// Constructor for server with specific name\n");
  sprintf(buf, "%s(const char *serverName);\n\n", skeletonName(_interface));
  print(output, buf);

  sprintf(buf, "virtual ~%s();\n",  skeletonName(_interface));
  print(output, buf);

  print(output, "\n");
  print(output, "protected:\n\n");

  // Declare pure virtual methods
  print(output, "// These methods must be defined in subclass\n");
  Method *method;
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    // Generate method signature
    strcpy(buf, "virtual ");
    strcat(buf, methodSignature(method));
    strcat(buf, " = 0;\n");
    print(output, buf);
  }

  print(output, "\n");

  print(output, "// Declare callbacks corresponding to each method\n");
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    sprintf(buf, "Boolean %s(Request *request, int nReqBytes,\n", 
	    callbackName(method));

    print(output, buf);

    sprintf(buf, "               Reply **reply, int *nReplyBytes);\n\n"); 

    print(output, buf);
  }

  print(output, "\n");

  print(output, "// Message structure pointer for each method\n");
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    sprintf(buf, "%s::%s *%s;\n", 
	    stubName(_interface),
	    msgStructTypeName(method), 
	    msgStructInstanceName(method));

    print(output, buf);
  }

  print(output, "\n");

  print(output, "// Determine max bytes required for message buffer\n");
  print(output, "virtual size_t maxRequestBytes();\n\n");
  print(output, "// Allocate buffer for messages, set pointers, etc\n");
  print(output, "virtual void allocateBuffers();\n\n");

  print(output, "private:\n\n");
  print(output, "// Initializer method called by constructors\n");
  print(output, "int init();\n\n");

  // End of class declaration
  _level--;
  print(output, "};\n\n");
  print(output, "#endif\n\n");
  return 0;
}


int IdlToCpp::generateSkeleton(FILE *output)
{
  _level = 0;

  printGeneratorComment(output);

  print(output, "#include <stdlib.h>\n");
  char buf[512];
  char *ptr;
  sprintf(buf, "#include \"%s.h\"\n\n", skeletonName(_interface));
  print(output, buf);
  int i, j;

  char parentClassName[256];

  if (_interface->parentClass)
    sprintf(parentClassName, "%s_SK", _interface->parentClass->name());
  else
    strcpy(parentClassName, "TaskServer");

  // Print constructor implementation
  sprintf(buf, "%s::%s()\n",
	  skeletonName(_interface), skeletonName(_interface));

  print(output, buf);

  sprintf(buf, "  :  %s(%sServerName)\n", 
	  parentClassName, _interface->name());

  print(output, buf);
  print(output, "{\n");
  _level++;
  print(output, "init();\n");
  _level--;
  print(output, "}\n\n\n");

  sprintf(buf, "%s::%s(const char *serverName)\n",
	  skeletonName(_interface), skeletonName(_interface));

  print(output, buf);
  sprintf(buf, "  : %s(serverName)\n", parentClassName);
  print(output, buf);
  print(output, "{\n");
  _level++;
  print(output, "init();\n");
  _level--;
  print(output, "}\n\n\n");

  // Print destructor
  sprintf(buf, "%s::~%s()\n{\n}\n\n",
	  skeletonName(_interface), skeletonName(_interface));

  print(output, buf);

  // Print callbacks corresponding to each method
  Method *method;
  for (i = 0; i < _interface->methods.size(); i++) {

    _interface->methods.get(i, &method);

    sprintf(buf, 
	    "Boolean %s::%s(Request *request, int nReqBytes,\n",
	    skeletonName(_interface), callbackName(method));

    print(output, buf);

    print(output, 
	  "                          Reply **reply, int *nReplyBytes)\n");
 
    print(output, "{\n");
    _level++;
    print(output, "// Invoke method implementation\n");
    if (method->returnObject->dataType() != VoidType) {
      sprintf(buf, "%s->%s = \n", 
	      msgStructInstanceName(method),
	      MethodReturnElementName);

      print(output, buf);

      sprintf(buf, "   %s(", method->name());
    }
    else 
      sprintf(buf, "%s(", method->name());
    
    ptr = buf + strlen(buf);

    Method::Argument *argument;
    for (j = 0; j < method->arguments.size(); j++) {
      method->arguments.get(j, &argument);
      if (passByReference(argument)) 
	sprintf(ptr, "&%s->%s", 
		msgStructInstanceName(method), argument->name());
      else
	sprintf(ptr, "%s->%s", 
		msgStructInstanceName(method), argument->name());

      ptr += strlen(ptr);
      if (j < method->arguments.size() - 1) {
	strcat(ptr, ", ");
	ptr += strlen(ptr);
      }
    }
    strcpy(ptr, ");\n\n");
    
    print(output, buf);

    sprintf(buf, "*reply = %s;\n", msgStructInstanceName(method));
    print(output, buf);

    sprintf(buf, "*nReplyBytes = sizeof(%s::%s);\n",
	    stubName(_interface),
	    msgStructTypeName(method));

    print(output, buf);

    print(output, "return True;\n");

    // End of method
    _level--;
    print(output, "}\n\n\n");
  }

  // Function to initialize object
  sprintf(buf, "int %s::init()\n{\n", 
	  skeletonName(_interface));

  print(output, buf);

  _level++;

  // Add callbacks
  print(output, "// Add callbacks for each method\n");

  for (i = 0; i < _interface->methods.size(); i++) {
    _interface->methods.get(i, &method);

    sprintf(buf, "addCallback(%s::%s,\n", 
	    stubName(_interface), msgCodeName(method));

    print(output, buf);

    sprintf(buf, "           (CallbackPtr )%s::%s);\n\n",
	    skeletonName(_interface), callbackName(method));

    print(output, buf);
  }
  
  _level--;
  print(output, "return 0;\n");
  print(output, "}\n\n\n");


  // Function to determine maximum request size
  sprintf(buf, "size_t %s::maxRequestBytes()\n{\n", 
	  skeletonName(_interface));

  print(output, buf);

  _level++;

  //  print(output, "size_t nBytes = sizeof(TaskServer::Event);\n");
  sprintf(buf, "size_t nBytes = %s::maxRequestBytes();\n", parentClassName);
  print(output, buf);

  for (i = 0; i < _interface->methods.size(); i++) {
    _interface->methods.get(i, &method);
    sprintf(buf, "nBytes = max(nBytes, sizeof(%s::%s));\n",
	    stubName(_interface), msgStructTypeName(method));

    print(output, buf);
  }
  print(output, "return nBytes;\n");
  _level--;
  print(output, "}\n\n\n");

  // Function to set message buffers
  sprintf(buf, "void %s::allocateBuffers()\n{\n", 
	  skeletonName(_interface));

  print(output, buf);

  _level++;

  sprintf(buf, "%s::allocateBuffers();\n\n", parentClassName);
  print(output, buf);

  for (i = 0; i < _interface->methods.size(); i++) {
    _interface->methods.get(i, &method);

    sprintf(buf, "%s = (%s::%s *)_requestPtr;\n",
	    msgStructInstanceName(method), 
	    stubName(_interface),
	    msgStructTypeName(method));

    print(output, buf);
  }
  _level--;
  print(output, "}\n\n\n");
  return 0;
}


void IdlToCpp::print(FILE *output, const char *buf)
{
  // Indent
  for (int l = 0; l < _level; l++) {
    fprintf(output, "  ");
  }

  fprintf(output, buf);
}


const char *IdlToCpp::typeMnem(DataDefinition *dataDef)
{
  bool debug = false;

  if (primitiveType(dataDef->dataType()))
    return typeMnem(dataDef->dataType());

  static char typeBuf[256];

  // Aggregate data type.
  const int MaxContexts = 10;
  Stack<Context *> contextStack(MaxContexts);

  Context *context = dataDef->context;

  while (context) {

    dprintf(stderr, "IdlToCpp::typeMnem() - context \"%s\"\n",
	    context->name());

    // Push context onto stack
    if (contextStack.push(context) == -1) {
      // Stack is full
      fprintf(stderr, 
	      "Context stack overflow on data definition for %s\n",
	      dataDef->name());

      exit(1);
    }

    // Get containing context
    context = context->context;
  }

  char *ptr = typeBuf;

  // Fill string with contexts
  dprintf(stderr, "IdlToCpp::typeMnem() - %d contexts in def for %s\n", 
	  contextStack.size(), dataDef->name());

  for (int i = 0; i < contextStack.size(); ptr += strlen(ptr), i++) {
    context = contextStack.pop();
    dprintf(stderr, "context %d name: %s\n", i, context->name());
    sprintf(ptr, "%s::", context->name());
  }

  // Now fill in name
  sprintf(ptr, "%s", dataDef->name());

  dprintf(stderr, "IdlToCpp::typeMnem() - return %s\n", typeBuf);
  return typeBuf;
}


const char *IdlToCpp::typeMnem(DataType dataType)
{
  switch (dataType) {

  case FloatType:
    return "float";
    break;

  case DoubleType:
    return "double";
    break;

  case ShortType:
    return "short";
    break;

  case LongType:
    return "long";
    break;

  case UnsignedShortType:
    return "unsigned short";
    break;

  case UnsignedLongType:
    return "unsigned long";
    break;

  case CharType:
    return "char";
    break;

  case UnsignedCharType:
    return "unsigned char";
    break;

  case BooleanType:
    // Looks like Watcom doesn't properly support "bool" type.
    // So use our typedef'ed Boolean instead.
    return "Boolean";
    break;

  case VoidType:
    return "void";
    break;

  case StructureType:
    return "struct";
    break;

  case EnumerationType:
    return "enum";
    break;

  default:
    return "UnknownType!";
  }
}


const char *IdlToCpp::methodSignature(Method *method, 
				      const char *interfaceName)
{
  static char outbuf[256];

  const char *returnTypeName = typeMnem(method->returnObject);

  int i, j;
  
  if (interfaceName)
    sprintf(outbuf, "%s %s::%s(", 
	    returnTypeName,
	    interfaceName,
	    method->name());
  else
    sprintf(outbuf, "%s %s(", returnTypeName, method->name());

  char *ptr = outbuf + strlen(outbuf);

  Method::Argument *argument;
  for (j = 0; j < method->arguments.size(); j++) {

    if (j > 0) {
      // Append ',' to previous argument
      sprintf(ptr, ", ");
      ptr += strlen(ptr);
    }

    method->arguments.get(j, &argument);
    sprintf(ptr, "%s", declaration(argument));

    ptr += strlen(ptr);
  }
  strcat(ptr, ")");

  return outbuf;
}


const char *IdlToCpp::msgStructTypeName(Method *method)
{
  static char buf[256];
  if (method->overloadCount() == 0)
    sprintf(buf, "%sMsg", method->name());
  else
    sprintf(buf, "%s%02dMsg", method->name(), method->overloadCount());

  buf[0] = toupper(buf[0]);
  return buf;
}


const char *IdlToCpp::msgStructInstanceName(Method *method)
{
  static char buf[256];
  if (method->overloadCount() == 0)
    sprintf(buf, "_%sMsg", method->name());
  else
    sprintf(buf, "_%s%02dMsg", method->name(), method->overloadCount());

  return buf;
}


const char *IdlToCpp::msgCodeName(Method *method)
{
  static char buf[256];
  if (method->overloadCount() == 0)
    sprintf(buf, "%sMsgCode", method->name());
  else
    sprintf(buf, "%s%02dMsgCode", method->name(), method->overloadCount());

  buf[0] = toupper(buf[0]);
  return buf;
}


const char *IdlToCpp::callbackName(Method *method)
{
  static char buf[256];
  if (method->overloadCount() == 0)
    sprintf(buf, "%sCallback", method->name());
  else
    sprintf(buf, "%s%02dCallback", method->name(), method->overloadCount());

  return buf;
}


const char *IdlToCpp::stubName(Interface *interface)
{
  return interface->name();
}


const char *IdlToCpp::skeletonName(Interface *interface)
{
  static char buf[256];
  sprintf(buf, "%s_SK", interface->name());
  return buf;
}


bool IdlToCpp::passByReference(Method::Argument *argument)
{
  if (argument->dataDefinition->dataType() == SequenceType)
    return False;

  if (argument->dataDefinition->dataType() == StructureType ||
      argument->io() == Method::Out || argument->io() == Method::InOut)
    return true;
  else
    return false;
}

/*
Print declaration of specified argument. 

*/
const char *IdlToCpp::declaration(Method::Argument *argument)
{
  static char buf[256];

  sprintf(buf, "%s ", typeMnem(argument->dataDefinition));

  if (passByReference(argument))
    strcat(buf, "*");

  strcat(buf, argument->name());
  return buf;
}


void IdlToCpp::printComments(FILE *output, Base *base)
{
  char buf[512];
  Comment *comment;

  for (int i = 0; i < base->comments.size(); i++) {
    base->comments.get(i, &comment);
    sprintf(buf, "%s", comment->text());
    print(output, buf);
  }
}



void IdlToCpp::printGeneratorComment(FILE *output)
{
  print(output, "/*\n");
  print(output, "********************************************************\n");
  print(output, "Copyright 2000 MBARI.\n");
  print(output, "MBARI Proprietary Information. All rights reserved.\n");
  print(output, "NOTE: This file is automatically generated.\n");
  print(output, "DO NOT MODIFY.\n");
  print(output, "********************************************************\n");
  print(output, "*/\n\n");
}


void IdlToCpp::printStructure(FILE *output, Structure *structure)
{
  printComments(output, structure);

  char buf[256];

  sprintf(buf, "%s %s {\n", typeMnem(StructureType), structure->name());
  print(output, buf);

  _level++;

  int i;
  for (i = 0; i < structure->structures.size(); i++) {
    Structure *nestedStruct;
    structure->structures.get(i, &nestedStruct);
    printStructure(output, nestedStruct);
  }

  for (i = 0; i < structure->enumerations.size(); i++) {
    Enumeration *enumeration;
    structure->enumerations.get(i, &enumeration);
    printEnumeration(output, enumeration);
  }

  for (i = 0; i < structure->sequences.size(); i++) {
    Sequence *sequence;
    structure->sequences.get(i, &sequence);
    printSequence(output, sequence);
  }

  for (i = 0; i < structure->instances.size(); i++) {
    DataInstance *instance;
    structure->instances.get(i, &instance);
    printInstance(output, instance);
  }

  _level--;

  print(output, "};\n");
}


void IdlToCpp::printEnumeration(FILE *output, Enumeration *enumeration)
{
  // Print comments
  printComments(output, enumeration);

  char buf[256];

  sprintf(buf, "%s %s {\n", typeMnem(EnumerationType), enumeration->name());

  print(output, buf);
  _level++;
  Enumeration::Value *value;

  for (int j = 0; j < enumeration->values.size(); j++) {
    enumeration->values.get(j, &value);
    printComments(output, value);
    if (value->defaultValue())
      sprintf(buf, "%s", value->name());
    else
      sprintf(buf, "%s = %d", value->name(), value->value());

    if (j < enumeration->values.size() - 1)
      strcat(buf, ",");

    strcat(buf, "\n");
    print(output, buf);
  }
  _level--;
  print(output, "};\n\n");
}


void IdlToCpp::printSequence(FILE *output, Sequence *sequence)
{
  // Print comments
  printComments(output, sequence);

  char buf[256];

  sprintf(buf, "typedef %s %s[%d];\n",
	  typeMnem(sequence->element),
	  sequence->name(),
	  sequence->maxElements());

  print(output, buf);
}


void IdlToCpp::printInstance(FILE *output, DataInstance *instance)
{
  printComments(output, instance);

  char buf[256];

  sprintf(buf, "%s %s;\n", typeMnem(instance->dataDefinition), 
	  instance->name());

  print(output, buf);
}

