/** @file  tst_psMetadata_07.c
*
*  @brief Test driver for psMetadataIterator functions
*
*  This test driver contains the following tests for psMetadata:
*     Test A - Allocate a psMetadataIterator
*     Test B - Set a psMetadataIterator
*     Test C - Get and Increment a psMetadataIterator
*     Test D - Get and Decrement a psMetadataIterator
*     Test E - psMetadataConfigWrite (also tests psMetadataConfigFormat)
*     Test F - psMetadataRemoveKey, RemoveIndex
*     Test G - psMetadataAddPtr, psMetadataItemAllocPtr
*     Test H - psMetadataCopy
*     Test I - psArgument Functions
*
*  @author  David Robbins, MHPCC
*
*  @version $Revision: 1.15 $  $Name: not supported by cvs2svn $
*  @date  $Date: 2005-11-18 01:51:03 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*
*/
#include "config.h"
#include "pslib_strict.h"
#include "psTest.h"
//#include "psMetadata.h"

static psS32 testMetaIter(void);
static psS32 testMetaWrite(void);
static psS32 testMetaRemove(void);
static psS32 testMetaAddPtr(void);
static psS32 testMetaCopy(void);
static psS32 testArgument(void);

testDescription tests[] = {
                              {testMetaIter, 0, "Test psMetadataIterator fxns", 0, false},
                              {testMetaWrite, 0, "Test psMetadataConfigWrite", 0, false},
                              {testMetaRemove, 0, "Test psMetadataRemoveKey/Index", 0, false},
                              {testMetaAddPtr, 0, "Test psMetadataAddPtr", 0, false},
                              {testMetaCopy, 0, "Test psMetadataCopy", 0, false},
                              {testArgument, 0, "Test psArgument fxns", 0, false},
                              {NULL}
                          };

static psMetadata *setupMeta(void);

static psMetadata *setupMeta(void)
{
    psMetadata *md = NULL;
    psVector *vec = NULL;
    psMetadata *newMD = NULL;
    psTime *time;
    int i = 0;
    md = psMetadataAlloc();
    newMD = psMetadataAlloc();
    vec = psVectorAlloc(60, PS_DATA_S32);
    time = psTimeAlloc(PS_TIME_TAI);
    for (i = 0; i < 5; i++) {
        vec->data.S32[i] = i+1;
    }
    time->sec = 1000;
    time->nsec = 25;
    time->leapsecond = true;
    psMetadataAddBool(md, PS_LIST_TAIL, "item1", 0, "I am a boolean", true);
    psMetadataAddS32(md, PS_LIST_TAIL, "item2", 0, "", 55);
    psMetadataAddF32(md, PS_LIST_TAIL, "item3", 0, NULL, 3.14);
    psMetadataAddF64(md, PS_LIST_TAIL, "item4", 0, "", 6.28);
    psMetadataAddStr(md, PS_LIST_TAIL, "item5", 0, "I am a string", "GNIRTS");
    psMetadataAddVector(md, PS_LIST_TAIL, "vector6", 0, "I am a vector", vec);
    psMetadataAddTime(md, PS_LIST_TAIL, "time01", 0, "I am time", time);

    psMetadataAddS32(newMD, PS_LIST_TAIL, "ITEM01", 0, NULL, 666);
    psMetadata *newestMD = NULL;
    newestMD = psMetadataAlloc();
    psMetadataAddVector(newestMD, PS_LIST_TAIL, "VECTORNEW", 0, "Newest VECTOR", vec);
    psMetadataAddStr(newestMD, PS_LIST_TAIL, "cell", 0, "I am a p-Star", "pStArRs");
    psMetadataAddMetadata(newMD, PS_LIST_TAIL, "META NEW", 0, "I AM Newest METADATA", newestMD);
    psMetadataAddF32(newMD, PS_LIST_TAIL, "ITEM02", 0, "I AM FLOAT", 666.6);
    psMetadataAddF64(newMD, PS_LIST_TAIL, "ITEM03", 0, "I AM DOUBLE", 666.666);

    psMetadataAddMetadata(md, PS_LIST_TAIL, "metadata7", 0, "I am a metadata", newMD);
    psFree(time);
    psFree(newestMD);
    psFree(vec);
    psFree(newMD);
    return md;
}

