/*****************************************************************************
    This routine must ensure that the psHistogram structure is correctly
    allocated and deallocated by the procedure psHistogramAlloc().
 *****************************************************************************/
#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();
        psHistogram *myHist = psHistogramAlloc(lower, higher, numBins);
        ok(myHist != NULL, "psHistogram allocated successfully");
        skip_start(myHist == NULL, 7, "Skipping tests because psHistogramAlloc() failed");
        ok(myHist->nums->n = numBins, "psHistogramAlloc() set the correct number of bins");
        ok(myHist->bounds->n == numBins+1, "psHistogramAlloc() 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.U32[%d] not initialized to 0.\n", i);
                errorFlag = true;
            }
            myHist->nums->data.F32[i] = 0.0;
        }
        ok(!errorFlag, "psHistogramAlloc() initialized the data to 0.0");
        ok(myHist->minNum == 0, "psHistogramAlloc() initialized minNum to 0.0");
        ok(myHist->maxNum == 0, "psHistogramAlloc() initialized maxNum to 0.0");
        ok(myHist->uniform == true, "psHistogramAlloc() initialized ->uniform to true");

        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);
        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
    }

    // XXX: How should we test these kinds of things?
    if (0) {
        psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
        psHistogram *myHist = psHistogramAlloc(higher, lower, 1);
        if (myHist != NULL) {
            printf("ERROR: myHist != NULL\n");
        }
    }
    return(1);
}

psS32 main()
{
    psLogSetFormat("HLNM");
    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);
}
