
#include <stdlib.h>
#include <pthread.h>

#include "http_request_queue.h"
#include "http_request_list.h"

#include "http_request_list_entry.h"
#include "threadpool.h"

struct s_HttpRequestList
{
    HttpRequestQueue *queue;

    HttpRequestHandlerDelegate handler;
    void *handlerContext;

    hshTvoid_list *list;
    pthread_rwlock_t listLock;
};

HttpRequestList *g_http_request_list = NULL;
static pthread_once_t g_http_request_list_once = PTHREAD_ONCE_INIT;


static void http_request_list_setupInstance (void);

HttpRequestList *
http_request_list_new()
{
    HttpRequestList *request = malloc (sizeof (HttpRequestList));

    request->list = hshFvoid_init (http_request_destroy);
    request->queue = http_request_queue_new();
    request->handler = NULL;

    pthread_rwlock_init (&request->listLock, NULL);

    return (request);
}

void
http_request_list_destroy (void *ptr)
{
    HttpRequestList *request = (HttpRequestList *) ptr;

    http_request_queue_destroy (request->queue);

    hshFvoid_destroy (request->list);

    free (request);
}

void
http_request_list_setHandler (HttpRequestList *instance, 
        HttpRequestHandlerDelegate delegate, void *context)
{
    pthread_rwlock_wrlock (&instance->listLock);

    instance->handler = delegate;
    instance->handlerContext = context;

    pthread_rwlock_unlock (&instance->listLock);
}

bool
http_request_list_containsRequest (HttpRequestList *requestList, const char *token)
{
    bool ret;

    pthread_rwlock_rdlock (&requestList->listLock);

    ret = hshFvoid_contains (requestList->list, token);

    pthread_rwlock_unlock (&requestList->listLock);

    return (ret);
}

static void
http_request_list_setupInstance()
{
    g_http_request_list = http_request_list_new();
}

HttpRequestList *
http_request_list_getRequestList()
{
    pthread_once (&g_http_request_list_once, http_request_list_setupInstance);

    return (g_http_request_list);
}

void
http_request_list_addRequest (HttpRequestList *requestList, HttpRequest *request)
{
    pthread_rwlock_wrlock (&requestList->listLock);

    hshFvoid_add (requestList->list, http_request_getToken (request), request);

    if (requestList->handler != NULL)
    {
        HttpRequestListEntry *entry = 
            http_request_list_entry_new (requestList->handler, request,
                    requestList->handlerContext);

        /* entry will be cleaned up by itself after the call is completed */
        threadpool_queueUserWorkItem (threadpool_getInstance(),
                http_request_list_entry_invokeEntry, entry);
    }
    else
    {
        http_request_queue_addRequest (requestList->queue, request);
    }

    pthread_rwlock_unlock (&requestList->listLock);
}

void
http_request_list_removeRequest (HttpRequestList *requestList, const char *token)
{
    pthread_rwlock_wrlock (&requestList->listLock);

    hshFvoid_del (requestList->list, token);

    pthread_rwlock_unlock (&requestList->listLock);
}

HttpRequest *
http_request_list_getNextRequest (HttpRequestList *requestList)
{
    return (http_request_queue_getRequest (requestList->queue));
}
