package com.mobify.astro.messaging;

import com.mobify.astro.messaging.annotations.AsyncRpcMethod;
import com.mobify.astro.messaging.annotations.RpcMethod;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class RpcMethodWrapper {

    enum RpcMethodType {
        SYNC,
        ASYNC
    }

    final Method method;
    final RpcMethodType methodType;
    private String[] parameterNames; // Populated lazily, use getter to access

    RpcMethodWrapper(Method method, RpcMethodType methodType) {
        this.method = method;
        this.methodType = methodType;
    }

    /**
     * Compute these once and cache them since getting them off the annotation each time is
     * expensive.
     *
     * We do this lazily so we avoid making this calculation for every single RpcMethod that
     * a class defines even if it is never used. This avoids a larger than necessary start-up
     * cost.
     */
    String[] getParameterNames()
            throws Exceptions.UnannotatedMethodException {
        if (parameterNames != null) {
            return parameterNames;
        }
        RpcMethod syncAnnotation = method.getAnnotation(RpcMethod.class);
        if (syncAnnotation != null) {
            parameterNames = syncAnnotation.parameterNames();
            return parameterNames;
        }
        AsyncRpcMethod asyncAnnotation = method.getAnnotation(AsyncRpcMethod.class);
        if (asyncAnnotation != null) {
            parameterNames = asyncAnnotation.parameterNames();
            return parameterNames;
        }
        throw new Exceptions.UnannotatedMethodException(method);
    }

    Object invoke(Object receiver, Object[] parameters) throws InvocationTargetException, IllegalAccessException {
        return method.invoke(receiver, parameters);
    }
}
