package com.mobify.astro.messaging;

import com.mobify.astro.AstroPlugin;

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

/**
 * Factory class that exposes a static method to create a Message from JSON.
 */
public class JsonMessageFactory {
    private static final String TAG = JsonMessageFactory.class.getName();

    // we don't need no instances
    private JsonMessageFactory() {}

    /**
     * Returns the JSONObject representation of a string
     *
     * @param jsonString the string to convert to a JSONObject
     * @return JSONObject representation of the string
     * @throws Exceptions.PayloadMissingException
     * @throws Exceptions.MalformedRpcMessageException
     * @throws JSONException
     */
    public static Message fromString(String jsonString)
            throws Exceptions.PayloadMissingException, Exceptions.MalformedRpcMessageException,
            JSONException {

        JSONObject jsonObject;
        jsonObject = new JSONObject(jsonString);

        return fromJSON(jsonObject);
    }

    /**
     * Constructs an object of type Message from `serializedMessage`.
     *
     * @param serializedMessage the JSONObject to convert to a message
     * @throws com.mobify.astro.messaging.Exceptions.MalformedRpcMessageException
     * @throws com.mobify.astro.messaging.Exceptions.PayloadMissingException
     */
    public static Message fromJSON(JSONObject serializedMessage)
            throws Exceptions.MalformedRpcMessageException, Exceptions.PayloadMissingException {
        Message message;
        JSONObject payload;

        try {
            payload = serializedMessage.getJSONObject(Message.KeyNames.PAYLOAD);
        } catch (JSONException e) {
            throw new Exceptions.PayloadMissingException(serializedMessage);
        }

        // TODO: Clean this up
        if (serializedMessage.has(RpcMessage.KeyNames.ID) &&
                serializedMessage.has(SenderMessage.KeyNames.SENDER_ADDRESS)) {
            if (payload.has(RpcRequest.KeyNames.METHOD) &&
                    payload.has(RpcRequest.KeyNames.PARAMS)) {
               message = new RpcRequest();
            } else if (payload.has(RpcResponse.KeyNames.RESULT) ||
                    payload.has(RpcResponse.KeyNames.ERROR)) {
               message = new RpcResponse();
            } else {
                throw new Exceptions.MalformedRpcMessageException(serializedMessage);
            }
        }
        else if (payload.has(EventMessage.KeyNames.EVENT_NAME)) {
            message = new EventMessage();
        }
        else if (serializedMessage.has(SenderMessage.KeyNames.SENDER_ADDRESS)) {
            message = new SenderMessage();
        }
        else {
            message = new Message();
        }

        message.setPayloadFromJSON(serializedMessage);
        message.setHeadersFromJSON(serializedMessage);
        return message;
    }

    /**
     * Creates a SenderMessage from the jsonData string by adding the provided
     * "addressable" object's address as a header.
     *
     * @param jsonData JSON string of the message to be sent
     * @param sender The object that is sending the message
     * @throws org.json.JSONException
     * @throws com.mobify.astro.messaging.Exceptions.PayloadMissingException
     * @throws com.mobify.astro.messaging.Exceptions.MalformedRpcMessageException
     */
    public static SenderMessage senderMessageFromJSONString(String jsonData, AddressableObject sender)
            throws JSONException, Exceptions.PayloadMissingException,
            Exceptions.MalformedRpcMessageException {

        JSONObject serializedMessage = new JSONObject(jsonData);

        serializedMessage.put(SenderMessage.KeyNames.SENDER_ADDRESS, sender.getInstanceAddress());
        return (SenderMessage)fromJSON(serializedMessage);
    }
}
