package com.pictc.utils;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public final class LambdaUtils {
	
	private LambdaUtils() {
		super();
	}
	
	public static <T, R>SerializedLambda getLambda(TFunction<T, R> fn) {
		// 从function取出序列化方法
        Method writeReplaceMethod = null;
    	try {
            writeReplaceMethod = fn.getClass().getDeclaredMethod("writeReplace");
            writeReplaceMethod.setAccessible(true);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        // 从序列化方法取出序列化的lambda信息
        SerializedLambda lambda = null;
        try {
        	lambda = (SerializedLambda) writeReplaceMethod.invoke(fn);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
		return lambda;
	}
    
    public static <T, R>Field getField(TFunction<T, R> fn) {
        // 从序列化方法取出序列化的lambda信息
        SerializedLambda lambda = getLambda(fn);
        String fieldName = getFieldName(lambda);
        Field field = null;
        try {
            field = Class.forName(lambda.getImplClass().replace("/", ".")).getDeclaredField(fieldName);
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        return field;
    }
    
    private static <T, R>String getFieldName(SerializedLambda lambda) {
    	// 从lambda信息取出method、field、class等
        String implMethodName = lambda.getImplMethodName();
		// 确保方法是符合规范的get方法，boolean类型是is开头
        if (!implMethodName.startsWith("is") && !implMethodName.startsWith("get")) {
            throw new RuntimeException("get方法名称: " + implMethodName + ", 不符合java bean规范");
        }
        // get方法开头为 is 或者 get，将方法名 去除is或者get，然后首字母小写，就是属性名
        int prefixLen = implMethodName.startsWith("is") ? 2 : 3;

        String fieldName = implMethodName.substring(prefixLen);
        String firstChar = fieldName.substring(0, 1);
        fieldName = fieldName.replaceFirst(firstChar, firstChar.toLowerCase());
        return fieldName;
    }
    
    public static <T, R>String getFieldName(TFunction<T, R> fn) {
        SerializedLambda lambda = getLambda(fn);
        return getFieldName(lambda);
    }


}

