/*****************************************************************************
    This code will test whether hash tables entries can be removed correctly.
 
    NOTE: Add code to test whether duplicates are handled correctly.
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "pslib_strict.h"
#include "psTest.h"
#include "psHash.h"
#include "psMemory.h"
#define NUM_HASH_TABLE_BUCKETS 100
psS32 imGlobal = 0;
psS32 currentId = 0;

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

static ID *IdAlloc(const char *name)
{
    ID *id = NULL;

    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;
    psS32 TotalKeys       = 0;
    psBool retVal         = false;
    ID *id = NULL;
    ID *ids[4];
    char *myKeys[] = {"ENTRY00", "ENTRY01", "ENTRY02", "ENTRY03", NULL
                     };
    char *myData[] = {"IDA", "IDB", "IDC", "IDD", NULL
                     };
    psS32 memLeaks        = 0;

    currentId = psMemGetId();

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

    // Add items to hash table
    myHashTable = psHashAlloc(NUM_HASH_TABLE_BUCKETS);
    i = 0;
    while (myKeys[i] != NULL) {
        ids[i] = IdAlloc(myData[i]);
        psHashAdd(myHashTable, myKeys[i], ids[i]);
        i++;
    }
    TotalKeys = i - 1;

    // Verify items which were just add to hash table
    i = TotalKeys;
    while (i >= 0) {

        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--;
    }

    // Remove each item from the table and verify item is no longer in the list
    i = 0;
    while (myKeys[i] != NULL) {
        // The psHashRemove() procedure removes the entry from the hash
        // table and deletes the data.
        retVal = psHashRemove(myHashTable, myKeys[i]);
        if (!retVal) {
            fprintf(stderr,"%s: Hash table entry not removed.\n",__func__);
            return 2;
        }
        id = psHashLookup(myHashTable, myKeys[i]);
        if (id != NULL) {
            fprintf(stderr, "%s: Hash table entry for key %s not removed.\n",
                    __func__, "IDA");
            return 3;
        }
        i++;
    }
    printFooter(stdout,"psHash functions","psHashRemove()",true);

    // Use an invalid key in the hash table: verify false is returned
    printNegativeTestHeader(stdout,"psHashRemove","Invalid key","Key is not found in table",0);
    if (psHashRemove(myHashTable,"BogusKey") ) {
        psError(PS_ERR_UNKNOWN,true,"psHashRemove removed an entry with a bogus key.");
        return 4;
    }
    printFooter(stdout,"psHashRemove","Invalid key",true);

    // Remove with null table
    printNegativeTestHeader(stdout,"psHashRemove","NULL table","Can not remove with NULL table",0);
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: psHashRemove with null table");
    retVal = psHashRemove(NULL,"ENTRY02");
    if (retVal) {
        psError(PS_ERR_UNKNOWN,true,"psHashRemove removed an entry from NULL hash table.");
        return 5;
    }
    printFooter(stdout,"psHashRemove","NULL table",true);

    // Remove with null key
    printNegativeTestHeader(stdout,"psHashRemove","NULL key","Can not remove with NULL key",0);
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message: psHashRemove with null key");
    if (psHashRemove(myHashTable,NULL) ) {
        psError(PS_ERR_UNKNOWN,true,"psHashRemove removed an entry from NULL key");
        return 6;
    }
    printFooter(stdout,"psHashRemove","NULL key",true);

    psFree(myHashTable);
    for(i=0; i<(TotalKeys+1); i++) {
        psFree(ids[i]);
    }
    memLeaks = psMemCheckLeaks(currentId,NULL,stdout,false);
    if (memLeaks != 0) {
        psAbort(__func__,"Memory Leaks! (%d leaks)", memLeaks);
    }
    psMemCheckCorruption(true);

    return (!testStatus);
}

