/*****************************************************************************
    This routine must ensure that PS_STAT_CLIPPED_MEAN and
    PS_STAT_CLIPPED_STDEV is calculate correctly by the procedure
    psVectorStats().
 
    XXX: Must add tests for various data types, other than psF32.  Copy code
    from tst_psStats00.c-tst_psStats02.c.
 *****************************************************************************/
#include <stdio.h>
#include "pslib_strict.h"
#include "psTest.h"
#include "psTest.h"
#include "psImageStats.h"
#include "float.h"
#include <math.h>

#define N 500
#define MY_MEAN  30.0
#define MY_RANGE 2.0

psS32 main()
{
    psLogSetFormat("HLNM");
    //
    // We list pertinent psStats.c functions here for debugging ease.
    //
    psTraceSetLevel(".", 0);
    psTraceSetLevel("p_psGetStatValue", 0);
    psTraceSetLevel("p_psVectorSampleMean", 0);
    psTraceSetLevel("p_psVectorMax", 0);
    psTraceSetLevel("p_psVectorMin", 0);
    psTraceSetLevel("p_psVectorCheckNonEmpty", 0);
    psTraceSetLevel("p_psVectorNValues", 0);
    psTraceSetLevel("p_psVectorClippedStats", 0);
    psTraceSetLevel("p_psNormalizeVectorRange", 0);
    psTraceSetLevel("psStatsAlloc", 0);
    psTraceSetLevel("p_psConvertToF32", 0);
    psTraceSetLevel("psVectorStats", 0);

    psStats *myStats    = NULL;
    psS32 testStatus      = true;
    psS32 globalTestStatus = true;
    psS32 i               = 0;
    psVector *maskVector= NULL;
    psVector *myGaussData  = NULL;
    // NOTE: These values were calculated by running the function on the data.
    // A: They must be changed if we adjust the number of data points.
    // B: We don't really know that they are correct.
    //    float realclippedMeanNoMask  = 0.0;
    //    float realclippedStdevNoMask = 0.0;
    //    float realclippedMeanWithMask  = 0.0;
    //    float realclippedStdevWithMask = 0.0;
    psS32 count           = 0;
    psS32 currentId       = psMemGetId();
    psS32 memLeaks        = 0;

    /*************************************************************************/
    /*  Allocate and initialize data structures                      */
    /*************************************************************************/
    myStats = psStatsAlloc(PS_STAT_CLIPPED_MEAN |
                           PS_STAT_CLIPPED_STDEV);

    myGaussData = psVectorAlloc(N, PS_TYPE_F32);
    myGaussData->n = myGaussData->nalloc;
    for (i=0;i<N;i++) {
        myGaussData->data.F32[i] = MY_MEAN - (MY_RANGE/1.9) +
                                   (MY_RANGE) * ((float) i) / ((float) N);
    }

    maskVector = psVectorAlloc(N, PS_TYPE_U8);
    maskVector->n = N;

    // Set the mask vector and calculate the expected maximum.
    for (i=0;i<N;i++) {
        if (i < (N/2)) {
            maskVector->data.U8[i] = 0;
            count++;
        } else {
            maskVector->data.U8[i] = 1;
        }
    }

    /*************************************************************************/
    /*  Call psVectorStats() with no vector mask.                    */
    /*************************************************************************/
    printPositiveTestHeader(stdout,
                            "psStats functions",
                            "PS_STAT_CLIPPED_MEAN: no vector mask");

    myStats = psVectorStats(myStats, myGaussData, NULL, NULL, 0);

    printf("Called psVectorStats() on a vector with no elements masked.\n");
    printf("The calculated clippedMean was %.2f\n", myStats->clippedMean);

    printFooter(stdout,
                "psVector functions",
                "PS_STAT_CLIPPED_MEAN/STDEV: no vector mask",
                testStatus);



    printPositiveTestHeader(stdout,
                            "psStats functions",
                            "PS_STAT_CLIPPED_STDEV: no vector mask");

    printf("Called psVectorStats() on a vector with no elements masked.\n");
    printf("The calculated clippedStdev was %.2f\n", myStats->clippedStdev);

    printFooter(stdout,
                "psVector functions",
                "PS_STAT_CLIPPED_MEAN/STDEV: no vector mask",
                testStatus);

    /*************************************************************************/
    /*  Call psVectorStats() with vector mask.                       */
    /*************************************************************************/
    printPositiveTestHeader(stdout,
                            "psStats functions",
                            "PS_STAT_CLIPPED_MEAN: vector mask");

    myStats = psVectorStats(myStats, myGaussData, NULL, maskVector, 1);

    printf("Called psVectorStats() on a vector with elements masked.\n");
    printf("The calculated clippedMean was %.2f\n", myStats->clippedMean);
    printFooter(stdout,
                "psVector functions",
                "PS_STAT_CLIPPED_MEAN/STDEV: vector mask",
                testStatus);



    printPositiveTestHeader(stdout,
                            "psStats functions",
                            "PS_STAT_CLIPPED_STDEV: vector mask");

    printf("Called psVectorStats() on a vector with elements masked.\n");
    printf("The calculated clippedStdev was %.2f\n", myStats->clippedStdev);
    printFooter(stdout,
                "psVector functions",
                "PS_STAT_CLIPPED_MEAN/STDEV: vector mask",
                testStatus);

    /*************************************************************************/
    /*  Deallocate data structures                                   */
    /*************************************************************************/
    printPositiveTestHeader(stdout,
                            "psStats functions",
                            "psStats(): deallocating memory");

    psFree(myStats);
    psFree(myGaussData);
    psFree(maskVector);

    psMemCheckCorruption(1);
    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psAbort(__func__,"Memory Leaks! (%d leaks)", memLeaks);
    }

    printFooter(stdout,
                "psVector functions",
                "psStats(): deallocating memory",
                testStatus);

    return (!globalTestStatus);
}
