/** @file  tst_psMetadata_01.c
*
*  @brief Test driver for psMetadata functions
*
*  @author  dRob, MHPCC
*
*  @version $Revision: 1.12 $  $Name: not supported by cvs2svn $
*  @date  $Date: 2006-08-09 00:06:26 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*
*/

#include <string.h>
#include "pslib_strict.h"
#include "psTest.h"

static psS32 testMetadataItemCopy(void);
static psS32 testMetadataItemTransfer(void);
static psS32 testMetadataPrint(void);
static psS32 testMetadataItemCompare(void);
static psS32 testMetadataItemParse(void);

testDescription tests[] = {
                              {testMetadataItemCopy, 666, "psMetadataItemCopy()", 0, false},
                              {testMetadataItemTransfer, 1, "psMetadataItemTransfer()", 0, false},
                              {testMetadataPrint,667,"psMetadataPrint",0,false},
                              {testMetadataItemCompare,669,"psMetadataItemCompare",0,false},
                              {testMetadataItemParse,665,"psMetadataItemParse",0,false},
                              {NULL}
                          };

psS32 main( psS32 argc, char* argv[] )
{
    psLogSetLevel( PS_LOG_INFO );

    return ( !runTestSuite(stderr,"psMetadata_01",tests,argc,argv) );

}

psS32 testMetadataItemCopy(void)
{
    psMetadataItem *item = psMetadataItemAlloc("metaITEM", PS_DATA_S32, "no Comment");
    item->data.S32 = 666;
    psMetadataItem *item2 = NULL;

    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    item2 = psMetadataItemCopy(NULL);
    if (item2 != NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataItemCopy failed to return NULL for NULL input psMetadataItem.\n");
        return 1;
    }

    //Simple copy of psS32 data
    item2 = psMetadataItemCopy(item);
    if (item2 == NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataItemCopy incorrectly returned NULL for valid input psMetadataItem.\n");
        return 2;
    }
    if ( strncmp(item2->name, item->name, 10) || item2->type != item->type ||
            item2->data.S32 != item->data.S32 || strncmp(item2->comment, item->comment, 15) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataItemCopy returned an incorrect psMetadataItem (S32 test).\n");
        return 3;
    }
    psFree(item2);
    psFree(item);
    item2 = NULL;

    //Copy of MetadataItem containing a psMetadata
    psMetadata* metadata = psMetadataAlloc();
    psMetadataAddS32(metadata, PS_LIST_TAIL, "item01", 0, "", 55);
    psMetadataAddF32(metadata, PS_LIST_TAIL, "item02", 0, NULL, 3.14);
    item = psMetadataItemAlloc("metaItem2", PS_DATA_METADATA, "newMeta", metadata);
    item2 = psMetadataItemCopy(item);
    if (item2 == NULL || item2->data.md == NULL) {
        psError(PS_ERR_BAD_PARAMETER_NULL, false,
                "psMetadataItemCopy returned either a NULL item or NULL metadata data\n");
        return 4;
    }
    if ( strncmp(item2->name, item->name, 11) || item2->type != item->type ||
            strncmp(item2->comment, item->comment, 15) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataItemCopy returned an incorrect psMetadataItem (Metadata test).\n");
        return 5;
    }
    psMetadataItem *temp1 = psMetadataGet(item->data.md, PS_LIST_HEAD);
    psMetadataItem *temp2 = psMetadataGet(item2->data.md, PS_LIST_HEAD);
    if ( strncmp(temp2->name, temp1->name, 10) || temp2->type != temp1->type ||
            temp2->data.S32 != temp1->data.S32 || strncmp(temp2->comment, temp1->comment, 15) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
                "psMetadataItemCopy incorrectly returned non-matching metadata data.\n");
        return 6;
    }

    psFree(item2);
    psFree(metadata);
    psFree(item);
    return 0;
}

