//==================================================================================================
// J a v a                                                                                Interface
// O b j e c t
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. 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 (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides a class to manipulate Java objects and classes in C++. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "java/object.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guJavaObject
#define guJavaObject

// Headers //---------------------------------------------------------------------------------------
#include <bpp/java/context.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef JAVA_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  javaObject
#define private_area javaObject_private

namespace public_area  { /*NAMESPACE*/ using namespace javaContext; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniJavaObject
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
/*MACROCOMMAND*/ /* <CODE>nil</CODE> value for the Java object references. */
#define java_nil ::bpp::javaJni::jyObject(nil)

/*MACROCOMMAND*/ /* Command to return an object to Java from a native method. */
#define return_object(prObject)                                                  \
 return (java::clContext().localObject(static_cast<java::clObject &>(prObject))) \

/*MACROCOMMAND*/ /* Default error handling for java native methods. */
#define java_native_catch            \
 catch (ctError & agError) {         \
  outError(agError);                 \
  clearError();                      \
  return (false);                    \
 }                                   \
                                     \
 catch (tcString agMessage) {        \
  outError(agMessage);               \
  clearError();                      \
  return (false);                    \
 }                                   \
                                     \
 catch (ctException & agException) { \
  outException(agException);         \
  clearError();                      \
  return (false);                    \
 }                                   \
                                     \
 catch (...) {                       \
  outUnexpectedError();              \
  clearError();                      \
  return (false);                    \
 }                                   \
                                     \
 return (true);                      \

/*ALIAS*/
#define tdArray class prBaseType,tyCardinal prDimension //

/*ALIAS*/
#define tuArray prBaseType,prDimension //

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <class prBaseType,tyCardinal prDimension> class clAbstractArray;

 class clObject;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clObject ctObject;
}

namespace private_area {
 typedef std_map(jyObject,tyCardinal) clObjectX;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 inline tyBoolean operator == (ctObject &,ctObject &);
 inline tyBoolean operator == (ctObject &,jyObject);
 inline tyBoolean operator != (ctObject &,ctObject &);
 inline tyBoolean operator != (ctObject &,jyObject);
}

namespace private_area {}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erInvalidJavaObjectOperation; /* Invalid operation upon the Java object. */
 /*ERROR*/ extern_error erJavaObjectNotRegistered; /* The Java object is not registered. */
}

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clObjectX,goObjectX,?);
extern_static_constant(private,clMutex,goMutex,?);

// O b j e c t  Interface //------------------------------------------------------------------------
namespace public_area {
 /*CLASS clObject */ /* Represents a Java object reference. */
 class clObject {
  //-----------------------------------------------------------------------------------------Private
  private_property static clInitializerMutex atMutex;

  private_property static jyObject registerObject(jyObject);
  private_property static void     unregisterObject(jyObject);

  private_property static tcString atClassName(void);
  private_property static jyClass  atClassPointer(void);

  private_property virtual void copy(ctObject &);
  private_property virtual void copy(jyObject);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clObject */ /* Pointer to the object in JNI. */
  read_only_attribute(jyObject,atJniPointer,jniPointer);

  public_property constructor        clObject(void);
  public_property constructor        clObject(ctObject &);
  public_property constructor        clObject(jyObject);
  public_property virtual destructor clObject(void);

  public_property operator jyObject(void) const;

  public_property virtual tcString  className(void) const;
  public_property virtual jyClass   classPointer(void) const;
  public_property virtual tyBoolean isArray(void) const;

  public_property clObject & operator = (ctObject &);
  public_property clObject & operator = (jyObject);
 };
}

