/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkParseJavaBeans.c

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include <stdio.h>
#include <string.h>
#include "vtkParse.h"
#include "vtkParseMain.h"
#include "vtkParseHierarchy.h"

HierarchyInfo *hierarchyInfo = NULL;
int numberOfWrappedFunctions = 0;
FunctionInfo *wrappedFunctions[1000];
extern FunctionInfo *currentFunction;

void output_temp(FILE *fp,int i)
{
  unsigned int aType =
    (currentFunction->ArgTypes[i] & VTK_PARSE_UNQUALIFIED_TYPE);

  /* ignore void */
  if (aType == VTK_PARSE_VOID)
    {
    return;
    }

  if (currentFunction->ArgTypes[i] == VTK_PARSE_FUNCTION)
    {
    fprintf(fp,"Object id0, String id1");
    return;
    }

  if ((aType == VTK_PARSE_CHAR_PTR) ||
      (aType == VTK_PARSE_STRING) ||
      (aType == VTK_PARSE_STRING_REF))
    {
    fprintf(fp,"String ");
    }
  else
    {
    switch ((aType & VTK_PARSE_BASE_TYPE) & ~VTK_PARSE_UNSIGNED)
      {
      case VTK_PARSE_FLOAT:   fprintf(fp,"double "); break;
      case VTK_PARSE_DOUBLE:   fprintf(fp,"double "); break;
      case VTK_PARSE_INT:   fprintf(fp,"int "); break;
      case VTK_PARSE_SHORT:   fprintf(fp,"int "); break;
      case VTK_PARSE_LONG:   fprintf(fp,"int "); break;
      case VTK_PARSE_ID_TYPE:   fprintf(fp,"int "); break;
      case VTK_PARSE_LONG_LONG:   fprintf(fp,"int "); break;
      case VTK_PARSE___INT64:   fprintf(fp,"int "); break;
      case VTK_PARSE_VOID:     fprintf(fp,"void "); break;
      case VTK_PARSE_SIGNED_CHAR:   fprintf(fp,"char "); break;
      case VTK_PARSE_CHAR:     fprintf(fp,"char "); break;
      case VTK_PARSE_OBJECT:     fprintf(fp,"%s ",currentFunction->ArgClasses[i]); break;
      case VTK_PARSE_UNKNOWN: return;
      }
    }

  fprintf(fp,"id%i",i);
  if (((aType & VTK_PARSE_INDIRECT) == VTK_PARSE_POINTER) &&
      (aType != VTK_PARSE_CHAR_PTR) &&
      (aType != VTK_PARSE_OBJECT_PTR))
    {
    fprintf(fp,"[]");
    }
}

