//==================================================================================================
// J a v a                                                                                Interface
// A r r a y
//                                                                                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 multidimensional Java arrays in C++. */

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

// Guardian //--------------------------------------------------------------------------------------
#ifndef guJavaArray
#define guJavaArray

// Headers //---------------------------------------------------------------------------------------
#include <bpp/java/object.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  javaArray
#define private_area javaArray_private

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

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniJavaArray
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
/*MACROCOMMAND*/ /* Command to return an array to Java from a native method. */
#define return_array(prArray)                                              \
 return ((prArray.synchronizeJavaSide(),clContext().localObject(prArray))) \

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

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

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 template <tdArray>          class clArray;
 template <class prBaseType> class clBuffer;
}

namespace private_area {
 typedef std_map(tyPointer,tyCardinal) clBufferX;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {}

namespace private_area {
 template <class prObject> void     getJavaArray(tyPointer,jyArray,tyCardinal,ctContext &);
 template <class prObject> clString javaName(void);
 template <class prObject> jyArray  newJavaArray(tyCardinal,ctContext &);
 template <class prObject> void     setJavaArray(tyPointer,jyArray &,tyCardinal,ctContext &);
}

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erJavaArrayBufferNotRegistered;
 /* The Java array buffer is not registered. */
}

// Constants & Variables //-------------------------------------------------------------------------
extern_dynamic_constant(private,clBufferX,goBufferX,?);
extern_static_constant(private,clMutex,goMutex,?);

// A r r a y  Interface //--------------------------------------------------------------------------
namespace public_area {
 /*CLASS clArray */ /* Represents a multidimensional Java array reference. */
 template <tdArray> class clArray : public clAbstractArray<tuArray> {
  //-----------------------------------------------------------------------------------------Private
  private_property static clInitializerMutex atMutex1;
  private_property static clInitializerMutex atMutex2;

  private_property static void registerBuffer(clBuffer<prBaseType> *);
  private_property static void unregisterBuffer(clBuffer<prBaseType> *);

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

  private_property virtual void copy(const clArray<tuArray> &);
  private_property virtual void copy(ctObject &);
  private_property virtual void copy(jyObject);

  private_property clBuffer<prBaseType> * atBuffer;
  //------------------------------------------------------------------------------------------Public
  public_property constructor        clArray(tyPointer,tyCardinal,...);
  public_property constructor        clArray(const clArray<tuArray> &);
  public_property constructor        clArray(ctObject &);
  public_property constructor        clArray(jyObject=nil);
  public_property virtual destructor clArray(void);

  public_property static tyCardinal dimension(void);

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

  public_property prBaseType &       operator [] (jyInteger);
  public_property const prBaseType & operator [] (jyInteger) const;

  public_property clBuffer<prBaseType> &       operator () (jyInteger);
  public_property const clBuffer<prBaseType> & operator () (jyInteger) const;

  public_property clArray<tuArray> & operator = (const clArray<tuArray> &);
  public_property clArray<tuArray> & operator = (ctObject &);
  public_property clArray<tuArray> & operator = (jyObject);

  public_property void synchronizeJavaSide(void);
  public_property void synchronizeNativeSide(void);
 };
}

// B u f f e r  Interface //------------------------------------------------------------------------
namespace public_area {
 /*CLASS clBuffer */ /* Represents a buffer that contains a multidimensional array of elements. */
 template <class prBaseType> class clBuffer {
  //-----------------------------------------------------------------------------------------Private
  private_property constructor clBuffer(const clBuffer<prBaseType> &);
  private_property clBuffer & operator = (const clBuffer<prBaseType> &);

  private_property constructor clBuffer(void);

  private_property void build(tyPointer,const std_vector(tyCardinal) &);

  private_property tyCardinal atSize;
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clBuffer */ /* Raw data contained in the buffer. */
  read_only_attribute(tyPointer,atData,data);

  /*ATTRIBUTE clBuffer */ /* Number of dimensions of the array contained in the buffer. */
  read_only_attribute(tyCardinal,atDimension,dimension);

  public_property constructor clBuffer(tyPointer,tyCardinal,const std_vector(tyCardinal) &);
  public_property constructor clBuffer(jyArray,tyCardinal);
  public_property destructor  clBuffer(void);

  public_property jyInteger size(void) const;

  public_property prBaseType &       operator [] (jyInteger);
  public_property const prBaseType & operator [] (jyInteger) const;

  public_property clBuffer<prBaseType> &       operator () (jyInteger);
  public_property const clBuffer<prBaseType> & operator () (jyInteger) const;

  public_property void build(jyArray,ctContext &);
  public_property void buildJavaSide(jyArray &,tcString,ctContext &);
 };
}

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