// A b s t r a c t A r r a y  Interface //----------------------------------------------------------
namespace public_area {
 /*CLASS clAbstractArray */
 /* Represents a multidimensional Java array reference. It is an abstract class. */
 template <tdArray> class clAbstractArray : public clObject {
  //------------------------------------------------------------------------------------------Public
  public_property constructor         clAbstractArray(void);
  public_property virtual destructor  clAbstractArray(void);

  /*AMETHOD clAbstractArray */
  /* Synchronizes the content of the array in the virtual machine with its buffer in C++,
     i.e. copies the content of the buffer into the Java array. Abstract method. */
  public_property virtual void synchronizeJavaSide(void) = 0;

  /*AMETHOD clAbstractArray */
  /* Synchronizes the buffer of the array in C++ with its content in the virtual machine,
     i.e. copies the content of the Java array into the buffer. Abstract method. */
  public_property virtual void synchronizeNativeSide(void) = 0;
 };
}

// Functions Inline //------------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Operator ==
 /*FUNCTION*/ /* Tests whether two Java object references are equal. */
 inline tyBoolean operator == (ctObject & agObject1,ctObject & agObject2)
 { return (agObject1.jniPointer()==agObject2.jniPointer()); }
 //--------------------------------------------------------------------------------------Operator ==
 /*FUNCTION*/ /* Tests whether two Java object references are equal. */
 inline tyBoolean operator == (ctObject & agObject1,jyObject agObject2)
 { return (agObject1.jniPointer()==agObject2); }
 //--------------------------------------------------------------------------------------Operator !=
 /*FUNCTION*/ /* Tests whether two Java object references are different. */
 inline tyBoolean operator != (ctObject & agObject1,ctObject & agObject2)
 { return (agObject1.jniPointer()!=agObject2.jniPointer()); }
 //--------------------------------------------------------------------------------------Operator !=
 /*FUNCTION*/ /* Tests whether two Java object references are different. */
 inline tyBoolean operator != (ctObject & agObject1,jyObject agObject2)
 { return (agObject1.jniPointer()!=agObject2); }
}

namespace private_area {}

// A b s t r a c t A r r a y  Inline //-------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clAbstractArray */ /* Builds a nil Java array reference. */
 template <tdArray> inline clAbstractArray<tuArray>::clAbstractArray(void) : clObject() {}
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clAbstractArray */ /* Destructs the Java array reference. */
 template <tdArray> inline clAbstractArray<tuArray>::~clAbstractArray(void) {}
}

