/* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode:nil -*-
   jninativ.c -- Java Native Interface native method operations.
   Created: Chris Toshok <toshok@hungry.com>, 26-Jul-1997
*/
/*
  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) 1997, 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 "jniint.h"
#include "qop.h"

typedef struct natives {
  struct natives *prev;
  struct natives *next;

  jclass clazz;
  const JNINativeMethod *methods;
  jint nMethods;
} natives;

static natives *natives_list = NULL;

jint
JNIFUNC(RegisterNatives)(JNIEnv *env,
                         jclass clazz,
                         const JNINativeMethod *methods,
                         jint nMethods)
{
  int i = 0;
  HungryEnv *henv = JNIEnvToHEnv(env);
  HungryVM *hvm = henv->vm;
  natives *new_natives = (natives*)PR_CALLOC(sizeof(natives));
  ClazzFile *cls = jclass_to_clazzfile(henv, clazz);
  char *class_name = NULL;

  if (new_natives == NULL) return -1; /* XXX exception? */

  if (hvm->_verbose_flags & VERBOSE_JNI)
    class_name = getClassName(henv, cls);

  new_natives->clazz = clazz;
  new_natives->methods = methods;
  new_natives->nMethods = nMethods;

  for (i = 0; i < nMethods; i++)
    {
      jmethodID method;
      method = HVM_MethodFindStatic(henv, cls,
                                    methods[i].name, methods[i].signature);

      if (NULL == method)
        method = HVM_MethodFind(henv, cls,
                                methods[i].name, methods[i].signature);

      if (NULL == method)
        {
          HVM_ExceptionThrow(henv,
                             java_lang_NoSuchMethodError,
                             methods[i].name);
          return -1;
        }
      else
        {
          if (hvm->_verbose_flags & VERBOSE_JNI)
            printf ("[Registering JNI native method %s.%s]\n", class_name, method->name);

          method->native_func = (NativeFunc)methods[i].fnPtr;
          method->jni_call = PR_TRUE;
        }
    }

  PR_EnterMonitor(hvm->_mon);
  ENQUEUE(new_natives, natives_list);
  PR_ExitMonitor(hvm->_mon);

  return 0;
}

static natives *
find_natives(jclass clazz)
{
  natives *n;

  for (n = natives_list; n != NULL; n=n->next)
    {
      if (n->clazz == clazz)
        {
          return n;
        }
    }

  return NULL;
}

jint
JNIFUNC(UnregisterNatives)(JNIEnv *env,
                           jclass clazz)
{
  int i = 0;
  HungryEnv *henv = JNIEnvToHEnv(env);
  HungryVM *hvm = henv->vm;
  natives *n = find_natives(clazz);
  ClazzFile *cf = jclass_to_clazzfile(henv, n->clazz);

  if (!n) return -1; /* exception? */

  PR_EnterMonitor(hvm->_mon);
  UNQUEUE(n, natives_list);
  PR_ExitMonitor(hvm->_mon);

  for (i = 0; i < n->nMethods; i++)
    {
      jmethodID method;
      method = HVM_MethodFindStatic(henv, cf,
                                    n->methods[i].name,
                                    n->methods[i].signature);
      if (NULL == method)
        method = HVM_MethodFind(henv, cf,
                                n->methods[i].name,
                                n->methods[i].signature);

      if (NULL != method)
        method->native_func = NULL;
    }

  return 0;
}
