/*****************************************************************************
    This code will test whether hash tables entries can be inserted correctly,
    and retrieved correctly.
 
    NOTE: Add code to test whether duplicates are handled correctly (use a
    small hash table and lots of keys).
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "pslib_strict.h"
#include "psTest.h"
#include "psHash.h"
#define NUM_HASH_TABLE_BUCKETS 100
psS32 imGlobal = 0;

typedef struct
{
    char *name;
}
ID;
static void IdFree(ID *id);

static ID *IdAlloc(const char *name)
{
    ID *id = psAlloc(sizeof(ID));
    psMemSetDeallocator(id,(psFreeFunc)IdFree);
    id->name = psStringCopy(name);

    return id;
}

static void IdFree(ID *id)
{
    imGlobal++;
    psFree(id->name);
}

psS32 main()
{
    psHash *myHashTable = NULL;
    psS32 testStatus      = true;
    psS32 i               = 0;
    ID *id = NULL;
    char *myKeys[] = {"ENTRY00", "ENTRY01", "ENTRY02", "ENTRY03", NULL
                     };
    char *myData[] = {"IDA", "IDB", "IDC", "IDD", NULL
                     };
    psS32 currentId = psMemGetId();
    psS32 memLeaks        = 0;

    printPositiveTestHeader(stdout,"psHash functions","psHashLookup");

    myHashTable = psHashAlloc(NUM_HASH_TABLE_BUCKETS);
    i = 0;
    while (myKeys[i] != NULL) {
        id = IdAlloc(myData[i]);
        psHashAdd(myHashTable, myKeys[i], id);
        psFree(id);
        i++;
    }

    i = 0;
    while (myKeys[i] != NULL) {
        id = psHashLookup(myHashTable, myKeys[i]);
        if (0 != strcmp(myData[i], id->name)) {
            fprintf(stderr, "%s: Hash table entry for key %s was %s (should be %s).\n",
                    __func__, myKeys[i], id->name, myData[i]);
            return 1;
        }
        i++;
    }
    printFooter(stdout,"psHash functions","psHashLookup",true);

    // Use an invalid key in the hash table: verify no item is returned
    printNegativeTestHeader(stdout,"psHashLookup","Invalid key","Key is not found in the table",0);
    id = psHashLookup(myHashTable, "BogusKey");
    if (id != NULL) {
        fprintf(stderr, "%s: Hash table entry for key %s was not NULL.\n",
                __func__, "BogusKey");
        return 2;
    }
    printFooter(stdout,"psHashLookup","Invalid key",true);

    // Lookup with null table
    printNegativeTestHeader(stdout,"psHashLookup","NULL table","Can not lookup with NULL table",0);
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: psHashLookup with null table");
    id = psHashLookup(NULL,"ENTRY01");
    if (id != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psHashLookup retrieved an entry from NULL hash table.");
        return 3;
    }
    printFooter(stdout,"psHashLookup","NULL table",true);

    // Lookup with null key
    printNegativeTestHeader(stdout,"psHashLookup","NULL key","Can not lookup with NULL key.",0);
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: psHashLookup with null key");
    id = psHashLookup(myHashTable,NULL);
    if (id != NULL) {
        psError(PS_ERR_UNKNOWN,true,"psHashLookup retrieved an entry with NULL key.");
        return 4;
    }
    printFooter(stdout,"psHashLookup","NULL key",true);

    psFree(myHashTable);

    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psAbort("Memory Leaks! (%d leaks)", memLeaks);
    }
    psMemCheckCorruption(1);

    return (!testStatus);
}