// O b j e c t  Inline //---------------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------------Copy
 inline void clObject::copy(ctObject & agObject) {
  if (clContext().isInstance(agObject.jniPointer(),classPointer())) {
   unregisterObject(atJniPointer);
   atJniPointer=registerObject(agObject.jniPointer());
  }
  else send_inline_error(erInvalidJavaObjectOperation,"object::copy");
 }
 //---------------------------------------------------------------------------------------------Copy
 inline void clObject::copy(jyObject agPointer) {
  if (clContext().isInstance(agPointer,classPointer())) {
   unregisterObject(atJniPointer);
   atJniPointer=registerObject(agPointer);
  }
  else send_inline_error(erInvalidJavaObjectOperation,"object::copy");
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clObject */ /* Builds a nil Java object reference. */
 inline clObject::clObject(void) : atJniPointer(nil) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clObject */ /* Builds and copies a Java object reference. */
 inline clObject::clObject(ctObject & agObject) : atJniPointer(nil)
 { atJniPointer=registerObject(agObject.jniPointer()); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clObject */ /* Builds a Java object reference from its pointer in JNI. */
 inline clObject::clObject(jyObject agPointer) : atJniPointer(nil)
 { atJniPointer=registerObject(agPointer); }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clObject */ /* Destructs the Java object reference. */
 inline clObject::~clObject(void) {
  unregisterObject(atJniPointer);
  atJniPointer=nil;
 }
 //-------------------------------------------------------------------Conversion Operator (jyObject)
 /*METHOD clObject */ /* Converts a Java object reference into a JNI pointer. */
 inline clObject::operator jyObject(void) const { return (jniPointer()); }
 //----------------------------------------------------------------------------------------ClassName
 /*METHOD clObject */ /* Returns the Java name of the class of the object reference. */
 inline tcString clObject::className(void) const { return (clObject::atClassName()); }
 //-------------------------------------------------------------------------------------ClassPointer
 /*METHOD clObject */ /* Returns the pointer in JNI to the class of the object reference. */
 inline jyClass clObject::classPointer(void) const { return (clObject::atClassPointer()); }
 //------------------------------------------------------------------------------------------IsArray
 /*METHOD clObject */ /* Indicates if the object reference is an array reference. */
 inline tyBoolean clObject::isArray(void) const { return (false); }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clObject */ /* Copies a Java object reference. */
 inline clObject & clObject::operator = (ctObject & agObject) {
  copy(agObject);
  return (*this);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clObject */ /* Copies a Java object reference through its pointer in JNI. */
 inline clObject & clObject::operator = (jyObject agPointer) {
  copy(agPointer);
  return (*this);
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// J a v a                                                                           Implementation
// O b j e c t
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. 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 (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "java/object.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define JAVA_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/java/object.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  javaObject
#define private_area javaObject_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Java/Object");

// Initialization //--------------------------------------------------------------------------------
#undef iniJavaObject
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erInvalidJavaObjectOperation;
 static_error erJavaObjectNotRegistered;
}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clObjectX,goObjectX);
static_constant(clMutex,goMutex);

// Static Members //--------------------------------------------------------------------------------
namespace public_area { property clInitializerMutex clObject::atMutex; }

namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// O b j e c t  Implementation //-------------------------------------------------------------------
namespace public_area {
 //-----------------------------------------------------------------------------------RegisterObject
 property jyObject clObject::registerObject(jyObject agObject) {
  jyObject lcObject;

  if (agObject==nil) return (nil);

  safe_yes ( private_area::goMutex.lock(); )

  if (private_area::goObjectX->count(agObject)==0) {
   lcObject=clContext().globalObject(agObject);

   if (private_area::goObjectX->count(lcObject)==0)
    private_area::goObjectX->insert(std_make_pair(lcObject,1));
   else ++((*private_area::goObjectX)[lcObject]);

   safe_yes ( private_area::goMutex.release(); )
   return (lcObject);
  }
  else {
   ++((*private_area::goObjectX)[agObject]);
   safe_yes ( private_area::goMutex.release(); )
   return (agObject);
  }
 }
 //---------------------------------------------------------------------------------UnregisterObject
 property void clObject::unregisterObject(jyObject agObject) {
  method_name("object::unregisterObject");

  if (agObject!=nil) {
   safe_yes ( private_area::goMutex.lock(); )

   if (private_area::goObjectX->count(agObject)==0) {
    safe_yes ( private_area::goMutex.release(); )
    send_error(erJavaObjectNotRegistered);
   }
   else if ((*private_area::goObjectX)[agObject]==1) {
    private_area::goObjectX->erase(agObject);
    clContext().freeGlobal(agObject);
   }
   else --((*private_area::goObjectX)[agObject]);

   safe_yes ( private_area::goMutex.release(); )
  }
 }
 //----------------------------------------------------------------------------------------ClassName
 property tcString clObject::atClassName(void) { return ("java/lang/Object"); }
 //-------------------------------------------------------------------------------------ClassPointer
 property jyClass clObject::atClassPointer(void) {
  static jyClass lcClassPointer;

  if (atMutex.tryLock()) {
   lcClassPointer=clContext().globalClass(clContext().getClass(atClassName()));
   atMutex.release();
  }

  return (lcClassPointer);
 }
}

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    erInvalidJavaObjectOperation.create("Java - Invalid operation upon the Java object.");
    erJavaObjectNotRegistered.create("Java - The Java object isn't registered.");

    goObjectX = new_object(clObjectX());
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  try {
   environment::informTermination(goModuleName);

   if (goObjectX->size()>0) {
    environment::nextLine();
    environment::out("[!] Warning: Many Java references haven't been properly destroyed.",true,true);
    environment::nextLine();
   }

   delete_object(goObjectX);
  }

  initializer_catch;
 }
}

// End //-------------------------------------------------------------------------------------------
}