int main(int argc, char* argv[])
{
    psLogSetLevel( PS_LOG_INFO );
    if( !runTestSuite(stderr,"psMetadata_07",tests,argc,argv)) {
        return 1;
    }
    return 0;
}

//Set a psMetadataIterator //
static psS32 testMetaIter(void)
{
    psMetadata *metadata = NULL;
    metadata = setupMeta();
    psMetadataIterator *iter = NULL;
    psMetadataItem *item1 = NULL;
    psMetadataItem *item2 = NULL;
    psMetadataItem *item3 = NULL;
    printPositiveTestHeader(stdout, "psMetadata", "Test A - Allocate psMetadataIterator");
    iter = psMetadataIteratorAlloc(metadata, PS_LIST_HEAD, NULL);
    if (iter == NULL) {
        fprintf(stderr, "Failed test point - Allocate a psMetadataIterator.  Iterator NULL. \n");
    }
    printFooter(stdout, "psMetadata", "Test A - Allocate psMetadataIterator", true);
    printPositiveTestHeader(stdout, "psMetadata", "Test B - Set psMetadataIterator");
    psMetadataIteratorSet(iter, 2);
    item1 = psMetadataGetAndIncrement(iter);
    if ( !strncmp(item1->name, "item2", 20) ) {
        fprintf(stderr, "Failed test point - IteratorSet - Item names don't match. \n");
    }
    printFooter(stdout, "psMetadata", "Test B - Set psMetadataIterator", true);
    printPositiveTestHeader(stdout, "psMetadata", "Test C - Get and Increment Iterator");
    item2 = psMetadataGetAndDecrement(iter);
    if ( !strncmp(item2->name, "item3", 20) ) {
        fprintf(stderr, "Failed test point - GetAndIncrement - Item names don't match. \n");
    }
    printFooter(stdout, "psMetadata", "Test C - Get and Increment Iterator", true);
    printPositiveTestHeader(stdout, "psMetadata", "Test D - Get and Decrement Iterator");
    item3 = psMetadataGetAndDecrement(iter);
    if ( !strncmp(item3->name, "item2", 20) ) {
        fprintf(stderr, "Failed test point - GetAndDecrement - Item names don't match. \n");
    }
    printFooter(stdout, "psMetadata", "Test D - Get and Decrement Iterator", true);
    psFree(iter);
    psFree(metadata);
    return 0;
}

static psS32 testMetaWrite(void)
{
    psMetadata *newMD = NULL;
    newMD = setupMeta();
    printPositiveTestHeader(stdout, "psMetadata", "Test E - psMetadataConfigWrite");
    if ( !psMetadataConfigWrite(newMD, "mdcfgwrt.out") ) {
        fprintf(stderr, "Failed test point E - Failed to write metadata to file. \n");
    }

    printFooter(stdout, "psMetadata", "Test E - psMetadataConfigWrite", true);
    psFree(newMD);
    return 0;
}

psS32 testMetaRemove(void)
{
    psMetadata *md = NULL;
    md = setupMeta();
    if ( !psMetadataRemoveKey(md, "item1") ) {
        fprintf(stderr, "Failed to remove item1 from psMetadata.\n");
        return 1;
    }
    if ( !psMetadataRemoveIndex(md, PS_LIST_HEAD) ) {
        fprintf(stderr, "Failed to remove item2 from psMetadata.\n");
        return 2;
    }
    psFree(md);
    return 0;
}

