/** @file  tst_psMatrix_07.c
 *
 *  @brief Test driver for psMatrix vector conversion functions
 *
 *  This test driver contains the following tests for psMatrix test point 7:
 *     A)  Create input and output images and vectors
 *     B)  Convert matrix to PS_DIMEN_VECTOR vector
 *     C)  Attempt to use null image input argument
 *     D)  Convert matrix to PS_DIMEN_TRANSV vector
 *     E)  Improper image size
 *     F)  Convert PS_DIMEN_VECTOR vector to matrix
 *     G)  Attempt to use null input vector argument
 *     H)  Convert PS_DIMEN_TRANSV vector to matrix
 *     I)  Free input and output images and vectors
 *
 *  @author  Ross Harman, MHPCC
 *
 *  @version $Revision: 1.8 $  $Name: not supported by cvs2svn $
 *  @date  $Date: 2004-12-10 22:55:17 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

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


#define TOLERANCE 0.000001

#define CHECK_MATRIX(IMAGE,TRUTH)                                                                        \
for(psU32 i=0; i<IMAGE->numRows; i++) {                                                                  \
    for(psU32 j=0; j<IMAGE->numCols; j++) {                                                              \
        if(IMAGE->type.type == PS_TYPE_F64) {                                                            \
            if(fabs(IMAGE->data.F64[i][j]-TRUTH[i][j]) > TOLERANCE) {                                    \
                printf("Matrix values at element %d, %d don't agree %lf vs %lf\n", i, j,                 \
                       IMAGE->data.F64[i][j], TRUTH[i][j]);                                              \
            }                                                                                            \
        } else if(IMAGE->type.type == PS_TYPE_F32){                                                      \
            if(fabs(IMAGE->data.F32[i][j]-TRUTH[i][j]) > TOLERANCE) {                                    \
                printf("Matrix values at element %d, %d don't agree %f vs %lf\n", i, j,                  \
                       IMAGE->data.F32[i][j], TRUTH[i][j]);                                              \
            }                                                                                            \
        }                                                                                                \
    }                                                                                                    \
}

#define CHECK_VECTOR(VECTOR)                                                                                 \
for(psU32 i=0; i<VECTOR->n; i++) {                                                                       \
    if(VECTOR->type.type == PS_TYPE_F64) {                                                               \
        if(fabs(VECTOR->data.F64[i]-truthVector[i]) > TOLERANCE) {                                       \
            printf("Vector values at element %d don't agree %lf vs %lf\n", i,                            \
                   VECTOR->data.F64[i], truthVector[i]);                                                 \
        }                                                                                                \
    } else if(VECTOR->type.type == PS_TYPE_F32){                                                         \
        if(fabs(VECTOR->data.F32[i]-truthVector[i]) > TOLERANCE) {                                       \
            printf("Vector values at element %d don't agree %f vs %lf\n", i,                             \
                   VECTOR->data.F32[i], truthVector[i]);                                                 \
        }                                                                                                \
    }                                                                                                    \
}


psS32 main(psS32 argc, char* argv[])
{
    psVector *v1 = NULL;
    psVector *tempVector = NULL;
    psImage *tempImage = NULL;
    psImage *m1 = NULL;
    psVector *v2 = NULL;
    psVector *v3 = NULL;
    psImage *m2 = NULL;
    psImage *m3 = NULL;
    psImage *m4 = NULL;
    psImage *badImage = NULL;

    double truthVector[3] = {0.0, 1.0, 2.0};
    double truthMatrix[3][1] = {{0.0}, {1.0}, {2.0}};

    // Test A - Create input and output images
    printPositiveTestHeader(stdout, "psMatrix", "Create input and output images and vectors");
    v1 = (psVector*)psVectorAlloc(3, PS_TYPE_F64);
    m1 = (psImage*)psImageAlloc(1, 3, PS_TYPE_F64);
    v2 = (psVector*)psVectorAlloc(3, PS_TYPE_F64);
    m2 = (psImage*)psImageAlloc(1, 3, PS_TYPE_F64);
    m3 = (psImage*)psImageAlloc(3, 1, PS_TYPE_F64);
    m4 = (psImage*)psImageAlloc(3, 1, PS_TYPE_F64);
    badImage = (psImage*)psImageAlloc(2, 2, PS_TYPE_F64);
    m1->data.F64[0][0] = 0.0;
    m1->data.F64[1][0] = 1.0;
    m1->data.F64[2][0] = 2.0;
    v2->data.F64[0] = 0.0;
    v2->data.F64[1] = 1.0;
    v2->data.F64[2] = 2.0;
    v2->n = 3;
    m4->data.F64[0][0] = 0.0;
    m4->data.F64[0][1] = 1.0;
    m4->data.F64[0][2] = 2.0;
    printFooter(stdout, "psMatrix", "Create input and output images and vectors", true);


    // Test B - Convert matrix to PS_DIMEN_VECTOR vector
    printPositiveTestHeader(stdout, "psMatrix", "Convert matrix to PS_DIMEN_VECTOR vector");
    tempVector = v1;
    v1 = psMatrixToVector(v1, m1);
    CHECK_VECTOR(v1);
    if(v1->type.dimen != PS_DIMEN_VECTOR) {
        printf("Error: Resulting image is not PS_DIMEN_VECTOR\n");
    } else if(v1 != tempVector) {
        printf("Error: Return pointer not equal to output argument pointer\n");
    }
    printFooter(stdout, "psMatrix", "Convert matrix to PS_DIMEN_VECTOR vector", true);


    // Test C - Attempt to use null image input argument
    printNegativeTestHeader(stdout,"psMatrix", "Attempt to use null image input argument",
                            "Invalid operation: inImage or its data is NULL.", 0);
    v1 = psMatrixToVector(v1, NULL);
    printFooter(stdout, "psMatrix", "Attempt to use null image input argument", true);


    // Test D - Convert matrix to PS_DIMEN_TRANSV vector
    printPositiveTestHeader(stdout, "psMatrix", "Convert matrix to PS_DIMEN_TRANSV vector");
    v3 = psVectorAlloc(3, PS_TYPE_F64);
    v3->type.dimen = PS_DIMEN_TRANSV;
    psMatrixToVector(v3, m4);
    CHECK_VECTOR(v3);
    if(v3->type.dimen != PS_DIMEN_TRANSV) {
        printf("Error: Resulting image is not PS_DIMEN_TRANSV\n");
    } else if(v3 != tempVector) {
        printf("Error: Return pointer not equal to output argument pointer\n");
    }
    printFooter(stdout, "psMatrix", "Convert matrix to PS_DIMEN_TRANSV vector", true);


    // Test E - Improper image size
    printNegativeTestHeader(stdout,"psMatrix", "Improper image size",
                            "Image does not have dim with 1 col or 1 row: (2 x 2).", 0);
    psMatrixToVector(v1, badImage);
    printFooter(stdout, "psMatrix", "Improper image size", true);


    // Test F - Convert PS_DIMEN_VECTOR vector to matrix
    printPositiveTestHeader(stdout, "psMatrix", "Convert PS_DIMEN_VECTOR vector to matrix");
    tempImage = m2;
    m2 = psVectorToMatrix(m2, v2);
    CHECK_MATRIX(m2,truthMatrix);
    if(m2->type.dimen != PS_DIMEN_IMAGE) {
        printf("Error: Resulting image is not PS_DIMEN_IMAGE\n");
    } else if(m2 != tempImage) {
        printf("Error: Return pointer not equal to output argument pointer\n");
    }
    printFooter(stdout, "psMatrix", "Convert PS_DIMEN_VECTOR vector to matrix", true);


    // Test G - Attempt to use null input vector argument
    printNegativeTestHeader(stdout,"psMatrix", "Attempt to use null input vector argument",
                            "Invalid operation: inVector or its data is NULL.", 0);
    psVectorToMatrix(m2, NULL);
    printFooter(stdout, "psMatrix", "Attempt to use null input vector argument", true);


    // Test H - Convert PS_DIMEN_TRANSV vector to matrix
    printPositiveTestHeader(stdout, "psMatrix", "Convert PS_DIMEN_TRANSV vector to matrix");
    v2->type.dimen = PS_DIMEN_TRANSV;
    tempImage = m3;
    psVectorToMatrix(m3, v2);
    CHECK_MATRIX(m3, truthMatrix);
    if(m3->type.dimen != PS_DIMEN_IMAGE) {
        printf("Error: Resulting image is not PS_DIMEN_IMAGE\n");
    } else if(m3 != tempImage) {
        printf("Error: Return pointer not equal to output argument pointer\n");
    }
    printFooter(stdout, "psMatrix", "Convert PS_DIMEN_TRANSV vector to matrix", true);


    // Test I - Free input and output images
    printPositiveTestHeader(stdout, "psMatrix", "Free input and output images and vectors");
    psFree(m1);
    psFree(v1);
    psFree(m2);
    psFree(v2);
    psFree(v3);
    psFree(m3);
    psFree(m4);
    psFree(badImage);
    if( psMemCheckLeaks(0, NULL, stdout, false) != 0) {
        psError(PS_ERR_UNKNOWN,true,"Memory leaks detected.");
        return 10;
    }
    psS32 nBad = psMemCheckCorruption(0);
    if(nBad) {
        printf("ERROR: Found %d bad memory blocks\n", nBad);
    }
    printFooter(stdout, "psMatrix" ,"Free input and output images and vectors", true);

    return 0;
}
