/** @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.21 $  $Name: not supported by cvs2svn $
*  @date  $Date: 2006-02-03 00:12:02 $
*
*  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);

testDescription tests[] = {
                              {testMetaIter, 1, "Test psMetadataIterator fxns", 0, false},
                              {testMetaWrite, 2, "Test psMetadataConfigWrite", 0, false},
                              {testMetaRemove, 3, "Test psMetadataRemoveKey/Index", 0, false},
                              {testMetaAddPtr, 4, "Test psMetadataAddPtr", 0, false},
                              {testMetaCopy, 5, "Test psMetadataCopy", 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;
    }
    vec->n = 5;
    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;
    //Return false for NULL input metadata
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if (psMetadataConfigWrite(newMD, "mdcfgwrt.out")) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataConfigWrite failed to return false for NULL input metadata.\n");
        return 1;
    }
    newMD = setupMeta();
    //Return false for NULL input filename
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if (psMetadataConfigWrite(newMD, NULL)) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataConfigWrite failed to return false for NULL input filename.\n");
        return 2;
    }
    //Return false for bad input filename
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if (psMetadataConfigWrite(newMD, "temp")) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataConfigWrite failed to return false for bad input filename.\n");
        return 3;
    }
    //Return true for valid inputs
    if ( !psMetadataConfigWrite(newMD, "mdcfgwrt.out") ) {
        fprintf(stderr, "Failed test point E - Failed to write metadata to file. \n");
        return 4;
    }

    //Make sure the output file matches the verified file output.
    FILE *verified;
    FILE *output;
    verified = fopen("mdcfgwrt.verified", "r");
    output = fopen("mdcfgwrt.out", "r");
    char buffer1[100];
    char buffer2[100];
    while ( fscanf(verified, "%s", buffer1) != EOF ) {
        if (fscanf(output, "%s", buffer2) == EOF) {
            psError(PS_ERR_BAD_PARAMETER_SIZE, false,
                    "Output file is smaller than the expected output file.\n");
            return 5;
        }
        if (strncmp(buffer1, buffer2, 100) ) {
            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                    "Output file contents do not match the expected output.\n");
            return 6;
        }
    }
    if (fscanf(output, "%s", buffer2) != EOF) {
        psError(PS_ERR_BAD_PARAMETER_SIZE, false,
                "Output file is larger than the expected output file.\n");
        return 7;
    }
    fclose(verified);
    fclose(output);

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

    psMetadata *strtest = psMetadataAlloc();
    //should return false for NULL input string
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if (psMetadataAddStr(strtest, PS_LIST_TAIL, "bar", 0, "baz", NULL) ) {
        psError(PS_ERR_BAD_PARAMETER_NULL, true, "strtest failed for NULL.\n");
        return 9;
    }
    psFree(strtest);

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

}

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

    //Return NULL for NULL input Metadata
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    test = psMetadataCopy(test, empty);
    if (test != NULL) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataCopy failed to return NULL for NULL input metadata.\n");
        psFree(md);
        return 1;
    }

    //Return a copy in of md in test
    test = psMetadataCopy(NULL, 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 ) {
        testItem = psMetadataGetAndIncrement(testIterator);
        mdItem = psMetadataGetAndIncrement(mdIterator);
    }

    if (!psMetadataConfigWrite(md, "MDCopy.in") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataConfigWrite failed to output original metadata contents.\n");
        return 3;
    }
    if (!psMetadataConfigWrite(test, "MDCopy.out") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataConfigWrite failed to output copied metadata contents.\n");
        return 4;
    }
    FILE *verified;
    FILE *output;
    verified = fopen("MDCopy.in", "r");
    output = fopen("MDCopy.out", "r");
    char buffer1[100];
    char buffer2[100];
    while ( fscanf(verified, "%s", buffer1) != EOF ) {
        if (fscanf(output, "%s", buffer2) == EOF) {
            psError(PS_ERR_BAD_PARAMETER_SIZE, false,
                    "Copied metadata is smaller than the original.\n");
            return 5;
        }
        if (strncmp(buffer1, buffer2, 100) ) {
            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                    "Copied metadata contents do not match original metadata contents.\n");
            return 6;
        }
    }
    if (fscanf(output, "%s", buffer2) != EOF) {
        psError(PS_ERR_BAD_PARAMETER_SIZE, false,
                "Copied metadata is larger than the original.\n");
        return 7;
    }
    fclose(verified);
    fclose(output);


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