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

#include "mobility.h"
#include "mobilitytable.h"


static pthread_once_t g_table_once_control = PTHREAD_ONCE_INIT;
static MobilityTable *g_table = NULL;

struct s_MobilityTable
{
    hshTvoid_list   *list;

    pthread_rwlock_t list_lock;
};

MobilityTable *
mobilitytable_new()
{
    MobilityTable *mtable = malloc (sizeof (MobilityTable));

    mtable->list = hshFvoid_init (mobility_destroy);

    pthread_rwlock_init (&mtable->list_lock, NULL);

    return (mtable);
}

void
mobilitytable_destroy (void *ptr)
{
    MobilityTable *mtable = (MobilityTable *) ptr;

    hshFvoid_destroy (mtable->list);

    pthread_rwlock_destroy (&mtable->list_lock);

    free (mtable);
}

static void
mobilitytable_createGlobalTable (void)
{
    g_table = mobilitytable_new();
}

MobilityTable *
mobilitytable_getTable()
{
    pthread_once (&g_table_once_control, mobilitytable_createGlobalTable);

    return (g_table);
}

Mobility *
mobilitytable_getMobilityEntryByPid (MobilityTable *mtable, int pid)
{
    hshTiterator *iter;
    Mobility *retMob = NULL;

    pthread_rwlock_rdlock (&mtable->list_lock);

    iter = hshFiterator_init (mtable->list);

    while (hshFiterator_next (iter) == 1)
    {
        Mobility *mob = (Mobility *) hshFiterator_current_value (iter);

        if (mobility_getPid (mob) == pid)
        {
            retMob = mob;

            break;
        }
    }

    hshFiterator_free (iter);

    pthread_rwlock_unlock (&mtable->list_lock);

    return (retMob);
}

Mobility *
mobilitytable_getMobilityEntry (MobilityTable *mtable, const char *executable)
{
    Mobility *entry;

    pthread_rwlock_rdlock (&mtable->list_lock);

    entry = (Mobility *) hshFvoid_find (mtable->list, executable);

    if (entry == NULL)
    {
        pthread_rwlock_unlock (&mtable->list_lock);
        pthread_rwlock_wrlock (&mtable->list_lock);

        entry = (Mobility *) hshFvoid_find (mtable->list, executable);

        if (entry == NULL)
        {
            entry = mobility_new (executable);

            if (entry != NULL)
            {
                hshFvoid_add (mtable->list, executable, entry);
            }
            else
            {
                printf ("-- couldn't find executable: %s\n", executable);
            }
        }
    }
    
    pthread_rwlock_unlock (&mtable->list_lock);

    return (entry);
}


