/* -*- Mode: C; c-file-style: "gnu" -*-
   japharJVMPlugin.cpp -- japhar's mozilla java runtime support
   Created: Chris Toshok <toshok@hungry.com>, 8-Aug-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) 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
*/
#include "config.h"

#include "jniint.h"
#include "japharJVMPlugin.h"
#include "japharJVMPluginInstance.h"

japharJVMPlugin::japharJVMPlugin()
{
  _vm = NULL;
  _env = NULL;
  _env_refcnt = 0;
  _factory_monitor = NULL;
  _browser = NULL;
}

/////////////////////////////////////////////////
// nsISupports
/////////////////////////////////////////////////

NS_IMPL_ADDREF(japharJVMPlugin)
  NS_IMPL_RELEASE(japharJVMPlugin)

  nsresult
japharJVMPlugin::QueryInterface(REFNSIID aIID,
				void** aInstancePtr)
{
  printf ("japharJVMPlugin::QueryInterface(this=%p)\n", this);
  if (NULL == aInstancePtr) {
    return NS_ERROR_NULL_POINTER;
  }

  *aInstancePtr = NULL;

  static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
  static NS_DEFINE_IID(kIJVMPluginIID, NS_IJVMPLUGIN_IID);
  static NS_DEFINE_IID(kIJVMConsoleIID, NS_IJVMCONSOLE_IID);
  static NS_DEFINE_IID(kIPluginIID, NS_IPLUGIN_IID);
  static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);

  if (aIID.Equals(kIJVMPluginIID)) {
    *aInstancePtr = (void*) ((nsIJVMPlugin*)this);
    AddRef();
    printf ("  + returning nsIJVMPlugin\n");
    return NS_OK;
  }
  if (aIID.Equals(kIPluginIID)) {
    *aInstancePtr = (void*) ((nsIPlugin*)this);
    AddRef();
    printf ("  + returning nsIPlugin\n");
    return NS_OK;
  }
  if (aIID.Equals(kIFactoryIID)) {
    *aInstancePtr = (void*) ((nsIFactory*)this);
    AddRef();
    printf ("  + returning nsIFactory\n");
    return NS_OK;
  }
  if (aIID.Equals(kISupportsIID)) {
    *aInstancePtr = (void*) ((nsISupports*)this);
    AddRef();
    printf ("  + returning nsISupports\n");
    return NS_OK;
  }

#if 0
  printf ("deferring to japharJVMConsole\n");
  if (_console == NULL)
    {
      japharJVMConsole *con = new japharJVMConsole(this);

      if (con)
	{
	  printf ("Calling queryinterface on the console\n");
	  nsresult ok = con->QueryInterface(kISupportsIID,
					    (void**)&_console);

	  if (ok != NS_OK)
	    _console = NULL;
	}
    }

  if (_console)
    {
      return _console->QueryInterface(aIID, aInstancePtr);
    }
  else
    {
#endif
      printf("  + returning NS_NOINTERFACE\n");
      return NS_NOINTERFACE;
#if 0
    }
#endif
}

/////////////////////////////////////////////////
// nsIFactory
/////////////////////////////////////////////////

nsresult
japharJVMPlugin::CreateInstance(nsISupports *aOuter,
				REFNSIID aIID,
				void **aResult)
{
  printf ("japharJVMPlugin::CreateInstance(this=%p)\n", this);

  if (aResult == NULL) {
    return NS_ERROR_NULL_POINTER;
  }

  *aResult = NULL;

  nsISupports* inst = new japharJVMPluginInstance(_browser);

  if (inst == NULL) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  nsresult res = inst->QueryInterface(aIID, aResult);

  if (res != NS_OK) {
    // We didn't get the right interface, so clean up
    delete inst;
  }

  static int initialized = 0;
  if (!initialized)
    {
      initialized = 1;
      StartupJVM();
    }

  return res;
}

nsresult
japharJVMPlugin::LockFactory(PRBool aLock)
{
  printf ("japharJVMPlugin::LockFactory(this=%p)\n", this);
  if (aLock)
    MONITOR_enter(_factory_monitor);
  else
    MONITOR_exit(_factory_monitor);
}

/////////////////////////////////////////////////
// nsIPlugin
/////////////////////////////////////////////////

/**
 * Initializes the plugin and will be called before any new instances are
 * created. It is passed browserInterfaces on which QueryInterface
 * may be used to obtain an nsIPluginManager, and other interfaces.
 *
 * @param browserInterfaces - an object that allows access to other browser
 * interfaces via QueryInterface
 * @result - NS_OK if this operation was successful
 */
nsresult
japharJVMPlugin::Initialize()
{
  printf ("japharJVMPlugin::Initialize(this=%p)\n", this);

#if 0
  _browser = browserInterfaces;
#endif

  if (!_factory_monitor)
    _factory_monitor = MONITOR_create();

  return NS_OK;
}
  
/**
 * Called when the browser is done with the plugin factory, or when
 * the plugin is disabled by the user.
 *
 * (Corresponds to NPP_Shutdown.)
 *
 * @result - NS_OK if this operation was successful
 */
nsresult
japharJVMPlugin::Shutdown(void)
{
  printf ("japharJVMPlugin::Shutdown(this=%p)\n", this);
  MONITOR_destroy(_factory_monitor);
  _factory_monitor = NULL;
  return NS_OK;
}