psS32 testMetadataItemTransfer(void)
{

    psMetadata *md = psMetadataAlloc();
    psMetadata *out = NULL;
    psMetadataAddS32(md, PS_LIST_TAIL, "metaITEM", 0, "no Comment", 666);

    //attempt transfer to NULL 'out' metadata.
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if ( psMetadataItemTransfer(out, md, "metaITEM") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed to return false for NULL 'out' metadata.\n");
        return 1;
    }
    out = psMetadataAlloc();
    //attempt to transfer using a NULL key.
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if ( psMetadataItemTransfer(out, md, NULL) ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed to return false for NULL key input.\n");
        return 2;
    }
    //attempt transfer to NULL 'in' metadata.
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if ( psMetadataItemTransfer(out, NULL, "metaITEM") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed to return false for NULL 'in' metadata.\n");
        return 3;
    }
    //attempt to transfer using an allocated metadata and invalid key
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate error message");
    if (psMetadataItemTransfer(out, md, "metaITEM2") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed to return false for invalid 'key'.\n");
        return 4;
    }
    //attempt to transfer with all valid inputs.
    psMetadataItem *item = NULL;
    if ( !psMetadataItemTransfer(out, md, "metaITEM") ) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed with valid inputs.\n");
        return 7;
    }
    item = psMetadataGet(out, PS_LIST_HEAD);
    if (item->data.S32 != 666 || strncmp(item->comment, "no Comment", 20)) {
        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                "psMetadataItemTransfer failed to correctly transfer item data.\n");
        return 8;
    }

    psFree(out);
    psFree(md);

    return 0;
}

static psMetadata *setupMeta2(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, "I am a integer", 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);
    psMetadataAddS8(md, PS_LIST_TAIL, "item6", 0, "I am S8", 6);
    psMetadataAddS16(md, PS_LIST_TAIL, "item7", 0, "I am S16", -666);
    psMetadataAddU8(md, PS_LIST_TAIL, "item8", 0, "I am U8", 6);
    psMetadataAddU16(md, PS_LIST_TAIL, "item9", 0, "I am U16", 666);
    psMetadataAddU32(md, PS_LIST_TAIL, "item10", 0, "I am U32", 666);
    psMetadataAddS64(md, PS_LIST_TAIL, "item11", 0, "I am S64", 666);
    psMetadataAddU64(md, PS_LIST_TAIL, "item12", 0, "I am U64", 666);

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

psS32 testMetadataPrint(void)
{
    psMetadata *meta = NULL;
    meta = setupMeta2();
    psMetadataPrint(NULL, meta, 0);
    psFree(meta);
    return 0;
}

psS32 testMetadataItemCompare(void)
{
    psMetadataItem *compare = NULL;
    psMetadataItem *template = NULL;
    psMetadataItem *itemCopy = NULL;
    psMetadataItem *item = psMetadataItemAlloc("Snickers", PS_DATA_BOOL, "No Comment", true)
                           ;
    if (!item->data.B) {
        return 1;
    }

    //compare = NULL
    if ( psMetadataItemCompare(compare, item)) {
        return 2;
    }
    //template = NULL
    if ( psMetadataItemCompare(item, template)) {
        return 3;
    }

    template = psMetadataItemAlloc("Milky Way", PS_DATA_BOOL, "No Comment", true)
               ;
    compare = psMetadataItemAlloc("Snickers", PS_DATA_S32, "No Comment", 1);
    //template->name != item->name
    if ( psMetadataItemCompare(template, item) ) {
        return 4;
    }
    //compare->type != item->type
    if ( psMetadataItemCompare(compare, item) ) {
        printf("\ncompare == item b/c of type\n");
        //        return 5;
    }

    //compare->type == F32  compare->data.F32 = 1.4
    psFree(compare);
    compare = psMetadataItemAlloc("Snickers", PS_DATA_F64, "No Comment", 1.00001);
    if ( psMetadataItemCompare(compare, item) ) {
        printf("\ncompare2 == item b/c of type\n");
        //        return 5;
    }
    psFree(template)
    ;
    template = psMetadataItemAlloc("Snickers", PS_DATA_S32, "No Comment", 1)
               ;
    if ( psMetadataItemCompare(compare, template) ) {
        printf("\ncompare3 == item b/c of type\n");
        //        return 5;
    }

    psFree(template)
    ;
    template = psMetadataItemAlloc("Snickers", PS_DATA_F32, "No Comment", 1.00001)
               ;
    if ( psMetadataItemCompare(compare, template) ) {
        printf("\ncompare4 == item b/c of type\n");
        //        return 5;
    }


    //itemCopy == item
    itemCopy = psMetadataItemCopy(item);
    if ( !psMetadataItemCompare(itemCopy, item) ) {
        return 7;
    }

    psFree(compare);
    psFree(template)
    ;
    psFree(itemCopy);
    psFree(item);

    return 0;
}

psS32 testMetadataItemParse(void)
{

    return 0;
}


