/* -*- Mode: C; c-file-style: "gnu" -*-
   objstrm.c -- native methods for java/io/ObjectStreamClass.
   Created: Chris Toshok <toshok@hungry.com>, 7-Mar-1998.
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "jni.h"
#include "ClazzFile.h"
#include "sig.h"
#include "objects.h"

#include <stdlib.h>
#include <string.h>

JNIEXPORT jint JNICALL
Java_java_io_ObjectStreamClass_getClassAccess(JNIEnv *env,
					      jclass cls,
					      jobject clazz)
{
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz);

  return clazz_cf->access_flags;
}

JNIEXPORT jobjectArray JNICALL
Java_java_io_ObjectStreamClass_getMethodSignatures(JNIEnv *env,
						   jclass cls,
						   jobject clazz)
{
  jobjectArray sig_array;
  jclass sig_array_class = (*env)->FindClass(env, "[Ljava/lang/String;");
  jclass clazz_clazz = (*env)->GetObjectClass(env, clazz);
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz_clazz);
  int i;

  sig_array = (*env)->NewObjectArray(env, clazz_cf->num_methods,
				     sig_array_class, NULL);

  for (i = 0; i < clazz_cf->num_methods; i++)
    {
      jstring method_sig = (*env)->NewStringUTF(env, clazz_cf->methods[i]->sig_str);

      method_sig = (*env)->NewGlobalRef(env, method_sig);
      (*env)->SetObjectArrayElement(env, sig_array,
				    i, method_sig);
    }

  sig_array = (*env)->NewGlobalRef(env, sig_array);

  return sig_array;
}

JNIEXPORT jint JNICALL
Java_java_io_ObjectStreamClass_getMethodAccess(JNIEnv *env,
					       jclass cls,
					       jobject clazz,
					       jstring methodName)
{
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz);
  int i;
  int access_flags = 0;
  const jbyte* methodName_str;

  methodName_str = (*env)->GetStringUTFChars(env, methodName, NULL);

  for (i = 0; i < clazz_cf->num_methods; i ++)
    {
      if (!strcmp(clazz_cf->methods[i]->name, (char*)methodName_str))
	{
	  access_flags = clazz_cf->methods[i]->access_flags;
	  break;
	}
    }
  
  (*env)->ReleaseStringUTFChars(env, methodName, methodName_str);

  /* should we throw an exception if the named method isn't present? */

  return access_flags;
}

JNIEXPORT jobjectArray JNICALL
Java_java_io_ObjectStreamClass_getFieldSignatures(JNIEnv *env,
						  jclass cls,
						  jobject clazz)
{
  jobjectArray sig_array;
  jclass sig_array_class = (*env)->FindClass(env, "[Ljava/lang/String;");
  jclass clazz_clazz = (*env)->GetObjectClass(env, clazz);
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz_clazz);
  int i;

  sig_array = (*env)->NewObjectArray(env, clazz_cf->num_fields,
				     sig_array_class, NULL);

  for (i = 0; i < clazz_cf->num_fields; i++)
    {
      jstring field_sig = (*env)->NewStringUTF(env, clazz_cf->fields[i]->sig_str);

      field_sig = (*env)->NewGlobalRef(env, field_sig);
      (*env)->SetObjectArrayElement(env, sig_array,
				    i, field_sig);
    }

  sig_array = (*env)->NewGlobalRef(env, sig_array);

  return sig_array;
}

JNIEXPORT jint JNICALL
Java_java_io_ObjectStreamClass_getFieldAccess(JNIEnv *env,
					      jclass cls,
					      jobject clazz,
					      jstring fieldName)
{
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz);
  int i;
  int access_flags = 0;
  const jbyte* fieldName_str;

  fieldName_str = (*env)->GetStringUTFChars(env, fieldName, NULL);

  for (i = 0; i < clazz_cf->num_fields; i ++)
    {
      if (!strcmp(clazz_cf->fields[i]->name, (char*)fieldName_str))
	{
	  access_flags = clazz_cf->fields[i]->access_flags;
	  break;
	}
    }
  
  (*env)->ReleaseStringUTFChars(env, fieldName, fieldName_str);

  /* should we throw an exception if the named field isn't present? */

  return access_flags;
}