// A r r a y  Inline //-----------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clArray */ /* Builds and copies a Java array reference. */
 template <tdArray> inline clArray<tuArray>::clArray(const clArray<tuArray> & agArray)
 : clAbstractArray<tuArray>(),atBuffer(nil) {
  copy(agArray);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clArray */ /* Builds and copies a Java array reference. */
 template <tdArray> inline clArray<tuArray>::clArray(ctObject & agObject)
 : clAbstractArray<tuArray>(),atBuffer(nil) {
  copy(agObject);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clArray */
 /* Builds and copies a Java array reference through its pointer in JNI. */
 template <tdArray> inline clArray<tuArray>::clArray(jyObject agPointer)
 : clAbstractArray<tuArray>(),atBuffer(nil) {
  copy(agPointer);
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clArray */ /* Destructs the Java array reference. */
 template <tdArray> inline clArray<tuArray>::~clArray(void) { unregisterBuffer(atBuffer); }
 //----------------------------------------------------------------------------------------Dimension
 /*METHOD clArray */ /* Returns the number of dimensions of the array. */
 template <tdArray> inline tyCardinal clArray<tuArray>::dimension(void)
 { return (prDimension); }
 //----------------------------------------------------------------------------------------ClassName
 /*METHOD clArray */ /* Returns the Java name of the class of the array reference. */
 template <tdArray> tcString clArray<tuArray>::className(void) const
 { return (clArray<tuArray>::atClassName()); }
 //-------------------------------------------------------------------------------------ClassPointer
 /*METHOD clArray */ /* Returns the pointer in JNI to the class of the array reference. */
 template <tdArray> jyClass clArray<tuArray>::classPointer(void) const
 { return (clArray<tuArray>::atClassPointer()); }
 //------------------------------------------------------------------------------------------IsArray
 /*METHOD clArray */ /* Indicates if the object reference is an array reference. */
 template <tdArray> inline tyBoolean clArray<tuArray>::isArray(void) const { return (true); }
 //---------------------------------------------------------------------------------------------Size
 /*METHOD clArray */ /* Returns the size of the first-level dimension of the array. */
 template <tdArray> inline jyInteger clArray<tuArray>::size() const
 { return (atBuffer->size()); }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clArray */
 /* Returns the element at a given position in the array (read-write version). This operation is
    valid only if the array has one dimension. */
 template <tdArray> inline prBaseType & clArray<tuArray>::operator [] (jyInteger agPosition)
 { return ((*atBuffer)[agPosition]); }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clArray */
 /* Returns the element at a given position in the array (read-only version). This operation is
    valid only if the array has one dimension. */
 template <tdArray>
 inline const prBaseType & clArray<tuArray>::operator [] (jyInteger agPosition) const
 { return ((*atBuffer)[agPosition]); }
 //--------------------------------------------------------------------------------------Operator ()
 /*METHOD clArray */
 /* Returns the subarray at a given position in the array (read-write version). This operation is
    valid only if the array has more than one dimension. */
 template <tdArray>
 inline clBuffer<prBaseType> & clArray<tuArray>::operator () (jyInteger agPosition)
 { return ((*atBuffer)(agPosition)); }
 //--------------------------------------------------------------------------------------Operator ()
 /*METHOD clArray */
 /* Returns the subarray at a given position in the array (read-only version). This operation is
    valid only if the array has more than one dimension. */
 template <tdArray>
 inline const clBuffer<prBaseType> & clArray<tuArray>::operator () (jyInteger agPosition) const
 { return ((*atBuffer)(agPosition)); }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clArray */ /* Copies a Java array reference. */
 template <tdArray>
 inline clArray<tuArray> & clArray<tuArray>::operator = (const clArray<tuArray> & agArray) {
  copy(agArray);
  return (*this);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clArray */ /* Copies a Java array reference. */
 template <tdArray>
 inline clArray<tuArray> & clArray<tuArray>::operator = (ctObject & agObject) {
  copy(agObject);
  return (*this);
 }
 //---------------------------------------------------------------------------------------Operator =
 /*METHOD clArray */ /* Copies a Java array reference through its pointer in JNI. */
 template <tdArray> inline clArray<tuArray> & clArray<tuArray>::operator = (jyObject agPointer) {
  copy(agPointer);
  return (*this);
 }
 //------------------------------------------------------------------------------SynchronizeJavaSide
 /*METHOD clArray */
 /* 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. */
 template <tdArray> inline void clArray<tuArray>::synchronizeJavaSide(void) {
  if (atBuffer!=nil)
   atBuffer->buildJavaSide((jyArray &)this->jniPointer(),className(),clContext());
 }
 //----------------------------------------------------------------------------SynchronizeNativeSide
 /*METHOD clArray */
 /* 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. */
 template <tdArray> inline void clArray<tuArray>::synchronizeNativeSide(void)
 { if (atBuffer!=nil) atBuffer->build((jyArray)this->jniPointer(),clContext()); }
}

// B u f f e r  Inline //---------------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------Constructor
 template <class prBaseType> inline clBuffer<prBaseType>::clBuffer(void)
 : atSize(0),atData(nil),atDimension(1) {}
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBuffer */
 /* Builds a buffer that contains a multidimensional array of elements, given the number of
    dimensions of the array and the size of each dimension. */
 template <class prBaseType>
 inline clBuffer<prBaseType>::clBuffer(tyPointer agArray,tyCardinal agDimension,
                                       const std_vector(tyCardinal) & agSizeS)
 : atSize(0),atData(nil),atDimension(agDimension) { build(agArray,agSizeS); }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clBuffer */
 /* Builds a buffer that contains a multidimensional array of elements that reflects a
    Java array. */
 template <class prBaseType>
 inline clBuffer<prBaseType>::clBuffer(jyArray agArray,tyCardinal agDimension)
 : atSize(0),atData(nil),atDimension(agDimension) { build(agArray,clContext()); }
 //---------------------------------------------------------------------------------------------Size
 /*METHOD clBuffer */
 /* Returns the size of the first-level dimension of the array contained in the buffer. */
 template <class prBaseType> inline jyInteger clBuffer<prBaseType>::size(void) const
 { return (jyInteger(atSize)); }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clBuffer */
 /* Returns the element at a given position in the array (read-write version). This operation is
    valid only if the array has one dimension. */
 template <class prBaseType>
 inline prBaseType & clBuffer<prBaseType>::operator [] (jyInteger agPosition)
 { return (((prBaseType *)atData)[agPosition]); }
 //--------------------------------------------------------------------------------------Operator []
 /*METHOD clBuffer */
 /* Returns the element at a given position in the array (read-only version). This operation is
    valid only if the array has one dimension. */
 template <class prBaseType>
 inline const prBaseType & clBuffer<prBaseType>::operator [] (jyInteger agPosition) const
 { return (((prBaseType *)atData)[agPosition]); }
 //--------------------------------------------------------------------------------------Operator ()
 /*METHOD clBuffer */
 /* Returns the subarray at a given position in the array (read-write version). This operation is
    valid only if the array has more than one dimension. */
 template <class prBaseType>
 inline clBuffer<prBaseType> & clBuffer<prBaseType>::operator () (jyInteger agPosition)
 { return (((clBuffer *)atData)[agPosition]); }
 //--------------------------------------------------------------------------------------Operator ()
 /*METHOD clBuffer */
 /* Returns the subarray at a given position in the array (read-only version). This operation is
    valid only if the array has more than one dimension. */
 template <class prBaseType> inline
 const clBuffer<prBaseType> & clBuffer<prBaseType>::operator () (jyInteger agPosition) const
 { return (((clBuffer *)atData)[agPosition]); }
}

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

namespace private_area {
 //-------------------------------------------------------------------------------------GetJavaArray
 template <class prObject>
 void getJavaArray(tyPointer agData,jyArray agArray,tyCardinal agSize,ctContext & agContext) {
  tyCardinal lcCounter = 0;

  while (lcCounter<agSize) {
   ((prObject *)agData)[lcCounter]=agContext.getObjectArrayElement(agArray,lcCounter);
   ++lcCounter;
  }
 }

 #define repeat_function(prType)                                                        \
  template <> inline void getJavaArray<prType>(tyPointer agData,jyArray agArray,        \
                                               tyCardinal agSize,ctContext & agContext) \
  { agContext.getPrimitiveArrayContent<prType>(agArray,agSize,(prType *)agData); }      \

 repeat_function(jyBoolean)
 repeat_function(jyByte)
 repeat_function(jyCharacter)
 repeat_function(jyShort)
 repeat_function(jyInteger)
 repeat_function(jyLong)
 repeat_function(jyFloat)
 repeat_function(jyDouble)

 #undef repeat_function
 //-----------------------------------------------------------------------------------------JavaName
 template <class prObject> clString javaName(void)
 { return (clString("L")+prObject().className()+";"); }

 template <> inline clString javaName<jyBoolean>(void) { return (clString("Z")); }
 template <> inline clString javaName<jyByte>(void) { return (clString("B")); }
 template <> inline clString javaName<jyCharacter>(void) { return (clString("C")); }
 template <> inline clString javaName<jyShort>(void) { return (clString("S")); }
 template <> inline clString javaName<jyInteger>(void) { return (clString("I")); }
 template <> inline clString javaName<jyLong>(void) { return (clString("J")); }
 template <> inline clString javaName<jyFloat>(void) { return (clString("F")); }
 template <> inline clString javaName<jyDouble>(void) { return (clString("D")); }
 //-------------------------------------------------------------------------------------NewJavaArray
 template <class prObject> inline jyArray newJavaArray(tyCardinal agSize,ctContext & agContext) {
  jyClass lcClass = agContext.getClass(prObject().className());
  jyArray lcArray = agContext.newObjectArray(lcClass,agSize);

  agContext.freeLocal(lcClass);
  return (lcArray);
 }

 #define repeat_function(prType)                                                           \
  template <> inline jyArray newJavaArray<prType>(tyCardinal agSize,ctContext & agContext) \
  { return (agContext.newPrimitiveArray<prType>(agSize)); }                                \

 repeat_function(jyBoolean)
 repeat_function(jyByte)
 repeat_function(jyCharacter)
 repeat_function(jyShort)
 repeat_function(jyInteger)
 repeat_function(jyLong)
 repeat_function(jyFloat)
 repeat_function(jyDouble)

 #undef repeat_function
 //-------------------------------------------------------------------------------------SetJavaArray
 template <class prObject>
 void setJavaArray(tyPointer agData,jyArray & agArray,tyCardinal agSize,ctContext & agContext) {
  jyClass lcClass;

  tyCardinal lcCounter = 0;

  if (agArray==nil) {
   lcClass=agContext.getClass(prObject().className());
   agArray=agContext.newObjectArray(lcClass,agSize);
   agContext.freeLocal(lcClass);
  }

  while (lcCounter<agSize) {
   agContext.setObjectArrayElement(agArray,lcCounter,
                                   ((prObject *)agData)[lcCounter].jniPointer());

   ++lcCounter;
  }
 }

 #define repeat_function(prType)                                                          \
  template <> inline void setJavaArray<prType>(tyPointer agData,jyArray & agArray,        \
                                               tyCardinal agSize,ctContext & agContext) { \
   if (agArray==nil) agArray=agContext.newPrimitiveArray<prType>(agSize);          \
   agContext.setPrimitiveArrayContent<prType>(agArray,agSize,(prType *)agData);           \
  }                                                                                       \

 repeat_function(jyBoolean)
 repeat_function(jyByte)
 repeat_function(jyCharacter)
 repeat_function(jyShort)
 repeat_function(jyInteger)
 repeat_function(jyLong)
 repeat_function(jyFloat)
 repeat_function(jyDouble)

 #undef repeat_function
}

// A r r a y  Implementation //---------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------------Attributes
 template <tdArray> clInitializerMutex clArray<tuArray>::atMutex1;
 template <tdArray> clInitializerMutex clArray<tuArray>::atMutex2;
 //-----------------------------------------------------------------------------------RegisterBuffer
 template <tdArray> void clArray<tuArray>::registerBuffer(clBuffer<prBaseType> * agBuffer) {
  safe_yes ( private_area::goMutex.lock(); )

  if (agBuffer!=nil) {
   if (private_area::goBufferX->count((tyPointer)agBuffer)==0)
    private_area::goBufferX->insert(std_make_pair((tyPointer)agBuffer,1));
   else
    ++((*private_area::goBufferX)[(tyPointer)agBuffer]);
  }

  safe_yes ( private_area::goMutex.release(); )
 }
 //---------------------------------------------------------------------------------UnregisterBuffer
 template <tdArray> void clArray<tuArray>::unregisterBuffer(clBuffer<prBaseType> * agBuffer) {
  method_name("array::unregisterBuffer");

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

   if (private_area::goBufferX->count((tyPointer)agBuffer)==0) {
    safe_yes ( private_area::goMutex.release(); )
    send_error(erJavaArrayBufferNotRegistered);
   }
   else if ((*private_area::goBufferX)[(tyPointer)agBuffer]==1) {
    private_area::goBufferX->erase((tyPointer)agBuffer);
    delete_object(agBuffer);
   }
   else --((*private_area::goBufferX)[(tyPointer)agBuffer]);

   safe_yes ( private_area::goMutex.release(); )
  }
 }
 //-----------------------------------------------------------------------------------BuildClassName
 template <tdArray> clString clArray<tuArray>::buildClassName(void) {
  clString lcName;

  tyCardinal lcCounter = 0;

  while (lcCounter<dimension()) {
   lcName+="[";
   ++lcCounter;
  }

  return (lcName+private_area::javaName<prBaseType>());
 }
 //----------------------------------------------------------------------------------------ClassName
 template <tdArray> tcString clArray<tuArray>::atClassName(void) {
  static tyCharacter lcClassName[2048];

  if (atMutex1.tryLock()) {
   standardBasicString::copy(lcClassName,buildClassName().data());
   atMutex1.release();
  }

  return (lcClassName);
 }
 //-------------------------------------------------------------------------------------ClassPointer
 template <tdArray> jyClass clArray<tuArray>::atClassPointer(void) {
  static jyClass lcClassPointer;

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

  return (lcClassPointer);
 }
 //---------------------------------------------------------------------------------------------Copy
 template <tdArray> void clArray<tuArray>::copy(const clArray<tuArray> & agArray) {
  clObject::copy(agArray);
  unregisterBuffer(atBuffer);
  atBuffer=agArray.atBuffer;
  registerBuffer(atBuffer);
 }
 //---------------------------------------------------------------------------------------------Copy
 template <tdArray> void clArray<tuArray>::copy(ctObject & agObject) {
  if (agObject.isArray()) {
   clObject::copy(agObject);
   unregisterBuffer(atBuffer);
   atBuffer=((const clArray<tuArray> &)agObject).atBuffer;
   registerBuffer(atBuffer);
  }
  else copy(agObject.jniPointer());
 }
 //---------------------------------------------------------------------------------------------Copy
 template <tdArray> void clArray<tuArray>::copy(jyObject agPointer) {
  clObject::copy(agPointer);
  unregisterBuffer(atBuffer);

  if (this->jniPointer()!=nil)
   atBuffer=new_object(clBuffer<prBaseType>((jyArray)this->jniPointer(),dimension()));
  else atBuffer=nil;

  registerBuffer(atBuffer);
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD clArray */
 /* Builds a Java array reference from a C++ array, given the number of dimensions of the array
    and the size of each dimension. */
 template <tdArray> clArray<tuArray>::clArray(tyPointer agArray,tyCardinal agFirstSize,...)
 : clAbstractArray<tuArray>(),atBuffer(nil) {
  jyClass                lcClass;
  clContext              lcContext;
  std_vector(tyCardinal) lcSizeS;

  tyCardinal lcCounter = dimension()-1;

  lcSizeS.push_back(agFirstSize);
  create_argument_list(agFirstSize);

  while (lcCounter>0) {
   lcSizeS.push_back(get_next_argument(tyCardinal));
   --lcCounter;
  }

  delete_argument_list;
  atBuffer=new_object(clBuffer<prBaseType>(agArray,dimension(),lcSizeS));
  registerBuffer(atBuffer);

  if (dimension()==1) this->atJniPointer=private_area::newJavaArray<prBaseType>(size(),lcContext);
  else {
   lcClass=lcContext.getClass(className()+1);
   this->atJniPointer=lcContext.newObjectArray(lcClass,size());
   lcContext.freeLocal(lcClass);
  }

  this->atJniPointer=clObject::registerObject(this->atJniPointer);
 }
}

// B u f f e r  Implementation //-------------------------------------------------------------------
namespace public_area {
 //--------------------------------------------------------------------------------------------Build
 template <class prBaseType>
 void clBuffer<prBaseType>::build(tyPointer agData,const std_vector(tyCardinal) & agSizeS) {
  typedef clBuffer<prBaseType> cpBuffer;

  tyCardinal lcCounter = 0;
  tyCardinal lcSize    = agSizeS[agSizeS.size()-atDimension];

  if (atData!=nil and lcSize!=atSize) {
   if (atDimension==1) delete_array((prBaseType *)atData);
   else delete_array((cpBuffer *)atData);
  }

  if (atDimension==1) {
   atData=(atSize==lcSize ? atData : (lcSize==0 ? nil : new_array(prBaseType,lcSize)));
   atSize=lcSize;

   if (agData!=nil) {
    while (lcCounter<atSize) {
     ((prBaseType *)atData)[lcCounter]=((prBaseType *)agData)[lcCounter];
     ++lcCounter;
    }
   }
  }
  else {
   atData=(atSize==lcSize ? atData : (lcSize==0 ? nil : new_array(cpBuffer,lcSize)));
   atSize=lcSize;

   while (lcCounter<atSize) {
    ((cpBuffer *)atData)[lcCounter].atDimension=atDimension-1;

    if (agData==nil) ((cpBuffer *)atData)[lcCounter].build(nil,agSizeS);
    else ((cpBuffer *)atData)[lcCounter].build(((prBaseType **)agData)[lcCounter],agSizeS);

    ++lcCounter;
   }
  }
 }
 //---------------------------------------------------------------------------------------Destructor
 /*METHOD clBuffer */ /* Destructs the buffer. */
 template <class prBaseType> clBuffer<prBaseType>::~clBuffer(void) {
  if (atData!=nil) {
   if (atDimension==1) delete_array((prBaseType *)atData);
   else delete_array((clBuffer<prBaseType> *)atData);
  }
 }
 //--------------------------------------------------------------------------------------------Build
 template <class prBaseType>
 void clBuffer<prBaseType>::build(jyArray agArray,ctContext & agContext) {
  typedef clBuffer<prBaseType> cpBuffer;

  jyArray lcArray;

  tyCardinal lcCounter = 0;
  tyCardinal lcSize    = (agArray==nil ? 0 : agContext.getArrayLength(agArray));

  if (atData!=nil and lcSize!=atSize) {
   if (atDimension==1) delete_array((prBaseType *)atData);
   else delete_array((cpBuffer *)atData);
  }

  if (atDimension==1) {
   atData=(atSize==lcSize ? atData : (lcSize==0 ? nil : new_array(prBaseType,lcSize)));
   atSize=lcSize;
   private_area::getJavaArray<prBaseType>(atData,agArray,atSize,agContext);
  }
  else {
   atData=(atSize==lcSize ? atData : (lcSize==0 ? nil : new_array(cpBuffer,lcSize)));
   atSize=lcSize;

   while (lcCounter<atSize) {
    ((cpBuffer *)atData)[lcCounter].atDimension=atDimension-1;
    lcArray=(jyArray)(agContext.getObjectArrayElement(agArray,lcCounter));
    ((cpBuffer *)atData)[lcCounter].build(lcArray,agContext);
    agContext.freeLocal(lcArray);
    ++lcCounter;
   }
  }
 }
 //------------------------------------------------------------------------------------BuildJavaSide
 template <class prBaseType>
 void clBuffer<prBaseType>::buildJavaSide(jyArray & agArray,tcString agClassName,
                                          ctContext & agContext) {
  typedef clBuffer<prBaseType> cpBuffer;

  jyArray lcArray;
  jyClass lcClass;

  tyCardinal lcCounter = 0;

  if (atDimension==1) private_area::setJavaArray<prBaseType>(atData,agArray,atSize,agContext);
  else {
   if (agArray==nil) {
    lcClass=agContext.getClass(agClassName+1);
    agArray=agContext.newObjectArray(lcClass,atSize);
    agContext.freeLocal(lcClass);
   }

   while (lcCounter<atSize) {
    lcArray=nil;
    ((cpBuffer *)atData)[lcCounter].buildJavaSide(lcArray,agClassName+1,agContext);
    agContext.setObjectArrayElement(agArray,lcCounter,lcArray);
    agContext.freeLocal(lcArray);
    ++lcCounter;
   }
  }
 }
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef tdArray
#undef tuArray
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// J a v a                                                                           Implementation
// A r r a y
//                                                                                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/array.cpp"

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

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

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  javaArray
#define private_area javaArray_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area {}

static_module_name("Java/Array");

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

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erJavaArrayBufferNotRegistered;
}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clBufferX,goBufferX);
static_constant(clMutex,goMutex);

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

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

// X X X  Implementation //-------------------------------------------------------------------------
namespace {}

// 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);

    erJavaArrayBufferNotRegistered.create("Java - The Java array buffer isn't registered.");

    goBufferX = new_object(clBufferX());

    environment_private::goJavaActivated=true;
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  try {
   environment_private::goJavaActivated=false;
   if (environment_private::goDisplay!=nil) environment_private::goDisplay->refresh();

   environment::informTermination(goModuleName);

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

   delete_object(goBufferX);
  }

  initializer_catch;
 }
}

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