
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "processor.h"
#include "command_handlers.h"
#include "request_dispatcher.h"
#include "request_handler_entry.h"

struct s_RequestDispatcher
{
    Processor *processor;
    RequestHandlerEntry *handlerEntry;
    Message *requestMessage;
};


RequestDispatcher *
request_dispatcher_new (Processor *processor, RequestHandlerEntry *handlerEntry, Message *requestMessage)
{
    RequestDispatcher *disp = malloc (sizeof (RequestDispatcher));

    disp->processor = processor;
    disp->handlerEntry = handlerEntry;
    disp->requestMessage = requestMessage;

    return (disp);
}

void
request_dispatcher_destroy (void *ptr)
{
    RequestDispatcher *disp = (RequestDispatcher *) ptr;

    message_destroy (disp->requestMessage);

    free (disp);
}

static Message *
request_dispatcher_validateMessage (const CommandHandler *handler, 
        Message *requestMessage)
{
    Message *responseMessage = NULL;
    dynTstring *errorMessage = dynFinit();
    int i;

    for (i = 0; handler->requiredParameters[i] != NULL; i++)
    {
        const char *value = message_getParameter (requestMessage, 
                handler->requiredParameters[i]);

        if (value == NULL)
        {
            dynFappend_print (errorMessage, "\nCould not find required parameter '%s'.", 
                    handler->requiredParameters[i]);
        }
    }

    if (dynFgetlen (errorMessage) > 0)
    {
        responseMessage = message_makeErrorResponse (requestMessage);
        
        message_setParameterString (responseMessage, "message", errorMessage);
    }

    dynFfree (errorMessage);

    return (responseMessage);
}

void 
request_dispatcher_process (void *requestDispatcherPtr)
{
    RequestDispatcher *dispatcher = (RequestDispatcher *) requestDispatcherPtr;
    Message *responseMessage = NULL;

    if (dispatcher->handlerEntry == NULL)
    {
        responseMessage = message_makeErrorResponse (dispatcher->requestMessage);

        message_setParameter (responseMessage, "message", "Could not find command.");
    }
    else
    {
        const CommandHandler *handler = request_handler_entry_getHandler (dispatcher->handlerEntry);
        void *context = request_handler_entry_getContext (dispatcher->handlerEntry);

        responseMessage = request_dispatcher_validateMessage (handler, 
                dispatcher->requestMessage);

        if (responseMessage == NULL)
        {
            responseMessage = handler->handler (context, dispatcher->requestMessage);

            if (responseMessage == NULL)
            {
                responseMessage = message_makeErrorResponse (dispatcher->requestMessage);

                message_setParameter (responseMessage, "message", "Could not execute handler.");
            }
        }
    }

    if (processor_sendMessageResponse (dispatcher->processor, responseMessage) == false)
    {
        logFmsg (CONT_LOG_ERROR, "causality: could not send message.");
    }

    message_destroy (responseMessage);

    request_dispatcher_destroy (dispatcher);
}