/**
 * Returns the MIME description for the plugin. The MIME description 
 * is a colon-separated string containg the plugin MIME type, plugin
 * data file extension, and plugin name, e.g.:
 *
 * "application/x-simple-plugin:smp:Simple LiveConnect Sample Plug-in"
 *
 * (Corresponds to NPP_GetMIMEDescription.)
 *
 * @param resultingDesc - the resulting MIME description 
 * @result - NS_OK if this operation was successful
 */
nsresult
japharJVMPlugin::GetMIMEDescription(const char* *resultingDesc)
{
  printf ("japharJVMPlugin::GetMIMEDescription(this=%p)\n", this);
  *resultingDesc = "application/x-java-vm:class:Japhar OJI Plugin";
  return NS_OK;\
		 }
  
/**
 * Returns the value of a variable associated with the plugin.
 *
 * (Corresponds to NPP_GetValue.)
 *
 * @param variable - the plugin variable to get
 * @param value - the address of where to store the resulting value
 * @result - NS_OK if this operation was successful
 */
nsresult
japharJVMPlugin::GetValue(nsPluginVariable variable, void *value)
{
  printf ("japharJVMPlugin::GetValue(this=%p)\n", this);
  return NS_OK;
}
  
/////////////////////////////////////////////////
// nsIJVMPlugin
/////////////////////////////////////////////////

nsresult
japharJVMPlugin::StartupJVM(void)
{
  JDK1_1InitArgs vm_args;

  printf ("japharJVMPlugin::StartupJVM(this=%p)\n", this);

  vm_args.version = 0x00010001;
  if (JNI_GetDefaultJavaVMInitArgs(&vm_args) != 0)
    {
      printf ("  + returning NS_ERROR_FAILURE\n");
      
      return NS_ERROR_FAILURE;
    }

  vm_args.enableVerboseClassLoading = JNI_TRUE;

  /*  printf ("  | initargs->classpathAdditions = '%s'\n", initargs->classpathAdditions);*/
  /*  vm_args.classpath = initargs->classpathAdditions;*/

  if (JNI_CreateJavaVM(&_vm, &_env,
		       &vm_args) == 0)
    {
      printf ("  + returning NS_OK\n");
      return NS_OK;
    }
  else
    {
      printf ("  + returning NS_ERROR_FAILURE(2)\n");
      return NS_ERROR_FAILURE;
    }

  /* set the security manager */
  jclass applet_security = _env->FindClass("sun/applet/AppletSecurity");
  jmethodID sec_mgr_ctor = _env->GetMethodID(applet_security, "<init>", "()V");
  jobject sec_manager = _env->NewObject(applet_security, sec_mgr_ctor);
  jclass system_cls = _env->FindClass("java/lang/System");
  jmethodID setSecurityManager = _env->GetStaticMethodID(system_cls, "setSecurityManager",
							 "(Ljava/lang/SecurityManager;)V");
  _env->CallStaticVoidMethod(system_cls,
			     setSecurityManager, sec_manager);
  if (_env->ExceptionOccurred())
    {
      _env->ExceptionDescribe();
      _env->ExceptionClear();
      return NS_ERROR_FAILURE;
    }
}
  
// Causes the JVM to append a new directory to its classpath.
// If the JVM doesn't support this operation, an error is returned.
nsresult
japharJVMPlugin::AddToClassPath(const char* dirPath)
{
  printf ("japharJVMPlugin::AddToClassPath(this=%p, dirPath=%s)\n", this, dirPath);
  return NS_ERROR_FAILURE; /* XXX for now. */
}
  
// Causes the JVM to remove a directory from its classpath.
// If the JVM doesn't support this operation, an error is returned.
nsresult
japharJVMPlugin::RemoveFromClassPath(const char* dirPath)
{
  printf ("japharJVMPlugin::RemoveFromClassPath(this=%p, dirPath=%s)\n", this, dirPath);
  return NS_ERROR_FAILURE; /* XXX for now. */
}
  
// Returns the current classpath in use by the JVM.
nsresult
japharJVMPlugin::GetClassPath(const char* *result)
{
  printf ("japharJVMPlugin::GetClassPath(this=%p)\n", this);

  *result = ((HungryJavaVM*)_vm)->_args.classpath;

  return NS_OK;
}

nsresult
japharJVMPlugin::GetJavaWrapper(JNIEnv* jenv,
				jint obj,
				jobject *jobj)
{
  printf ("japharJVMPlugin::GetJavaWrapper(this=%p)\n", this);
  return NS_ERROR_FAILURE;
}
  
/**
 * Gives time to the JVM from the main event loop of the browser. This is
 * necessary when there aren't any plugin instances around, but Java threads exist.
 */
nsresult
japharJVMPlugin::SpendTime(PRUint32 /*timeMillis*/)
{
  /* nothing, for now. */
  return NS_OK;
}

/**
 * This creates a new secure communication channel with Java. The second parameter,
 * nativeEnv, if non-NULL, will be the actual thread for Java communication.
 * Otherwise, a new thread should be created.
 * @param	proxyEnv		the env to be used by all clients on the browser side
 * @return	outSecureEnv	the secure environment used by the proxyEnv
 */
nsresult
japharJVMPlugin::CreateSecureEnv(JNIEnv* proxyJNI,
				 nsISecureEnv* *outSecureEnv)
{
  return NS_ERROR_FAILURE; /* XXX */
}
