package com.mobify.astro.messaging;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class RpcRequest extends RpcMessage {

    private RpcResponse response;

    static final class KeyNames {
        public static final String METHOD = "method";
        public static final String PARAMS = "params";
    }

    /**
     * Constructs an RpcRequest.
     *
     * @param payload a JSON Object with a payload
     * @param sender The sending object
     * @param id an identifier for this request/response pair
     */
    protected RpcRequest(JSONObject payload, AddressableObject sender, String id) {
        super(payload, sender, id);
    }

    protected RpcRequest() {
        super();
    }

    /**
     * Gets or creates the response for this RPC request
     * @param sender the object that will be said to have sent this response
     * @return an RpcResponse to this request that can be sent
     * @throws Exceptions.ResponseCreationException
     */
    protected RpcResponse getResponse(AddressableObject sender) throws Exceptions.ResponseCreationException {
        if (response == null) {
            response = createResponseWithSender(sender);
        } else {
            response.setSenderAddress(sender);
        }
        return response;
    }

    /**
     * Creates an RpcResponse to respond to this RpcRequest, populating the address and
     * callId from the senderAddress and callId of the request RpcMessage, and leaving the result
     * unfilled.
     */
    private RpcResponse createResponseWithSender(AddressableObject sender) throws Exceptions.ResponseCreationException {
        String address = getSenderAddress();
        String id = getId();
        RpcResponse response;
        try {
            response = new RpcResponse(address, sender, id);
        } catch (JSONException e) {
            throw new Exceptions.ResponseCreationException(this, e);
        }
        return response;
    }

    /**
     * Fetches the method key from the payload of this RpcRequest
     *
     * @return String name of the method this RpcRequest calls
     * @throws Exceptions.MalformedRpcRequestMessage
     */
    String getMethod() throws Exceptions.MalformedRpcRequestMessage {
        try {
            return getPayload().getString(KeyNames.METHOD);
        } catch (JSONException e) {
            throw new Exceptions.MalformedRpcRequestMessage(KeyNames.METHOD, this);
        }
    }

    /**
     * Fetches the parameters to be passed as arguments to the method
     *
     * @return JSONObject holding the parameters for the RpcMethod
     * @throws Exceptions.ParametersNotFoundException
     */
    JSONObject getParameters() throws Exceptions.ParametersNotFoundException {
        JSONObject payload = getPayload();
        try {
            return payload.getJSONObject(KeyNames.PARAMS);
        } catch(JSONException e) {
            throw new Exceptions.ParametersNotFoundException(this);
        }
    }

    List<Object> getParameterValues(String[] parameterNames) throws Exceptions.ParameterMissingException,
            Exceptions.ParametersNotFoundException {
        JSONObject parameters;
        ArrayList<Object> parameterValues = new ArrayList<Object>();

        parameters = getParameters();

        for(String parameterName : parameterNames) {
            try {
                Object value = parameters.get(parameterName);
                if (value == JSONObject.NULL) {
                    value = null;
                }
                parameterValues.add(value);
            } catch (JSONException e) {
                throw new Exceptions.ParameterMissingException(parameterName, this);
            }
        }

        return parameterValues;
    }
}
