package nxm.sys.inc;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;

/** ****** BCEL dependent version **********************
 *  In JDK 8+ the BCEL jar is needed to create KeyValuePairs
 *  lambda expressions
 *
 *  @author Jeanette McCall
 *  @since NeXtMidas 4.0.0
 */
interface KeyValuePairSwapBCEL {

  /** Gets the parameter names using Apache BCEL if available, otherwise try means that only works with JDK 8.
  *
  *  @param c    The class.
  *  @param m    The method.
  *  @param fn   The file name.
  *  @param path The file path (including name and extension)
  *  @throws ReflectiveOperationException On error.
  *  @since NextMidas 3.9.3 for NXM-3560 JDK breakage
  */
  @InternalUseOnly
 static String[] getParamNames (Class<?> c, Method m, String fn, String path) throws ReflectiveOperationException {
   try {
     int paramCount    = m.getParameterCount();
     InputStream inputStream   = c.getClassLoader().getResourceAsStream(path);
     org.apache.bcel.classfile.ClassParser classParser   = new org.apache.bcel.classfile.ClassParser(inputStream,fn);
     JavaClass parsedClass   = classParser.parse();
     org.apache.bcel.classfile.Method javaMethod    = parsedClass.getMethod(m);
     LocalVariableTable localVarTable = javaMethod.getLocalVariableTable();

     if (localVarTable != null) {
       String[] names      = new String[paramCount];
       int offset     = (Modifier.isStatic(m.getModifiers()))? 0 : 1;
       int namesIndex = 0;

       for (int i = offset; namesIndex < paramCount; i++) {
         // In Java 14 (and possibly other versions) this...
         //   MapKBT.toMap(str->Double.toString(num))
         // will have a local variable table similar to ["num",null,"str"]
         LocalVariable localVar = localVarTable.getLocalVariable(i,0);

         if (localVar != null) { // NXM-3675 allow for the local variable table to have changed and have null entries
           names[namesIndex++] = localVar.getName();
         }
       }
       return names;
     }
     else {
       throw new AssertionError("Class was not build with -g flag: "+c.getName());
     }
   }
   catch (Exception e) {
     throw new AssertionError("Unable to read: "+fn, e);
   }
 }

}
