package com.github.forax.proxy2;

import java.lang.invoke.CallSite;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;

import com.github.forax.proxy2.Proxy2;
import com.github.forax.proxy2.Proxy2.ProxyContext;
import com.github.forax.proxy2.Proxy2.ProxyHandler;

public class RetroRT {
  static class LambdaProxyHandler implements ProxyHandler {
    private final MethodHandle target;
    private final List<Class<?>> capturedTypes;
    
    LambdaProxyHandler(MethodHandle target, List<Class<?>> capturedTypes) {
      this.target = target;
      this.capturedTypes = capturedTypes;
    }

    @Override
    public boolean override(Method method) {
      return Modifier.isAbstract(method.getModifiers());
    }
    
    @Override
    public boolean isMutable(int fieldIndex, Class<?> fieldType) {
      return false;
    }
    
    @Override
    public CallSite bootstrap(ProxyContext context) throws Throwable {
      // we can not use MethodBuilder here, it will introduce a cycle when retro-weaving
      Method method = context.method();
      MethodType methodType = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
      MethodHandle endPoint = target;
      if (!methodType.equals(target.type())) {
        endPoint = endPoint.asType(methodType.insertParameterTypes(0, capturedTypes));
      }
      return new ConstantCallSite(MethodHandles.dropArguments(endPoint, 0, Object.class));
    }
  }
  
  public static CallSite metafactory(Lookup lookup, String name, MethodType type,
                                     MethodType sig, MethodHandle impl, MethodType reifiedSig) throws Throwable {
    List<Class<?>> capturedTypes = type.parameterList();
    MethodHandle target = impl.asType(reifiedSig.insertParameterTypes(0, capturedTypes)); // apply generic casts
    MethodHandle mh = Proxy2.createAnonymousProxyFactory(lookup, type, new LambdaProxyHandler(target, capturedTypes));
    if (type.parameterCount() == 0) { // no capture
      return new ConstantCallSite(MethodHandles.constant(type.returnType(), mh.invoke()));
    }
    return new ConstantCallSite(mh);
  }
}

@@ -333,31 +333,8 @@
 ier;
-%0Aimport java.util.List;
 %0A%0Aim
@@ -615,29 +615,24 @@
 e final 
-List%3C
 Class%3C?%3E
 %3E captur
@@ -615,33 +615,34 @@
 e final Class%3C?%3E
-%3E
+%5B%5D
  capturedTypes;%0A
@@ -690,29 +690,24 @@
 target, 
-List%3C
 Class%3C?%3E
 %3E captur
@@ -690,33 +690,34 @@
 target, Class%3C?%3E
-%3E
+%5B%5D
  capturedTypes) 
@@ -1841,21 +1841,16 @@
     
-List%3C
 Class%3C?%3E
 %3E ca
@@ -1845,17 +1845,18 @@
 Class%3C?%3E
-%3E
+%5B%5D
  capture
@@ -1882,12 +1882,13 @@
 eter
-List
+Array
 ();%0A

simplify the code a little bit.