/** @file  tst_psArray.c
 *
 *  @brief Test driver for psArray integer functions
 *
 *  This test driver contains the following tests for psArray test point 1:
 *     A)  Create void pointer array
 *     B)  Add data to void pointer array
 *     C)  Reallocate void pointer array bigger
 *     D)  Reallocate void pointer array smaller
 *     E)  Reallocate with null pointer
 *     F)  Remove item from array
 *     G)  Remove invalid item from array
 *     H)  Remove item from null array
 *     I)  Remove null item from array
 *     J)  Free void pointer array
 *
 *  @author  Ross Harman, MHPCC
 *
 *  @version $Revision: 1.9 $  $Name: not supported by cvs2svn $
 *  @date  $Date: 2004-11-22 21:07:42 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

#include <math.h>

#include "pslib.h"
#include "psTest.h"

typedef struct
{
    psS32 x;
    float y;
}
testStruct;


psS32 main(psS32 argc,
           char* argv[])
{
    // Create array of pointers
    testStruct *mySt[10];
    psArray *psArr1 = NULL;

    // Test A - Create void pointer array
    printPositiveTestHeader(stdout,"psArray", "Create void pointer array");
    psArray *psArr = psArrayAlloc(5);
    if (psArr->nalloc != 5) {
        psError(PS_ERR_UNKNOWN, true,"psArray didn't have proper number of elements.");
        return 1;
    }
    printFooter(stdout, "psArray", "Create void pointer array", true);


    // Test B - Add data to void pointer array
    printPositiveTestHeader(stdout, "psArray", "Add data to void pointer array");
    for(psS32 i = 0; i < 5; i++) {
        testStruct *ts = psAlloc(sizeof(testStruct));
        ts->x = 10*i;
        ts->y = 10.1*i;
        mySt[i] = ts;
        psArr->data[i] = ts;
        psMemIncrRefCounter(ts);
    }

    for(psS32 i = 0; i < 5; i++) {
        testStruct *ts = (testStruct*)psArr->data[i];
        printf("ts[%d].x = %d ts[%d].y = %.2f\n", i, ts->x, i, ts->y);
        if (fabsf(ts->x - 10*i) > 0.01f || fabsf(ts->y - 10.1*i) > 0.01f) {
            psError(PS_ERR_UNKNOWN, true,"Couldn't properly get elements from array.");
            return 2;
        }
    }
    printf("array size = %d\n", psArr->nalloc);
    if (psArr->nalloc != 5) {
        psError(PS_ERR_UNKNOWN, true,"Array Size wrong");
        return 3;
    }
    printf("array population = %d\n", psArr->n);
    if (psArr->n != 5) {
        psError(PS_ERR_UNKNOWN, true,"Array population wrong");
        return 4;
    }
    printFooter(stdout, "psArray", "Add data to void pointer array", true);


    // Test C - Reallocate void pointer array bigger
    printPositiveTestHeader(stdout,"psArray", "Reallocate void pointer array bigger");
    psArr = psArrayRealloc(psArr,10);
    printf("Adding more elements to void pointer array...\n");
    for(psS32 i = 5; i < 10; i++) {
        testStruct *ts = psAlloc(sizeof(testStruct));
        ts->x = 10*i;
        ts->y = 10.1*i;
        mySt[i] = ts;
        psArr->data[i] = ts;
        psArr->n++;
        psMemIncrRefCounter(ts);
    }
    for(psS32 i = 0; i < 10; i++) {
        testStruct *ts = (testStruct*)psArr->data[i];
        printf("ts[%d].x = %d ts[%d].y = %.2f\n", i, ts->x, i, ts->y);
        if (fabsf(ts->x - 10*i) > 0.01f || fabsf(ts->y - 10.1*i) > 0.01f) {
            psError(PS_ERR_UNKNOWN, true,"Couldn't properly get elements from array.");
            return 5;
        }
    }
    printf("array size = %d\n", psArr->nalloc);
    if (psArr->nalloc != 10) {
        psError(PS_ERR_UNKNOWN, true,"Array Size wrong");
        return 6;
    }
    printf("array population = %d\n", psArr->n);
    if (psArr->n != 10) {
        psError(PS_ERR_UNKNOWN, true,"Array Population wrong");
        return 7;
    }
    printFooter(stdout, "psArray", "Reallocate void pointer array bigger", true);

    // Test D - Reallocate void pointer array smaller
    printPositiveTestHeader(stdout,"psArray","Reallocate void pointer array smaller");
    psArr = psArrayRealloc(psArr,3);
    for(psS32 i = 0; i < 3; i++) {
        testStruct *ts = (testStruct*)psArr->data[i];
        printf("ts[%d].x = %d ts[%d].y = %.2f\n", i, ts->x, i, ts->y);
        if (fabsf(ts->x - 10*i) > 0.01f || fabsf(ts->y - 10.1*i) > 0.01f) {
            psError(PS_ERR_UNKNOWN, true,"Couldn't properly get elements from array.");
            return 8;
        }
    }
    printf("array size = %d\n", psArr->nalloc);
    if (psArr->nalloc != 3) {
        psError(PS_ERR_UNKNOWN, true,"Array Size wrong");
        return 9;
    }
    printf("array population = %d\n", psArr->n);
    if (psArr->n != 3) {
        psError(PS_ERR_UNKNOWN, true,"Array Population wrong");
        return 10;
    }
    printFooter(stdout, "psArray", "Reallocate integer void pointer smaller", true);

    // Test E - Reallocate with a null
    printNegativeTestHeader(stdout,"psArray","Reallocate with a null array",
                            "Error message generator", 0 );
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
    psArr1 = psArrayRealloc(NULL,5);
    if ( psArr1 != NULL ) {
        printf("ERROR: Return is not NULL\n");
    }
    printFooter(stdout,"psArray","Reallocate with a null array",true);


    // Test F - Remove item from array
    printPositiveTestHeader(stdout, "psArray", "Remove valid item");
    if( !psArrayRemove(psArr,mySt[0]) ) {
        psError(PS_ERR_UNKNOWN,true,"Unable to remove valid item");
        return 100;
    }
    printf("Array size after removal = %d\n",psArr->n);
    if ( psArr->n != 2 ) {
        psError(PS_ERR_UNKNOWN, true, "Items in array not decremented after removal");
        return 101;
    }
    for(psS32 i = 0; i < psArr->n; i++) {
        testStruct *ts = (testStruct*)psArr->data[i];
        printf("ts[%d].x = %d ts[%d].y = %.2f\n", i, ts->x, i, ts->y);
        if(fabsf(ts->x - 10*(i+1)) > 0.01f || fabsf(ts->y - 10.1*(i+1)) > 0.01f) {
            psError(PS_ERR_UNKNOWN, true, "Elements not as expected after remove.");
            return 102;
        }
    }
    psFree(mySt[0]);
    printFooter(stdout,"psArray","Remove valid item", true);

    // Test G - Remove invalid item from array
    printPositiveTestHeader(stdout, "psArray", "Remove invalid item from array");
    if( psArrayRemove(psArr,mySt[9]) ) {
        psError(PS_ERR_UNKNOWN,true,"Removed invalid item from array");
        return 103;
    }
    printFooter(stdout,"psArray","Remove invalid item from array",true);

    // Test H - Remove item from null array
    printPositiveTestHeader(stdout, "psArray", "Remove item from null array");
    if ( psArrayRemove(NULL,mySt[1]) ) {
        psError(PS_ERR_UNKNOWN,true,"Removed valid item from null array");
        return 104;
    }
    printFooter(stdout,"psArray","Remove item from null array",true);

    // Test I - Remove null item from array
    printPositiveTestHeader(stdout, "psArray", "Remove null item from array");
    if( psArrayRemove(psArr,NULL) ) {
        psError(PS_ERR_UNKNOWN,true,"Remove null item from array",true);
        return 105;
    }
    printFooter(stdout,"psArray","Remove null item from array",true);

    // Test J - Free void pointer array
    printPositiveTestHeader(stdout, "psArray", "Free void pointer array");
    psFree(psArr);
    for(psS32 i = 0; i < 10; i++) {
        psFree(mySt[i]);
    }
    if( psMemCheckLeaks(0, NULL, stdout, false) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Memory leaks detected.");
        return 110;
    }
    psS32 nBad = psMemCheckCorruption(0);
    if(nBad) {
        printf("ERROR: Found %d bad memory blocks\n", nBad);
        return 111;
    }
    printFooter(stdout, "psArray" ,"Free void pointer array", true);

    return 0;
}