JNIEXPORT jobjectArray JNICALL
Java_java_io_ObjectStreamClass_getFields0(JNIEnv *env,
					  jobject obj,
					  jobject clazz)
{
  ClazzFile *clazz_cf = jclass_to_clazzfile(env, clazz);
  jobjectArray field_array;
  jclass field_array_class = (*env)->FindClass(env, "[Ljava/io/ObjectStreamField;");
  jclass element_class = (*env)->FindClass(env, "java/io/ObjectStreamField");
  jmethodID element_ctor = (*env)->GetMethodID(env, element_class,
					       "<init>",
					       "(Ljava/lang/String;CILjava/lang/String;)V");
  int i;

  field_array = (*env)->NewObjectArray(env, clazz_cf->num_fields,
				       field_array_class, NULL);
  
  for (i = 0; i < clazz_cf->num_fields; i++)
    {
      jobject element;
      jstring element_name;
      jstring element_typeString;
      jchar element_type = 0; /* XXXX */
      
      element_name = (*env)->NewStringUTF(env, clazz_cf->fields[i]->name);
      element_name = (*env)->NewGlobalRef(env, element_name);

      element_typeString = (*env)->NewStringUTF(env, clazz_cf->fields[i]->sig_str);

      element_typeString = (*env)->NewGlobalRef(env, element_typeString);

      element = (*env)->NewObject(env, element_class, element_ctor,
				  element_name, element_type,
				  i, element_typeString);
      
      element = (*env)->NewGlobalRef(env, element);

      (*env)->SetObjectArrayElement(env, field_array,
				    i, element);
    }

  field_array = (*env)->NewGlobalRef(env, field_array);

  return field_array;
}

JNIEXPORT jlong JNICALL
Java_java_io_ObjectStreamClass_getSerialVersionUID(JNIEnv *env,
						   jclass cls,
						   jobject clazz)
{
  jclass clazz_cls = (*env)->GetObjectClass(env, clazz);
  jfieldID serialVersionUID_field;

  serialVersionUID_field = (*env)->GetStaticFieldID(env, clazz_cls, "serialVersionUID", "J");

  if (serialVersionUID_field)
    {
      return (*env)->GetStaticLongField(env, clazz_cls, serialVersionUID_field);
    }
  else
    {
      /* what are we supposed to do here?  throw an exception?  return -1? */
      return -1; /* XXXX */
    }
}

JNIEXPORT jboolean JNICALL
Java_java_io_ObjectStreamClass_hasWriteObject(JNIEnv *env,
					      jclass cls,
					      jobject clazz)
{
  /* I'm taking this method to mean "Does this given clazz have a
     writeObject method. */
  jboolean result;
  jclass clazz_cls = (*env)->GetObjectClass(env, clazz);
  jmethodID writeObject_method;

  writeObject_method = (*env)->GetMethodID(env, clazz_cls,
					   "writeObject",
					   "(Ljava/lang/Object;)V");

  if ((*env)->ExceptionOccurred(env))
    {
      (*env)->ExceptionClear(env);
      result = JNI_FALSE;
    }
  else if (writeObject_method == NULL)
    {
      result = JNI_FALSE;
    }
  else
    {
      result = JNI_TRUE;
    }
  
  return result;
}

/* JDK1.2 */
JNIEXPORT jboolean JNICALL
Java_java_io_ObjectStreamClass_hasStaticInitializer(JNIEnv *env,
						    jclass cls,
						    jobject obj)
{
  (*env)->FatalError(env, "Java_java_io_ObjectStreamClass_hasStaticInitializer not implemented");
  return JNI_FALSE; /* XXX */
}
