/*****************************************************************************
    This routine must ensure that the psHistogram structure is correctly
    allocated and deallocated by the procedure psHistogramAllocGeneric().
 *****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <pslib.h>
#include "tap.h"
#include "pstap.h"
#define ERROR_TOLERANCE 0.001

psS32 genericTest(psS32 numBins, psS32 lower, psS32 higher)
{
    // Allocate the psHistogram structure
    {
        psMemId id = psMemGetId();
        psVector *myBounds = psVectorAlloc(numBins+1, PS_TYPE_F32);
        myBounds->n = myBounds->nalloc;
        for (int i=0;i<numBins+1;i++)
        {
            myBounds->data.F32[i] = lower + ((higher - lower) / (float) numBins) *
                                    (float) i;
        }
        psHistogram *myHist = psHistogramAllocGeneric(myBounds);
        ok(myHist != NULL, "psHistogram allocated successfully");
        skip_start(myHist == NULL, 7, "Skipping tests because psHistogramAlloc() failed");
        ok(myHist->nums->n = numBins, "psHistogramAllocGeneric() set the correct number of bins");
        ok(myHist->bounds->n == numBins+1, "psHistogramAllocGeneric() set the correct number of bounds");
        bool errorFlag = false;
        for (int i=0;i<numBins;i++)
        {
            if (myHist->nums->data.F32[i] != 0.0) {
                diag("ERROR: myHist->nums->data.F32[%d] not initialized to 0.\n", i);
                errorFlag = false;
            }
            myHist->nums->data.F32[i] = 0.0;
        }
        ok(!errorFlag, "psHistogramAllocGeneric() initialized the data to 0.0");
        ok(myHist->minNum == 0, "psHistogramAllocGeneric() initialized minNum to 0.0");
        ok(myHist->maxNum == 0, "psHistogramAllocGeneric() initialized maxNum to 0.0");
        ok(myHist->uniform == false, "psHistogramAllocGeneric() initialized ->uniform to false");

        errorFlag = false;
        for (int i=0;i<numBins;i++)
        {
            psF32 expectedBound = (psF32) (i + 1);
            if (fabs(expectedBound - myHist->bounds->data.F32[i]) > ERROR_TOLERANCE) {
                diag("Bin number %d bounds: (%6.3f - %6.3f)\n", i,
                     myHist->bounds->data.F32[i],
                     myHist->bounds->data.F32[i+1]);
                diag("Was %f, expected %f\n", myHist->bounds->data.F32[i], expectedBound);
                errorFlag = true;
            }
        }
        ok(!errorFlag, "psHistogramAlloc() set the histogram bounds correctly");

        skip_end();
        psFree(myHist);
        psFree(myBounds);
        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");

    }
    return(1);
}


psS32 main()
{
    psLogSetFormat("HLNM");
    //
    // We list pertinent psStats.c functions here for debugging ease.
    //
    psTraceSetLevel(".", 0);
    psTraceSetLevel("p_psVectorBinDisect", 0);
    psTraceSetLevel("psHistogramAlloc", 0);
    psTraceSetLevel("psHistogramAllocGeneric", 0);
    psTraceSetLevel("UpdateHistogramBins", 0);
    psTraceSetLevel("psVectorHistogram", 0);
    plan_tests(36);

    genericTest(1, 1, 2);
    genericTest(2, 1, 3);
    genericTest(10, 1, 11);
    genericTest(20, 1, 21);
}