void return_result(FILE *fp)
{
  switch (currentFunction->ReturnType & VTK_PARSE_UNQUALIFIED_TYPE)
    {
    case VTK_PARSE_FLOAT:
      fprintf(fp,"double ");
      break;
    case VTK_PARSE_VOID:
      fprintf(fp,"void ");
      break;
    case VTK_PARSE_CHAR:
      fprintf(fp,"char ");
      break;
    case VTK_PARSE_DOUBLE:
      fprintf(fp,"double ");
      break;
    case VTK_PARSE_INT:
    case VTK_PARSE_SHORT:
    case VTK_PARSE_LONG:
    case VTK_PARSE_ID_TYPE:
    case VTK_PARSE_LONG_LONG:
    case VTK_PARSE___INT64:
    case VTK_PARSE_UNSIGNED_CHAR:
    case VTK_PARSE_UNSIGNED_INT:
    case VTK_PARSE_UNSIGNED_SHORT:
    case VTK_PARSE_UNSIGNED_LONG:
    case VTK_PARSE_UNSIGNED_ID_TYPE:
    case VTK_PARSE_UNSIGNED_LONG_LONG:
    case VTK_PARSE_UNSIGNED___INT64:
      fprintf(fp,"int ");
      break;
    case VTK_PARSE_CHAR_PTR:
    case VTK_PARSE_STRING:
    case VTK_PARSE_STRING_REF:
      fprintf(fp,"String ");
      break;
    case VTK_PARSE_OBJECT_PTR:
      fprintf(fp,"%s ",currentFunction->ReturnClass);
      break;

      /* handle functions returning vectors */
      /* this is done by looking them up in a hint file */
    case VTK_PARSE_FLOAT_PTR:
    case VTK_PARSE_DOUBLE_PTR:
      fprintf(fp,"double[] ");
      break;
    case VTK_PARSE_INT_PTR:
    case VTK_PARSE_SHORT_PTR:
    case VTK_PARSE_LONG_PTR:
    case VTK_PARSE_ID_TYPE_PTR:
    case VTK_PARSE_LONG_LONG_PTR:
    case VTK_PARSE___INT64_PTR:
    case VTK_PARSE_SIGNED_CHAR_PTR:
    case VTK_PARSE_UNSIGNED_CHAR_PTR:
    case VTK_PARSE_UNSIGNED_INT_PTR:
    case VTK_PARSE_UNSIGNED_SHORT_PTR:
    case VTK_PARSE_UNSIGNED_LONG_PTR:
    case VTK_PARSE_UNSIGNED_ID_TYPE_PTR:
    case VTK_PARSE_UNSIGNED_LONG_LONG_PTR:
    case VTK_PARSE_UNSIGNED___INT64_PTR:
      fprintf(fp,"int[]  "); break;
    }
}

/* Check to see if two types will map to the same Java type,
 * return 1 if type1 should take precedence,
 * return 2 if type2 should take precedence,
 * return 0 if the types do not map to the same type */
