
#include "message.h"
#include "http_request.h"
#include "mobility.h"

#include "command.h"

#include "serialization.h"

Message * http_message_handler_processWriteMessage (void *context, Message *requestMessage);
Message * http_message_handler_processFinishMessage (void *context, Message *requestMessage);
Message * http_message_handler_processReadEntityBody (void *context, Message *requestMessage);
Message * http_message_handler_handlePing (void *context, Message *requestMessage);


static const char *command_HttpWrite_RequiredParameters[] = { "token", "data", NULL };
static const char *command_HttpWrite_OptionalParameters[] = { "responseHeaders", "status", NULL };
CommandHandler command_HttpWrite = { "HttpWrite", http_message_handler_processWriteMessage, 
    command_HttpWrite_RequiredParameters, command_HttpWrite_OptionalParameters };

static const char *command_HttpFinish_RequiredParameters[] = { "token", "returnStatus", NULL };
static const char *command_HttpFinish_OptionalParameters[] = { NULL };
CommandHandler command_HttpFinish = { "HttpFinish", http_message_handler_processFinishMessage, 
    command_HttpFinish_RequiredParameters, command_HttpFinish_OptionalParameters };

static const char *command_HttpReadEntityBody_RequiredParameters[] = { "token", NULL };
static const char *command_HttpReadEntityBody_OptionalParameters[] = { NULL };
CommandHandler command_HttpReadEntityBody = { "HttpReadEntityBody", http_message_handler_processReadEntityBody, 
    command_HttpReadEntityBody_RequiredParameters, command_HttpReadEntityBody_OptionalParameters };

static const char *command_HttpPing_RequiredParameters[] = { "token", NULL };
static const char *command_HttpPing_OptionalParameters[] = { NULL };
CommandHandler command_HttpPing = { "HttpPing", http_message_handler_processReadEntityBody, 
    command_HttpPing_RequiredParameters, command_HttpPing_OptionalParameters };


static Message *
http_message_handler_createErrorMessage (Message *requestMessage, const char *message, const char *token)
{
    Message *response = message_makeErrorResponse (requestMessage);

    message_setParameter (response, "message", message);

    if (token != NULL)
    {
        message_setParameter (response, "token", token);
    }

    return (response);
}

Message *
http_message_handler_processWriteMessage (void *context, Message *requestMessage)
{
    Mobility *mobility = (Mobility *) context;
    HttpRequest *request;
    const char *token = message_getParameter (requestMessage, "token");

    request = mobility_getRequest (mobility, token);

    if (request == NULL)
    {
        dynTstring *diag;

        Message *responseMessage = 
            http_message_handler_createErrorMessage (requestMessage,
                    "Could not find specified request.", token);

        diag = mobility_getRequestDiag (mobility);

        message_setParameterString (responseMessage, "hash_diag", diag);

        dynFfree (diag);

        return (responseMessage);
    }

    {
        dynTstring *serializedResponseHeaders;

        serializedResponseHeaders = message_getParameterString (
                requestMessage, "responseHeaders");

        if (serializedResponseHeaders != NULL)
        {
            StringDictionary *responseHeaders;

            serialization_deserializeType ("StringDictionary", 
                    &responseHeaders, serializedResponseHeaders);

            http_request_setResponseHeaders (request, responseHeaders);

            stringdictionary_destroy (responseHeaders);
        }
    }

    {
        dynTstring *status = message_getParameterString (
                requestMessage, "status");

        if (status != NULL)
        {
            int status_int = atoi (dynFgetstr (status));

            /* currently not using the string */
            http_request_setStatus (request, status_int, NULL);
        }
    }

    {
        Message *response;
        dynTstring *data = message_getParameterString (requestMessage, "data");

        if (http_request_write (request, data) == true)
        {
            response = message_makeResponse (requestMessage);

            message_setParameter (response, "message", "Data written.");
        }
        else
        {
            response = message_makeErrorResponse (requestMessage);

            message_setParameter (response, "message", "Did not send data.");
        }

        return (response);
    }
}

Message *
http_message_handler_processFinishMessage (void *context, Message *requestMessage)
{
    Mobility *mobility = (Mobility *) context;
    HttpRequest *request;
    const char *token = message_getParameter (requestMessage, "token");

    request = mobility_getRequest (mobility, token);

    if (request == NULL)
    {
        dynTstring *diag;

        Message *responseMessage = 
            http_message_handler_createErrorMessage (requestMessage,
                    "Could not find specified request.", token);

        diag = mobility_getRequestDiag (mobility);

        message_setParameterString (responseMessage, "hash_diag", diag);

        dynFfree (diag);

        return (responseMessage);
    }

    {
        Message *response;
        const char *status = message_getParameter (requestMessage, "returnStatus");

        http_request_setResponse (request, atoi (status));

        response = message_makeResponse (requestMessage);

        message_setParameter (response, "message", "Data written.");

        return (response);
    }
}

Message *
http_message_handler_processReadEntityBody (void *context, Message *requestMessage)
{
    Mobility *mobility = (Mobility *) context;
    HttpRequest *request;
    const char *token = message_getParameter (requestMessage, "token");

    if (token == NULL)
    {
        return (http_message_handler_createErrorMessage (requestMessage,
                    "Could not find required 'token' parameter.", NULL));
    }

    request = mobility_getRequest (mobility, token);

    if (request == NULL)
    {
        dynTstring *diag;

        Message *responseMessage = 
            http_message_handler_createErrorMessage (requestMessage,
                    "Could not find specified request.", token);

        diag = mobility_getRequestDiag (mobility);

        message_setParameterString (responseMessage, "hash_diag", diag);

        dynFfree (diag);

        return (responseMessage);
    }

    {
        Message *response;
        httpTtrans *t = http_request_getHttpTrans (request);;

        if (httpFread_post (t) != -1)
        {
            response = message_makeResponse (requestMessage);
            message_setParameter (response, "data", lstFset_get (t->vars, "post_query"));
        }
        else
        {
            response = http_message_handler_createErrorMessage (requestMessage, 
                    "There was no data to retrieve.", token);
        }

        return (response);
    }
}

Message *
http_message_handler_handlePing (void *context, Message *requestMessage)
{
    Mobility *mobility = (Mobility *) context;
    const char *token = message_getParameter (requestMessage, "token");

    if (mobility_getRequest (mobility, token) == NULL)
    {
        dynTstring *diag;

        Message *responseMessage = 
            http_message_handler_createErrorMessage (requestMessage,
                    "Could not find specified request.", token);

        diag = mobility_getRequestDiag (mobility);

        message_setParameterString (responseMessage, "hash_diag", diag);

        dynFfree (diag);

        return (responseMessage);
    }
    else
    {
        Message *responseMessage = message_makeResponse (requestMessage);

        message_setParameter (responseMessage, "message", "Request found.");

        return (responseMessage);
    }
}

