package com.gesmallworld.magik.utils;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class MethodHandleBug {

    public static MethodHandle handler;
    public static MethodHandle body8;
    public static MethodHandle prim8;
    public static MethodHandle body9;
    public static MethodHandle prim9;
    
    public static Object handler(Exception e) {
        return null;
    }
    
    public static Object body8(
            Object a1, Object a2, Object a3, Object a4, 
            Object a5, Object a6, Object a7, Object...a8) {
        return null;
    }
    
    public static Object prim8(
            Object a1, Object a2, Object a3, Object a4, 
            Object a5, Object a6, Object a7, Object...a8) {
        return null;
    }
    

    public static Object body9(
            Object a1, Object a2, Object a3, Object a4, 
            Object a5, Object a6, Object a7, Object a8, Object...a9) {
        return null;
    }
    
    public static Object prim9(
            Object a1, Object a2, Object a3, Object a4, 
            Object a5, Object a6, Object a7, Object a8, Object...a9) {
        return null;
    }
    
    static {
        try {
            handler = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class, "handler", 
                    MethodType.methodType(Object.class, Exception.class));
            prim8 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class, "prim8", 
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object[].class));
            body8 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class, "body8", 
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object[].class));
            prim9 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class, "prim9", 
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object[].class));
            body9 = MethodHandles.lookup().findStatic(
                    MethodHandleBug.class, "body9", 
                    MethodType.methodType(
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object.class, Object.class, Object.class,
                            Object.class, Object[].class));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        System.out.printf("Java Version is %s.\n", System.getProperty("java.version"));

        System.out.printf("\nWorking case (8 args).\n\n");
        System.out.printf("Handler is a %s.\nBody8 is a %s.\nPrim8 is a %s.\n", handler, body8, prim8);
        MethodHandle primWithHandler8 = MethodHandles.catchException(
                prim8, Exception.class, handler);
        System.out.printf("Prim8 with Handler is a %s.\n", primWithHandler8);
        MethodHandle bodyWithEXcp8 = MethodHandles.dropArguments(body8, 0, Exception.class);
        System.out.printf("Body8 with exception is a %s.\n", bodyWithEXcp8);
        MethodHandle primFallBackToBody8 = MethodHandles.catchException(
            primWithHandler8, Exception.class, bodyWithEXcp8);
        System.out.printf("Prim8 with fallback to body8 is a %s.\n", primFallBackToBody8);
        
        System.out.printf("\nFailing case (9 args).\n\n");
        System.out.printf("Handler is a %s.\nBody9 is a %s.\nPrim9 is a %s.\n", handler, body9, prim9);
        MethodHandle primWithHandler9 = MethodHandles.catchException(
                prim9, Exception.class, handler);
        System.out.printf("Prim9 with Handler is a %s.\n", primWithHandler9);
        MethodHandle bodyWithEXcp9 = MethodHandles.dropArguments(
            body9, 0, Exception.class);
        System.out.printf("Body9 with exception is a %s.\n", bodyWithEXcp9);
        MethodHandle primFallBackToBody9 = MethodHandles.catchException(
            primWithHandler9, Exception.class, bodyWithEXcp9);
        System.out.printf("Prim9 with fallback to body9 is a %s.\n", primFallBackToBody9);
    }
}