static int CheckMatch(
  unsigned int type1, unsigned int type2, const char *c1, const char *c2)
{
  static unsigned int floatTypes[] = {
    VTK_PARSE_DOUBLE, VTK_PARSE_FLOAT, 0 };

  static unsigned int intTypes[] = {
    VTK_PARSE_UNSIGNED_LONG_LONG, VTK_PARSE_UNSIGNED___INT64,
    VTK_PARSE_LONG_LONG, VTK_PARSE___INT64, VTK_PARSE_ID_TYPE,
    VTK_PARSE_UNSIGNED_LONG, VTK_PARSE_LONG,
    VTK_PARSE_UNSIGNED_INT, VTK_PARSE_INT,
    VTK_PARSE_UNSIGNED_SHORT, VTK_PARSE_SHORT,
    VTK_PARSE_UNSIGNED_CHAR, VTK_PARSE_SIGNED_CHAR, 0 };

  static unsigned int stringTypes[] = {
    VTK_PARSE_CHAR_PTR, VTK_PARSE_STRING_REF, VTK_PARSE_STRING, 0 };

  static unsigned int *numericTypes[] = { floatTypes, intTypes, 0 };

  int i, j;
  int hit1, hit2;

  if ((type1 & VTK_PARSE_UNQUALIFIED_TYPE) ==
      (type2 & VTK_PARSE_UNQUALIFIED_TYPE))
    {
    if ((type1 & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT)
      {
      if (strcmp(c1, c2) == 0)
        {
        return 1;
        }
      return 0;
      }
    else
      {
      return 1;
      }
    }

  for (i = 0; numericTypes[i]; i++)
    {
    hit1 = 0;
    hit2 = 0;
    for (j = 0; numericTypes[i][j]; j++)
      {
      if ((type1 & VTK_PARSE_BASE_TYPE) == numericTypes[i][j])
        {
        hit1 = j+1;
        }
      if ((type2 & VTK_PARSE_BASE_TYPE) == numericTypes[i][j])
        {
        hit2 = j+1;
        }
      }
    if (hit1 && hit2 &&
        (type1 & VTK_PARSE_INDIRECT) == (type2 & VTK_PARSE_INDIRECT))
      {
      if (hit1 < hit2)
        {
        return 1;
        }
      else
        {
        return 2;
        }
      }
    }

  hit1 = 0;
  hit2 = 0;
  for (j = 0; stringTypes[j]; j++)
    {
    if ((type1 & VTK_PARSE_UNQUALIFIED_TYPE) == stringTypes[j])
      {
      hit1 = j+1;
      }
    if ((type2 & VTK_PARSE_UNQUALIFIED_TYPE) == stringTypes[j])
      {
      hit2 = j+1;
      }
    }
  if (hit1 && hit2)
    {
    if (hit1 < hit2)
      {
      return 1;
      }
    else
      {
      return 2;
      }
    }

  return 0;
}

/* have we done one of these yet */
int DoneOne()
{
  int i,j;
  int match;
  FunctionInfo *fi;

  for (i = 0; i < numberOfWrappedFunctions; i++)
    {
    fi = wrappedFunctions[i];

    if ((!strcmp(fi->Name,currentFunction->Name))
        &&(fi->NumberOfArguments == currentFunction->NumberOfArguments))
      {
      match = 1;
      for (j = 0; j < fi->NumberOfArguments; j++)
        {
        if (!CheckMatch(currentFunction->ArgTypes[j], fi->ArgTypes[j],
                        currentFunction->ArgClasses[j],fi->ArgClasses[j]))
          {
          match = 0;
          }
        }
      if (!CheckMatch(currentFunction->ReturnType, fi->ReturnType,
                      currentFunction->ReturnClass, fi->ReturnClass))
        {
        match = 0;
        }
      if (match) return 1;
      }
    }
  return 0;
}

static int isClassWrapped(const char *classname)
{
  HierarchyEntry *entry;

  if (hierarchyInfo)
    {
    entry = vtkParseHierarchy_FindEntry(hierarchyInfo, classname);

    if (entry == 0 ||
        vtkParseHierarchy_GetProperty(entry, "WRAP_EXCLUDE") ||
        !vtkParseHierarchy_IsTypeOf(hierarchyInfo, entry, "vtkObjectBase"))
      {
      return 0;
      }
    }

  return 1;
}

int checkFunctionSignature(ClassInfo *data)
{
  static unsigned int supported_types[] = {
    VTK_PARSE_VOID, VTK_PARSE_BOOL, VTK_PARSE_FLOAT, VTK_PARSE_DOUBLE,
    VTK_PARSE_CHAR, VTK_PARSE_UNSIGNED_CHAR, VTK_PARSE_SIGNED_CHAR,
    VTK_PARSE_INT, VTK_PARSE_UNSIGNED_INT,
    VTK_PARSE_SHORT, VTK_PARSE_UNSIGNED_SHORT,
    VTK_PARSE_LONG, VTK_PARSE_UNSIGNED_LONG,
    VTK_PARSE_ID_TYPE, VTK_PARSE_UNSIGNED_ID_TYPE,
    VTK_PARSE_LONG_LONG, VTK_PARSE_UNSIGNED_LONG_LONG,
    VTK_PARSE___INT64, VTK_PARSE_UNSIGNED___INT64,
    VTK_PARSE_VTK_OBJECT, VTK_PARSE_STRING,
    0
  };

  int i, j;
  int args_ok = 1;
  unsigned int rType =
    (currentFunction->ReturnType & VTK_PARSE_UNQUALIFIED_TYPE);
  unsigned int aType = 0;
  unsigned int baseType = 0;

  /* some functions will not get wrapped no matter what else */
  if (currentFunction->IsOperator ||
      currentFunction->ArrayFailure ||
      !currentFunction->IsPublic ||
      !currentFunction->Name)
    {
    return 0;
    }

  /* NewInstance and SafeDownCast can not be wrapped because it is a
     (non-virtual) method which returns a pointer of the same type as
     the current pointer. Since all methods are virtual in Java, this
     looks like polymorphic return type.  */
  if (!strcmp("NewInstance",currentFunction->Name))
    {
    return 0;
    }

  if (!strcmp("SafeDownCast",currentFunction->Name))
    {
    return 0;
    }

  /* The GetInput() in vtkMapper cannot be overriden with a
   * different return type, Java doesn't allow this */
  if (strcmp(data->Name, "vtkMapper") == 0 &&
      strcmp(currentFunction->Name, "GetInput") == 0)
    {
    return 0;
    }

  /* function pointer arguments for callbacks */
  if (currentFunction->NumberOfArguments == 2 &&
      currentFunction->ArgTypes[0] == VTK_PARSE_FUNCTION &&
      currentFunction->ArgTypes[1] == VTK_PARSE_VOID_PTR &&
      rType == VTK_PARSE_VOID)
    {
    return 1;
    }

  /* check to see if we can handle the args */
  for (i = 0; i < currentFunction->NumberOfArguments; i++)
    {
    aType = (currentFunction->ArgTypes[i] & VTK_PARSE_UNQUALIFIED_TYPE);
    baseType = (aType & VTK_PARSE_BASE_TYPE);

    for (j = 0; supported_types[j] != 0; j++)
      {
      if (baseType == supported_types[j]) { break; }
      }
    if (supported_types[j] == 0)
      {
      args_ok = 0;
      }

    if (baseType == VTK_PARSE_OBJECT)
      {
      if ((aType & VTK_PARSE_INDIRECT) != VTK_PARSE_POINTER)
        {
        args_ok = 0;
        }
      else if (!isClassWrapped(currentFunction->ArgClasses[i]))
        {
        args_ok = 0;
        }
      }

    if (aType == VTK_PARSE_VTK_OBJECT) args_ok = 0;
    if (((aType & VTK_PARSE_INDIRECT) != VTK_PARSE_POINTER) &&
        ((aType & VTK_PARSE_INDIRECT) != 0) &&
        (aType != VTK_PARSE_STRING_REF)) args_ok = 0;
    if (aType == VTK_PARSE_STRING_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_CHAR_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_INT_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_SHORT_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_LONG_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_ID_TYPE_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED_LONG_LONG_PTR) args_ok = 0;
    if (aType == VTK_PARSE_UNSIGNED___INT64_PTR) args_ok = 0;
    }

  baseType = (rType & VTK_PARSE_BASE_TYPE);

  for (j = 0; supported_types[j] != 0; j++)
    {
    if (baseType == supported_types[j]) { break; }
    }
  if (supported_types[j] == 0)
    {
    args_ok = 0;
    }

  if (baseType == VTK_PARSE_OBJECT)
    {
    if ((rType & VTK_PARSE_INDIRECT) != VTK_PARSE_POINTER)
      {
      args_ok = 0;
      }
    else if (!isClassWrapped(currentFunction->ReturnClass))
      {
      args_ok = 0;
      }
    }

  if (((rType & VTK_PARSE_INDIRECT) != VTK_PARSE_POINTER) &&
      ((rType & VTK_PARSE_INDIRECT) != 0) &&
      (rType != VTK_PARSE_STRING_REF)) args_ok = 0;
  if (rType == VTK_PARSE_STRING_PTR) args_ok = 0;

  /* eliminate unsigned char * and unsigned short * */
  if (rType == VTK_PARSE_UNSIGNED_INT_PTR) args_ok = 0;
  if (rType == VTK_PARSE_UNSIGNED_SHORT_PTR) args_ok = 0;
  if (rType == VTK_PARSE_UNSIGNED_LONG_PTR) args_ok = 0;
  if (rType == VTK_PARSE_UNSIGNED_ID_TYPE_PTR) args_ok = 0;
  if (rType == VTK_PARSE_UNSIGNED_LONG_LONG_PTR) args_ok = 0;
  if (rType == VTK_PARSE_UNSIGNED___INT64_PTR) args_ok = 0;

  /* make sure we have all the info we need for array arguments in */
  for (i = 0; i < currentFunction->NumberOfArguments; i++)
    {
    aType = (currentFunction->ArgTypes[i] & VTK_PARSE_UNQUALIFIED_TYPE);

    if (((aType & VTK_PARSE_INDIRECT) == VTK_PARSE_POINTER)&&
        (currentFunction->ArgCounts[i] <= 0)&&
        (aType != VTK_PARSE_VTK_OBJECT_PTR)&&
        (aType != VTK_PARSE_CHAR_PTR)) args_ok = 0;
    }

  /* if we need a return type hint make sure we have one */
  switch (rType)
    {
    case VTK_PARSE_FLOAT_PTR:
    case VTK_PARSE_VOID_PTR:
    case VTK_PARSE_DOUBLE_PTR:
    case VTK_PARSE_INT_PTR:
    case VTK_PARSE_SHORT_PTR:
    case VTK_PARSE_LONG_PTR:
    case VTK_PARSE_ID_TYPE_PTR:
    case VTK_PARSE_LONG_LONG_PTR:
    case VTK_PARSE___INT64_PTR:
    case VTK_PARSE_SIGNED_CHAR_PTR:
    case VTK_PARSE_BOOL_PTR:
    case VTK_PARSE_UNSIGNED_CHAR_PTR:
      args_ok = currentFunction->HaveHint;
      break;
    }

  /* make sure there isn't a Java-specific override */
  if (!strcmp("vtkObject",data->Name))
    {
    /* remove the original vtkCommand observer methods */
    if (!strcmp(currentFunction->Name,"AddObserver") ||
        !strcmp(currentFunction->Name,"GetCommand") ||
        (!strcmp(currentFunction->Name,"RemoveObserver") &&
         (currentFunction->ArgTypes[0] != VTK_PARSE_UNSIGNED_LONG)) ||
        ((!strcmp(currentFunction->Name,"RemoveObservers") ||
          !strcmp(currentFunction->Name,"HasObserver")) &&
         (((currentFunction->ArgTypes[0] != VTK_PARSE_UNSIGNED_LONG) &&
           (currentFunction->ArgTypes[0] !=
            (VTK_PARSE_CHAR_PTR|VTK_PARSE_CONST))) ||
          (currentFunction->NumberOfArguments > 1))) ||
        (!strcmp(currentFunction->Name,"RemoveAllObservers") &&
         (currentFunction->NumberOfArguments > 0)))
      {
      args_ok = 0;
      }
    }
  else if (!strcmp("vtkObjectBase",data->Name))
    {
    /* remove the special vtkObjectBase methods */
    if (!strcmp(currentFunction->Name,"PrintRevisions") ||
        !strcmp(currentFunction->Name,"Print"))
      {
      args_ok = 0;
      }
    }

  /* make sure it isn't a Delete or New function */
  if (!strcmp("Delete",currentFunction->Name) ||
      !strcmp("New",currentFunction->Name))
    {
    args_ok = 0;
    }

  return args_ok;
}

void outputFunction(FILE *fp, ClassInfo *data)
{
  unsigned int rType =
    (currentFunction->ReturnType & VTK_PARSE_UNQUALIFIED_TYPE);
  unsigned int aType = 0;
  unsigned int baseType;
  int i;
  /* beans */
  char *beanfunc;

  /* make the first letter lowercase for set get methods */
  beanfunc = strdup(currentFunction->Name);
  if (isupper(beanfunc[0])) beanfunc[0] = beanfunc[0] + 32;

  args_ok = checkFunctionSignature(data);

  if (currentFunction->IsPublic && args_ok &&
      strcmp(data->Name,currentFunction->Name) &&
      strcmp(data->Name, currentFunction->Name + 1))
    {
    /* make sure we haven't already done one of these */
    if (!DoneOne())
      {
      fprintf(fp,"\n  private native ");
      return_result(fp);
      fprintf(fp,"%s_%i(",currentFunction->Name,numberOfWrappedFunctions);

      for (i = 0; i < currentFunction->NumberOfArguments; i++)
        {
        if (i)
          {
          fprintf(fp,",");
          }
        output_temp(fp,i);

        /* ignore args after function pointer */
        if (currentFunction->ArgTypes[i] == VTK_PARSE_FUNCTION)
          {
          break;
          }
        }
      fprintf(fp,");\n");
      fprintf(fp,"  public ");
      return_result(fp);
      fprintf(fp,"%s(",beanfunc);

      for (i = 0; i < currentFunction->NumberOfArguments; i++)
        {
        if (i)
          {
          fprintf(fp,",");
          }
        output_temp(fp,i);

        /* ignore args after function pointer */
        if (currentFunction->ArgTypes[i] == VTK_PARSE_FUNCTION)
          {
          break;
          }
        }
      /* if not void then need return otherwise none */
      if (rType == VTK_PARSE_VOID)
        {
        fprintf(fp,")\n    { %s_%i(",currentFunction->Name,
                numberOfWrappedFunctions);
        }
      else
        {
        fprintf(fp,")\n    { return %s_%i(",currentFunction->Name,
                numberOfWrappedFunctions);
        }
      for (i = 0; i < currentFunction->NumberOfArguments; i++)
        {
        if (i)
          {
          fprintf(fp,",");
          }
        fprintf(fp,"id%i",i);

        /* ignore args after function pointer */
        if (currentFunction->ArgTypes[i] == VTK_PARSE_FUNCTION)
          {
          break;
          }
        }
      if ((currentFunction->NumberOfArguments == 1) &&
          (currentFunction->ArgTypes[0] == VTK_PARSE_FUNCTION)) fprintf(fp,",id1");

      /* stick in secret beanie code for set methods */
      if (rType == VTK_PARSE_VOID)
        {
        aType = (currentFunction->ArgTypes[0] & VTK_PARSE_UNQUALIFIED_TYPE);

        /* only care about set methods and On/Off methods */
        if (!strncmp(beanfunc,"set",3) &&
            currentFunction->NumberOfArguments == 1 &&
            (((aType & VTK_PARSE_INDIRECT) == 0 &&
              (aType & VTK_PARSE_UNSIGNED) == 0)||
             aType == VTK_PARSE_CHAR_PTR ||
             (aType & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT))
          {
          char prop[256];

          strncpy(prop,beanfunc+3,strlen(beanfunc)-3);
          prop[strlen(beanfunc)-3] = '\0';
          if (isupper(prop[0])) prop[0] = prop[0] + 32;
          fprintf(fp,");\n      changes.firePropertyChange(\"%s\",null,",prop);

          /* handle basic types */
          if ((aType == VTK_PARSE_CHAR_PTR) ||
              (aType == VTK_PARSE_STRING) ||
              (aType == VTK_PARSE_STRING_REF))
            {
            fprintf(fp," id0");
            }
          else
            {
            switch ((aType & VTK_PARSE_BASE_TYPE) & ~VTK_PARSE_UNSIGNED)
              {
              case VTK_PARSE_FLOAT:
              case VTK_PARSE_DOUBLE:   fprintf(fp," new Double(id0)"); break;
              case VTK_PARSE_INT:
              case VTK_PARSE_SHORT:
              case VTK_PARSE_LONG:   fprintf(fp," new Integer(id0)"); break;
              case VTK_PARSE_OBJECT:   fprintf(fp," id0"); break;
              case VTK_PARSE_CHAR:   /* not implemented yet */
              default:  fprintf(fp," null");
              }
            }
          }
        /* not a set method is it an On/Off method ? */
        else
          {
          if (!strncmp(beanfunc + strlen(beanfunc) - 2, "On",2))
            {
            /* OK we think this is a Boolean method so need to fire a change */
            char prop[256];
            strncpy(prop,beanfunc,strlen(beanfunc)-2);
            prop[strlen(beanfunc)-2] = '\0';
            fprintf(fp,");\n      changes.firePropertyChange(\"%s\",null,new Integer(1)",
                    prop);
            }
          if (!strncmp(beanfunc + strlen(beanfunc) - 3, "Off",3))
            {
            /* OK we think this is a Boolean method so need to fire a change */
            char prop[256];
            strncpy(prop,beanfunc,strlen(beanfunc)-3);
            prop[strlen(beanfunc)-3] = '\0';
            fprintf(fp,");\n      changes.firePropertyChange(\"%s\",null,new Integer(0)",
                    prop);
            }
          }
        }
      fprintf(fp,"); }\n");

      wrappedFunctions[numberOfWrappedFunctions] = currentFunction;
      numberOfWrappedFunctions++;
      }
    }
  free(beanfunc);
}

/* print the parsed structures */
void vtkParseOutput(FILE *fp, FileInfo *file_info)
{
  OptionInfo *options;
  ClassInfo *data;
  int i;

  if ((data = file_info->MainClass) == NULL)
    {
    return;
    }

  /* get the command-line options */
  options = vtkParse_GetCommandLineOptions();

  /* get the hierarchy info for accurate typing */
  if (options->HierarchyFileName)
    {
    hierarchyInfo = vtkParseHierarchy_ReadFile(options->HierarchyFileName);
    }

  fprintf(fp,"// java wrapper for %s object\n//\n",data->Name);
  fprintf(fp,"\npackage vtk;\n");

  /* beans */
  if (!data->NumberOfSuperClasses)
    {
    fprintf(fp,"import java.beans.*;\n");
    }

if (strcmp("vtkObject",data->Name))
    {
    fprintf(fp,"import vtk.*;\n");
    }
  fprintf(fp,"\npublic class %s",data->Name);
  if (strcmp("vtkObject",data->Name))
    {
    if (data->NumberOfSuperClasses)
      fprintf(fp," extends %s",data->SuperClasses[0]);
    }
  fprintf(fp,"\n{\n");

  fprintf(fp,"  public %s getThis%s() { return this;}\n\n",
          data->Name, data->Name+3);

  /* insert function handling code here */
  for (i = 0; i < data->NumberOfFunctions; i++)
    {
    currentFunction = data->Functions[i];
    outputFunction(fp, data);
    }

if (!data->NumberOfSuperClasses)
    {
    fprintf(fp,"\n  public %s() { this.VTKInit();};\n",data->Name);
    fprintf(fp,"  protected int vtkId = 0;\n");

    /* beans */
    fprintf(fp,"  public void addPropertyChangeListener(PropertyChangeListener l)\n    {\n");
    fprintf(fp,"    changes.addPropertyChangeListener(l);\n    }\n");
    fprintf(fp,"  public void removePropertyChangeListener(PropertyChangeListener l)\n    {\n");
    fprintf(fp,"    changes.removePropertyChangeListener(l);\n    }\n");
    fprintf(fp,"  protected PropertyChangeSupport changes = new PropertyChangeSupport(this);\n\n");

    /* if we are a base class and have a delete method */
    if (data->HasDelete)
      {
      fprintf(fp,"\n  public native void VTKDelete();\n");
      fprintf(fp,"  protected void finalize() { this.VTKDelete();};\n");
      }
    }
  if ((!data->IsAbstract)&&
      strcmp(data->Name,"vtkDataWriter") &&
      strcmp(data->Name,"vtkPointSet") &&
      strcmp(data->Name,"vtkDataSetSource")
      )
    {
    fprintf(fp,"  public native void   VTKInit();\n");
    }
  if (!strcmp("vtkObject",data->Name))
    {
    fprintf(fp,"  public native String Print();\n");
    }
  fprintf(fp,"}\n");
}

