import java.lang.reflect.*;
import java.util.*;
import java.io.*;

import org.apache.bcel.Repository;
import org.apache.bcel.classfile.*;

import com.techtrader.modules.tools.bytecode.*;


public class GetParamNamesBench2 {
  public static void main(String[] args) throws Exception {
    Class cls;
    java.lang.reflect.Method[] methods;
    Date d1, d2;
    String[] result;
    int time, i;
    boolean printout = false;
    HashMap ttClassCache;
    BCClass bclass;
    
    if(args.length != 1) {
      System.out.println("Please supply a class name!");
      System.exit(0);
    }
    
    cls = Class.forName(args[0]);
    methods = cls.getMethods();
    System.out.println("Number of methods: " + methods.length);
    
    // bcel
    d1 = new Date();
    for(i = 0; i < methods.length; i++) {
      result = executeBcel(methods[i]);
      if(printout)
        printResult(methods[i], result);
    }
    d2 = new Date();
    System.out.println("bcel: " + (d2.getTime() - d1.getTime()) + "ms");
    
    if(printout)
      System.out.println();
    
    // tt-bytecode
    ttClassCache = new HashMap();
    d1 = new Date();
    for(i = 0; i < methods.length; i++) {
      cls = methods[i].getDeclaringClass();
      bclass = (BCClass)ttClassCache.get(cls);
      if(bclass == null) {
        try {
          bclass = new BCClass(cls);
          ttClassCache.put(cls, bclass);
        } catch (IOException e) {
          if(printout)
            printResult(methods[i], null);
          continue;
        }
      }
      
      result = executeTTbytecode(bclass, methods[i]);
      if(printout)
        printResult(methods[i], result);
    }
    d2 = new Date();
    System.out.println("tt-bytecode: " + (d2.getTime() - d1.getTime()) + "ms");
    
  }
  
  private static String[] executeBcel(java.lang.reflect.Method reflectMethod) throws Exception {
    Class cls;
    JavaClass javaClass;
    org.apache.bcel.classfile.Method [] methods;
    org.apache.bcel.classfile.Method method;
    LocalVariableTable localVarTable;
    org.apache.bcel.classfile.LocalVariable[] localVars;
    org.apache.bcel.classfile.LocalVariable localVar;
    String[] result = null;
    int i, j, numParams;
    
    numParams = reflectMethod.getParameterTypes().length;
    if (numParams == 0)
      return null;
    
    cls = reflectMethod.getDeclaringClass();
    javaClass = Repository.lookupClass(cls.getName());
    if(javaClass == null)
      throw new Exception("bcel could not load class!");
    
    methods = javaClass.getMethods();
    
    for(i = 0; i < methods.length; i++) {
      method = methods[i];
      
      if(method.getName().equals(reflectMethod.getName())) {
        localVarTable = method.getLocalVariableTable();
        
        if(localVarTable != null) {
          localVars = localVarTable.getLocalVariableTable();
          
          //          if(localVars.length == numParams) {
          result = new String[numParams + 1];
          
          for(j = 0; j < localVars.length; j++) {
            localVar = localVars[j];
            
            if(localVar.getIndex() <= numParams && ! localVar.getName().equals("this"))
              result[localVar.getIndex()] = localVar.getName();
          }
          //          }
        }
      }
    }
    return(result);
  } // executeBcel
  
  private static String[] executeTTbytecode(BCClass bclass, java.lang.reflect.Method reflectMethod) throws Exception {
    Class cls;
    BCMethod bmeth;
//    BCClass bclass;
    com.techtrader.modules.tools.bytecode.Code code;
    LocalVariableTableAttribute attr;
    com.techtrader.modules.tools.bytecode.LocalVariable[] vars;
    com.techtrader.modules.tools.bytecode.LocalVariable var;
    String[] result = null;
    int numParams, i;
    
    numParams = reflectMethod.getParameterTypes().length;
    if(numParams == 0)
      return null;
    
//    cls = reflectMethod.getDeclaringClass();
//    
//    try {
//      bclass = new BCClass(cls);
//    } catch (IOException e) {
//      return null;
//    }
    
    bmeth = bclass.getMethod(reflectMethod.getName(), reflectMethod.getParameterTypes());
    if (bmeth == null)
      return null;
    
    code = bmeth.getCode();
    if (code == null)
      return null;
    
    attr = (LocalVariableTableAttribute)code.getAttribute(Constants.ATTR_LOCALS);
    if (attr == null)
      return null;
    
    vars = attr.getLocalVariables();
    
    result = new String[numParams + 1];
    
    for (i = 0; i < vars.length; i++) {
      var = vars[i];
      
      if (var.getIndex() <= numParams) {
        
        if (var.getName().equals("this"))
          continue;
        result[var.getIndex()] = var.getName();
      }
    }
    return(result);
  } // executeTTbytecode
  
  private static void printResult(java.lang.reflect.Method method, String[] result) {
    int j;
    boolean first;
    
    System.out.print(method.getName() + "(");
    if(result != null) {
      first = true;
      for(j = 1; j < result.length; j++) {
        if(first)
          first = false;
        else
          System.out.print(", ");
        System.out.print(result[j]);
      }
    }
    System.out.println(")");
  } // printResult
} // GetParamNamesBench
