//==================================================================================================
// J a v a                                                                                     Java
// R e f l e c t i o n
// J i r k M e t h o d
//                                                                                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 build the Jirk++ representation of a Java method. */

// Package //---------------------------------------------------------------------------------------
package bpp.java.reflection;

// Inportation //-----------------------------------------------------------------------------------
import java.lang.reflect.*;
import java.util.*;

@SuppressWarnings("unchecked")

// J i r k M e t h o d  Class //--------------------------------------------------------------------
/*CLASS JirkMethod */ /* Represents a method of a Java class and its Jirk++ representation. */
public class JirkMethod {
 //---------------------------------------------------------------------------------------Attributes
 protected JirkClass atArgumentS[]; // Types of the arguments of the method.
 protected JirkClass atClass;       // Class the method belongs to.
 protected Method    atMethod;      // Reference of the method.
 //-----------------------------------------------------------------------------------BuildArguments
 // Builds a list of the types of the method's arguments.
 protected void buildArguments() {
  Class lcClassS[] = atMethod.getParameterTypes();
  int   lcCounter  = 0;

  atArgumentS=new JirkClass[lcClassS.length];

  while (lcCounter<lcClassS.length) {
   atArgumentS[lcCounter]=new JirkClass(lcClassS[lcCounter]);
   ++lcCounter;
  }
 }
 //--------------------------------------------------------------------------------------Constructor
 /*METHOD JirkMethod */ /* Builds an object representing a given method of a given class. */
 public JirkMethod(JirkClass agClass,Method agMethod) {
  atClass=agClass;
  atMethod=agMethod;
  buildArguments();
 }
 //---------------------------------------------------------------------------------------------Name
 /*METHOD JirkMethod */ /* Returns the name of the method. */
 public String name() { return (atMethod.getName()); }
 //----------------------------------------------------------------------------------------Signature
 /*METHOD JirkMethod */ /* Returns the JNI signature of the method. */
 public String signature() {
  int    lcCounter = 0;
  String lcString  = "(";

  while (lcCounter<atArgumentS.length) {
   lcString+=atArgumentS[lcCounter].signature();
   lcCounter++;
  }

  return (lcString+")"+returnType().signature());
 }
 //------------------------------------------------------------------------------------ArgumentTypes
 /*METHOD JirkMethod */ /* Returns the types of the arguments of the method. */
 public JirkClass[] argumentTypes() { return (atArgumentS); }
 //---------------------------------------------------------------------------------------ReturnType
 /*METHOD JirkMethod */ /* Returns the type of the value returned by the method. */
 public JirkClass returnType() { return (new JirkClass(atMethod.getReturnType())); }
 //-----------------------------------------------------------------------------------------IsPublic
 /*METHOD JirkMethod */ /* Indicates if the method is public. */
 public boolean isPublic() { return (Modifier.isPublic(atMethod.getModifiers())); }
 //-----------------------------------------------------------------------------------------IsStatic
 /*METHOD JirkMethod */ /* Indicates if the method is static. */
 public boolean isStatic() { return (Modifier.isStatic(atMethod.getModifiers())); }
 //--------------------------------------------------------------------------------------Declaration
 /*METHOD JirkMethod */ /* Returns the Jirk++ declaration of the method. */
 public Vector declaration() {
  String lcString;

  String lcConst      = (isStatic() ? "" : " const");
  int    lcCounter    = 0;
  Vector lcLineS      = new Vector();
  String lcReturnType = (returnType().isPrimitive() ? returnType().fullName() : "jyObject");
  String lcStatic     = (isStatic() ? "static " : "");

  lcString=" public_property "+lcStatic+lcReturnType+" j_"+name()+"(";

  if (argumentTypes().length==0) lcString+="void";
  else {
   while (lcCounter<argumentTypes().length) {
    if (!argumentTypes()[lcCounter].isArray()) lcString+="const ";
    lcString+=argumentTypes()[lcCounter].fullName()+" &";
    ++lcCounter;
    if (lcCounter<argumentTypes().length) lcString+=",";
   }
  }

  lcString+=")"+lcConst+";";
  lcLineS.add(lcString);
  return (lcLineS);
 }
 //---------------------------------------------------------------------------------------Definition
 /*METHOD JirkMethod */ /* Returns the Jirk++ definition of the method. */
 public Vector definition() {
  String lcString;

  String lcClass      = atClass.shortName()+(isStatic() ? "::atC" : "::c")+"lassPointer()";
  String lcConst      = (isStatic() ? "" : " const");
  int    lcCounter    = 0;
  String lcInstance   = (isStatic() ? "Class" : "Instance");
  Vector lcLineS      = new Vector();
  String lcPointer    = (isStatic() ? lcClass : "jniPointer()");
  String lcReturnType = (returnType().isPrimitive() ? returnType().fullName() : "jyObject");

  lcString="property "+lcReturnType+" "+atClass.shortName()+"::j_"+name()+"(";

  if (argumentTypes().length==0) lcString+="void";
  else {
   while (lcCounter<argumentTypes().length) {
    if (!argumentTypes()[lcCounter].isArray()) lcString+="const ";
    lcString+=argumentTypes()[lcCounter].fullName()+" & agValue"+(lcCounter+1);
    ++lcCounter;
    if (lcCounter<argumentTypes().length) lcString+=",";
   }
  }

  lcLineS.add(lcString+")"+lcConst+" {");

  lcLineS.add(" safe_static jyMethod lcMethod = clContext().get"+lcInstance+"Method("+
              lcClass+",\""+name()+"\",\""+signature()+"\");");

  lcCounter=0;

  while (lcCounter<argumentTypes().length) {
   if (argumentTypes()[lcCounter].isArray())
    lcLineS.add(" agValue"+(1+lcCounter)+".synchronizeJavaSide();");

   ++lcCounter;
  }

  if (!returnType().javaName().equals("void")) lcString=" "+lcReturnType+" lcReturn = ";
  else lcString=" ";

  lcString+="clContext().call"+lcInstance+returnType().name()+"Method("+lcPointer+",lcMethod";

  lcCounter=0;
  while (lcCounter<argumentTypes().length) {
   if (argumentTypes()[lcCounter].isPrimitive()) lcString+=",agValue"+(1+lcCounter);
   else lcString+=",agValue"+(1+lcCounter)+".jniPointer()";

   ++lcCounter;
  }

  lcLineS.add(lcString+");");
  lcCounter=0;

  while (lcCounter<argumentTypes().length) {
   if (argumentTypes()[lcCounter].isArray())
    lcLineS.add(" agValue"+(1+lcCounter)+".synchronizeNativeSide();");

   ++lcCounter;
  }

  if (!returnType().javaName().equals("void")) lcLineS.add(" return (lcReturn);");
  lcLineS.add("}");

  return (lcLineS);
 }
}

// End //-------------------------------------------------------------------------------------------