/*****************************************************************************
    This routine must ensure that the psSpline1DAlloc() function properly
    allocates the spline data structure.  It allocates both linear and cubic
    splines with a variety of min/max ranges.
 *****************************************************************************/
#include <stdio.h>
#include "pslib.h"
#include "psTest.h"
#include "psMemory.h"
#include "psFunctions.h"

#define N 4
#define LINEAR 1
#define CUBIC 3

psS32 main()
{
    psS32 testStatus = true;
    psS32 memLeaks=0;
    psS32 i;
    psS32  currentId = psMemGetId();
    psSpline1D *tmpSpline;
    psVector* bounds;

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(): linear, normal");

    tmpSpline = psSpline1DAlloc(N, LINEAR, 1.0, 10.0);
    if (tmpSpline == NULL) {
        printf("ERROR: Could not allocate psSpline1D data structure\n");
        testStatus = false;
    }
    if (tmpSpline->spline == NULL) {
        printf("ERROR: Could not allocate psSpline1D->spline data structure\n");
        testStatus = false;
    }

    if (tmpSpline->n != N) {
        printf("ERROR: spline->n set incorrectly (%d)\n", tmpSpline->n);
        testStatus = false;
    }

    for (i=0;i<N;i++) {
        if (tmpSpline->spline[i] == NULL) {
            printf("ERROR: Could not allocate spline %d\n", i);
            testStatus = false;
        }
        if ((tmpSpline->spline[i])->n != LINEAR+1) {
            printf("ERROR: Spline created with order %d\n", (tmpSpline->spline[i])->n);
            testStatus = false;
        }
    }

    if (tmpSpline->knots == NULL) {
        printf("ERROR: Could not allocate psSpline1D->knots data structure\n");
        testStatus = false;
    }

    for (i=0;i<N+1;i++) {
        printf("psSpline1D->knots->data.F32[%d] is %f\n", i,
               tmpSpline->knots->data.F32[i]);
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): linear, normal",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(): linear, min/max are equal");

    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
    tmpSpline = psSpline1DAlloc(N, LINEAR, 1.0, 1.0);

    if (tmpSpline != NULL) {
        printf("ERROR: allocated psSpline1D data structure when min==max\n");
        testStatus = false;
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): linear, min/max are equal",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(): linear, min > max.");

    tmpSpline = psSpline1DAlloc(N, LINEAR, 1.0, -1.0);
    if (tmpSpline == NULL) {
        printf("ERROR: Could not allocate psSpline1D data structure\n");
        testStatus = false;
    }
    if (tmpSpline->spline == NULL) {
        printf("ERROR: Could not allocate psSpline1D->spline data structure\n");
        testStatus = false;
    }

    if (tmpSpline->n != N) {
        printf("ERROR: spline->n set incorrectly (%d)\n", tmpSpline->n);
        testStatus = false;
    }

    for (i=0;i<N;i++) {
        if (tmpSpline->spline[i] == NULL) {
            printf("ERROR: Could not allocate spline %d\n", i);
            testStatus = false;
        }
        if ((tmpSpline->spline[i])->n != LINEAR+1) {
            printf("ERROR: Spline created with order %d\n", (tmpSpline->spline[i])->n);
            testStatus = false;
        }
    }

    if (tmpSpline->knots == NULL) {
        printf("ERROR: Could not allocate psSpline1D->knots data structure\n");
        testStatus = false;
    }

    for (i=0;i<N+1;i++) {
        printf("psSpline1D->knots->data.F32[%d] is %f\n", i,
               tmpSpline->knots->data.F32[i]);
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): linear, min > max.",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(), cubic, normal");

    tmpSpline = psSpline1DAlloc(N, CUBIC, 1.0, 10.0);
    if (tmpSpline == NULL) {
        printf("ERROR: Could not allocate psSpline1D data structure\n");
        testStatus = false;
    }
    if (tmpSpline->spline == NULL) {
        printf("ERROR: Could not allocate psSpline1D->spline data structure\n");
        testStatus = false;
    }

    if (tmpSpline->n != N) {
        printf("ERROR: spline->n set incorrectly (%d)\n", tmpSpline->n);
        testStatus = false;
    }

    for (i=0;i<N;i++) {
        if (tmpSpline->spline[i] == NULL) {
            printf("ERROR: Could not allocate spline %d\n", i);
            testStatus = false;
        }
        if ((tmpSpline->spline[i])->n != CUBIC+1) {
            printf("ERROR: Spline created with order %d\n", (tmpSpline->spline[i])->n);
            testStatus = false;
        }
    }

    if (tmpSpline->knots == NULL) {
        printf("ERROR: Could not allocate psSpline1D->knots data structure\n");
        testStatus = false;
    }

    for (i=0;i<N+1;i++) {
        printf("psSpline1D->data.F32[%d] is %f\n", i,
               tmpSpline->knots->data.F32[i]);
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): cubic, normal",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(): cubic, min/max are equal");

    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message");
    tmpSpline = psSpline1DAlloc(N, CUBIC, 1.0, 1.0);

    if (tmpSpline != NULL) {
        printf("ERROR: allocated psSpline1D data structure when min==max\n");
        testStatus = false;
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): cubic, min/max are equal",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAlloc(): cubic, min > max.");

    tmpSpline = psSpline1DAlloc(N, CUBIC, 1.0, -1.0);
    if (tmpSpline == NULL) {
        printf("ERROR: Could not allocate psSpline1D data structure\n");
        testStatus = false;
    }
    if (tmpSpline->spline == NULL) {
        printf("ERROR: Could not allocate psSpline1D->spline data structure\n");
        testStatus = false;
    }

    if (tmpSpline->n != N) {
        printf("ERROR: spline->n set incorrectly (%d)\n", tmpSpline->n);
        testStatus = false;
    }

    for (i=0;i<N;i++) {
        if (tmpSpline->spline[i] == NULL) {
            printf("ERROR: Could not allocate spline %d\n", i);
            testStatus = false;
        }
        if ((tmpSpline->spline[i])->n != CUBIC+1) {
            printf("ERROR: Spline created with order %d\n", (tmpSpline->spline[i])->n);
            testStatus = false;
        }
    }

    if (tmpSpline->knots == NULL) {
        printf("ERROR: Could not allocate psSpline1D->knots data structure\n");
        testStatus = false;
    }

    for (i=0;i<N+1;i++) {
        printf("psSpline1D->knots->data.F32[%d] is %f\n", i,
               tmpSpline->knots->data.F32[i]);
    }

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

    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAlloc(): cubic, min > max.",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAllocGeneric(): linear, normal");

    bounds = psVectorAlloc(5,PS_TYPE_F32);
    bounds->n = bounds->nalloc;
    for(psU32 n = 0; n < 5; n++ ) {
        bounds->data.F32[n] = (n+1) * 2;
    }
    tmpSpline = psSpline1DAllocGeneric(bounds, LINEAR);
    if (tmpSpline == NULL) {
        printf("ERROR: Could not allocate psSpline1D data structure\n");
        testStatus = false;
    }
    if (tmpSpline->spline == NULL) {
        printf("ERROR: Could not allocate psSpline1D->spline data structure\n");
        testStatus = false;
    }

    if (tmpSpline->n != N) {
        printf("ERROR: spline->n set incorrectly (%d)\n", tmpSpline->n);
        testStatus = false;
    }

    for (i=0;i<N;i++) {
        if (tmpSpline->spline[i] == NULL) {
            printf("ERROR: Could not allocate spline %d\n", i);
            testStatus = false;
        }
        if ((tmpSpline->spline[i])->n != LINEAR+1) {
            printf("ERROR: Spline created with order %d\n", (tmpSpline->spline[i])->n);
            testStatus = false;
        }
    }

    if (tmpSpline->knots == NULL) {
        printf("ERROR: Could not allocate psSpline1D->knots data structure\n");
        testStatus = false;
    }

    for (i=0;i<N+1;i++) {
        printf("psSpline1D->knots->data.F32[%d] is %f\n", i,
               tmpSpline->knots->data.F32[i]);
    }
    psFree(bounds);
    psFree(tmpSpline);

    psMemCheckCorruption(1);
    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psError(PS_ERR_UNKNOWN,true,"Memory Leaks! (%d leaks)", memLeaks);
        testStatus = false;
    }
    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAllocGeneric(): linear, normal",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAllocGeneric(): negative order");

    bounds = psVectorAlloc(5,PS_TYPE_F32);
    bounds->n = bounds->nalloc;
    for(psU32 n = 0; n < 5; n++ ) {
        bounds->data.F32[n] = (n+1) * 2;
    }
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
    tmpSpline = psSpline1DAllocGeneric(bounds, -1);
    if (tmpSpline != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return null for negative order");
        return 10;
    }
    psFree(bounds);
    psMemCheckCorruption(1);
    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psError(PS_ERR_UNKNOWN,true,"Memory Leaks! (%d leaks)", memLeaks);
        testStatus = false;
    }
    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAllocGeneric(): negative order",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAllocGeneric(): bound equal to NULL");

    bounds = NULL;
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
    tmpSpline = psSpline1DAllocGeneric(bounds, LINEAR);
    if (tmpSpline != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return null for bounds equal to NULL");
        return 20;
    }
    psMemCheckCorruption(1);
    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psError(PS_ERR_UNKNOWN,true,"Memory Leaks! (%d leaks)", memLeaks);
        testStatus = false;
    }
    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAllocGeneric(): bound equal to NULL",
                testStatus);

    /****************************************************************************/
    /****************************************************************************/
    testStatus = true;
    printPositiveTestHeader(stdout,
                            "psFunction functions",
                            "psSpline1DAllocGeneric(): bounds with zero elements");

    bounds = psVectorAlloc(5,PS_TYPE_F32);
    bounds->n = 0;
    psLogMsg(__func__,PS_LOG_INFO,"Following should generate an error message.");
    tmpSpline = psSpline1DAllocGeneric(bounds, LINEAR);
    if (tmpSpline != NULL) {
        psError(PS_ERR_UNKNOWN,true,"Did not return null for negative order");
        return 30;
    }
    psFree(bounds);
    psMemCheckCorruption(1);
    memLeaks = psMemCheckLeaks(currentId,NULL,stderr,false);
    if (0 != memLeaks) {
        psError(PS_ERR_UNKNOWN,true,"Memory Leaks! (%d leaks)", memLeaks);
        testStatus = false;
    }
    printFooter(stdout,
                "psFunctions functions",
                "psSpline1DAllocGeneric(): bounds with zero elements",
                testStatus);

    return (!testStatus);
}
