package cz.senslog.connector.tools.interceptor;

import cz.senslog.connector.tools.util.Arrays;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.BiFunction;


public abstract class AbstractMethodInterceptor implements MethodInterceptor {

    private final Object object;
    private final Method expectedMethod;

    protected AbstractMethodInterceptor(Object object, Method expectedMethod) {
        this.object = object;
        this.expectedMethod = expectedMethod;
    }

    private static boolean methodEquals(Method a, Method b) {
        if (a==null||b==null) { return false; }
        if (!a.getName().equals(b.getName())) { return false; }

        Class<?> aRetType = a.getReturnType(), bRetType = b.getReturnType();
        if (aRetType==null||bRetType==null) { return false; }
        if (!(aRetType == bRetType || bRetType.isInstance(aRetType))) { return false;}

        BiFunction<Object, Object, Boolean> compareFnc = (o1, o2) -> o1.getClass().isInstance(o2.getClass());
        return Arrays.equals(a.getParameterTypes(), b.getParameterTypes(), compareFnc);
    }

    protected Object getObject() {
        return object;
    }

    public abstract Object[] preProcessing(Object[] methodParams);

    public abstract Object postProcessing(Object returnObject);

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws InvocationTargetException, IllegalAccessException {
        Object obj = object != null ? object : o;
        if (methodEquals(expectedMethod, method)) {
            Object[] newArgs = preProcessing(args);
            if (newArgs != null) {
                Object result = method.invoke(obj, newArgs);
                return postProcessing(result);
            } else {
                return postProcessing(null);
            }
        } else {
            return method.invoke(obj, args);
        }
    }
}