psS32 testMetaAddPtr(void)
{
    bool status;
    psVector *vecptr = NULL;
    psVector *vecptr2 = NULL;
    vecptr = psVectorAlloc(5, PS_TYPE_S32);
    vecptr->data.S32[0] = 666;
    psMetadata *md = NULL;
    md = psMetadataAlloc();
    psMetadataItem *item = NULL;
    psMetadataItem *item2 = NULL;
    item = psMetadataItemAllocPtr("itemptr", PS_DATA_STRING, "", "Devil String");
    status = psMetadataAddPtr(md, PS_LIST_HEAD, "vecptr", PS_DATA_VECTOR,
                              "this is a vector comment", vecptr);
    if (!status) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to add psPtr (vector) to metadata.\n");
        return 1;
    }
    status = false;
    vecptr2 = (psVector*)psMetadataLookupPtr(&status, md, "vecptr");
    if (!status) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to retrieve psPtr (vector) from metadata.\n");
        return 2;
    }
    if (vecptr2->data.S32[0] != 666) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Failed to retrieve correct psPtr (vector) from metadata.\n");
        return 3;
    }
    status = false;
    if (item == NULL) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to Alloc psPtr (string) metadata item .\n");
        return 5;
    }
    if ( !psMetadataAddItem(md, item, PS_LIST_TAIL, 0) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to add psPtr (string) metadata item to metadata.\n");
        return 6;
    }
    item2 = psMetadataGet(md, PS_LIST_TAIL);
    if (item2 == NULL) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to retrieve psPtr (string) metadata item .\n");
        return 7;
    }
    if ( strncmp((char*)item2->data.V, "Devil String", 20) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "Unable to retrieve correct psPtr (string) metadata item .\n");
        printf("\n string = %s \n", (char*)item2->data.V);
        return 8;
    }

    psFree(item);
    psFree(vecptr);
    psFree(vecptr2);
    psFree(md);
    return 0;

}

psS32 testMetaCopy(void)
{
    psMetadata *test = NULL;
    psMetadata *empty = NULL;
    psMetadata *md = setupMeta();


    //Return NULL for NULL input Metadata
    test = psMetadataCopy(test, empty);

    //Return a copy in of md in test
    test = psMetadataCopy(test, md);
    //Check if contents are the same
    psMetadataItem *testItem = NULL;
    psMetadataItem *mdItem = NULL;
    psMetadataIterator *testIterator = NULL;
    psMetadataIterator *mdIterator = NULL;
    testIterator = psMetadataIteratorAlloc(test, PS_LIST_HEAD, NULL);
    mdIterator = psMetadataIteratorAlloc(md, PS_LIST_HEAD, NULL);
    testItem = psMetadataGetAndIncrement(testIterator);
    mdItem = psMetadataGetAndIncrement(mdIterator);
    while (testItem != NULL || mdItem != NULL ) {
        if (testItem != mdItem) {
            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                    "Copied psMetadataItem does not match Original.\n");
        }
        testItem = psMetadataGetAndIncrement(testIterator);
        mdItem = psMetadataGetAndIncrement(mdIterator);
    }

    psFree(testItem);
    psFree(mdItem);
    psFree(testIterator);
    psFree(mdIterator);
    psFree(test);
    psFree(md);
    return 0;
}

psS32 testArgument(void)
{
    char *argv[6];
    argv[0] = "./program";
    argv[1] = "-string";
    argv[2] = "new";
    argv[3] = "-float";
    argv[4] = "6.66";
    argv[5] = "-vvv";
    int argc = 6;

    int i = psArgumentGet(argc, argv, "-float");
    if ( i != 0 ) {
        if ( !psArgumentRemove(i, &argc, argv) ) {
            printf("\n Failed to remove float from argument list\n");
        }
    } else {
        printf("\nFailed to find string in argument list\n");
        return 1;
    }
    psArgumentRemove(i, &argc, argv);
    printf("\n Argument %d has been removed", i);
    int log = psArgumentVerbosity(&argc, argv);
    printf("\nLog level = %d \n", log);

    psMetadata *args = psMetadataAlloc();
    psMetadataAdd(args, PS_LIST_TAIL, "-string", PS_DATA_STRING, "Test String", "SomeString");
    psMetadataAdd(args, PS_LIST_TAIL, "-int", PS_DATA_S32 | PS_META_DUPLICATE_OK, "Int1", 1);
    psMetadataAdd(args, PS_LIST_TAIL, "-int", PS_DATA_S32 | PS_META_DUPLICATE_OK, "Int2", 2);
    psMetadataAdd(args, PS_LIST_TAIL, "-float", PS_DATA_F32, "Test Float", 0.0);

    printf("\nThis Should print the Argument Help list.\n\n");
    psArgumentHelp(args);

    if ( !psArgumentParse(args, &argc, argv) || argc != 1 ) {
        psArgumentHelp(args);
        psFree(args);
        return 2;
    }

    psMetadataPrint(args, 4);

    psFree(args);
    return 0;
}

