/** \file
 *
 *  Contains the test cases for the NetCdf3Reader class
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef _NETCDF3READER_TEST_H_
#define _NETCDF3READER_TEST_H_

//#ifndef __arm__
#include "utils/NetCdf3Reader.h"
//#endif

#include <cxxtest/TestSuite.h>

/**
 * %Units tests for class NetCdf3Reader
 *
 * \ingroup utils
 */
class NetCdf3Reader_Test : public CxxTest::TestSuite
{
public:

    // Constructor/Destructor test
    void testConstructorDestructor( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            delete netCdf3Reader;
        }
//#endif
    }

    // GetAttsDimsVars test
    void testFindAttsDimsVars( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            TS_ASSERT( netCdf3Reader->findDim( "latitude" ) );
            TS_ASSERT( netCdf3Reader->findDim( "longitude" ) );

            TS_ASSERT( netCdf3Reader->findAtt( "name" ) );

            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "distance" ) );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->findAtt( *var, "units" ) );
            }

            delete netCdf3Reader;
        }
//#endif
    }

    // Read(String,Att) test
    void testReadStringAtt( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            Str attString;
            NetCdf3Reader::NetCdfAtt* att( netCdf3Reader->findAtt( "name" ) );
            TS_ASSERT( att );
            if( att )
            {
                TS_ASSERT( netCdf3Reader->readAttStr( attString, att ) );
                TS_ASSERT_EQUALS( attString, "Distance from shore, central California region" );
            }

            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "distance" ) );
            TS_ASSERT( var );
            if( var )
            {
                att = netCdf3Reader->findAtt( *var, "units" );
                TS_ASSERT( att );
                if( att )
                {
                    TS_ASSERT( netCdf3Reader->readAttStr( attString, att ) );
                    TS_ASSERT_EQUALS( attString, "m" );
                }
            }

            delete netCdf3Reader;
        }
//#endif
    }

    // Read(Att) test
    void testReadAtt( void )
    {
        float theFloat;
        double theDouble;
        int theInt;
        NetCdf3Reader::NetCdfAtt* att;
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        att = netCdf3Reader->findAtt( "double" );
        TS_ASSERT( att );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theFloat, NetCdf3Reader::NC_FLOAT, att ) );
        TS_ASSERT_EQUALS( theFloat, ( float ) 1234.56789 );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theDouble, NetCdf3Reader::NC_DOUBLE, att ) );
        TS_ASSERT_EQUALS( theDouble, ( double ) 1234.56789 );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theInt, NetCdf3Reader::NC_INT, att ) );
        TS_ASSERT_EQUALS( theInt, ( int ) 1234.56789 );

        att = netCdf3Reader->findAtt( "float" );
        TS_ASSERT( att );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theFloat, NetCdf3Reader::NC_FLOAT, att ) );
        TS_ASSERT_EQUALS( theFloat, ( float ) 12.345F );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theDouble, NetCdf3Reader::NC_DOUBLE, att ) );
        TS_ASSERT_EQUALS( theDouble, ( double ) 12.345F );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theInt, NetCdf3Reader::NC_INT, att ) );
        TS_ASSERT_EQUALS( theInt, ( int ) 12.345F );

        att = netCdf3Reader->findAtt( "long" );
        TS_ASSERT( att );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theFloat, NetCdf3Reader::NC_FLOAT, att ) );
        TS_ASSERT_EQUALS( theFloat, ( float ) 123456789 );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theDouble, NetCdf3Reader::NC_DOUBLE, att ) );
        TS_ASSERT_EQUALS( theDouble, ( double ) 123456789 );
        TS_ASSERT( netCdf3Reader->readAtt( ( void* ) &theInt, NetCdf3Reader::NC_INT, att ) );
        TS_ASSERT_EQUALS( theInt, ( int ) 123456789 );

    }

    // Read(Float,Var,Index1) test
    void testReadFloatVar1D( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            float theFloat;
            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "latitude" ) );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read1D( &theFloat, NetCdf3::NC_FLOAT, *var, 0 ) );
                TS_ASSERT_DELTA( theFloat, 35.0, 1e-4 );
                TS_ASSERT( netCdf3Reader->read1D( &theFloat, NetCdf3::NC_FLOAT, *var, 280 ) );
                TS_ASSERT_DELTA( theFloat, 37.8, 1e-4 );
            }
            var = netCdf3Reader->findVar( "longitude" );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read1D( &theFloat, NetCdf3::NC_FLOAT, *var, 0 ) );
                TS_ASSERT_DELTA( theFloat, -123.8, 1e-4 );
                TS_ASSERT( netCdf3Reader->read1D( &theFloat, NetCdf3::NC_FLOAT, *var, 280 ) );
                TS_ASSERT_DELTA( theFloat, -121.0, 1e-4 );
            }
            var = netCdf3Reader->findVar( "distance" );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read2D( &theFloat, NetCdf3::NC_FLOAT, *var, 0, 0 ) );
                TS_ASSERT_DELTA( theFloat, 224.5141, 1e-4 );
            }
            delete netCdf3Reader;
        }
//#endif
    }

    // Read(Float,Var,Index1a,Index1b) test
    void testReadFloatVar1DRange( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            float theFloats[3];
            double theDoubles[3];
            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "longitude" ) );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read1DArray( theFloats, NetCdf3::NC_FLOAT, *var, 30, 32 ) );
                TS_ASSERT_DELTA( theFloats[0], -123.50, 1e-4 );
                TS_ASSERT_DELTA( theFloats[1], -123.49, 1e-4 );
                TS_ASSERT_DELTA( theFloats[2], -123.48, 1e-4 );
                TS_ASSERT( netCdf3Reader->read1DArray( theDoubles, NetCdf3::NC_DOUBLE, *var, 30, 32 ) );
                TS_ASSERT_DELTA( theFloats[0], -123.50, 1e-4 );
                TS_ASSERT_DELTA( theFloats[1], -123.49, 1e-4 );
                TS_ASSERT_DELTA( theFloats[2], -123.48, 1e-4 );
            }
            delete netCdf3Reader;
        }
//#endif
    }

    // ReadFloatVar,Index1,Index2) test
    void testReadFloatVar2D( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );

        // Should fail...
        TS_ASSERT_DIFFERS( ( int )( size_t ) netCdf3Reader, 0 );

        if( NULL != netCdf3Reader )
        {
            float theFloat;
            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "distance" ) );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read2D( &theFloat, NetCdf3::NC_FLOAT, *var, 0, 0 ) );
                TS_ASSERT_DELTA( theFloat, 224.5141, 1e-4 );
                TS_ASSERT( netCdf3Reader->read2D( &theFloat, NetCdf3::NC_FLOAT, *var, 140, 140 ) );
                TS_ASSERT_DELTA( theFloat, 41.8181, 1e-4 );
                TS_ASSERT( netCdf3Reader->read2D( &theFloat, NetCdf3::NC_FLOAT, *var, 280, 280 ) );
                TS_ASSERT_DELTA( theFloat, 96.3373, 1e-4 );
            }
            delete netCdf3Reader;
        }
//#endif
    }

    // ReadFloat(Var,Index1a,Index1b,Index2a,Index2b) test
    void testReadFloatVar2DRange( void )
    {
//#ifndef __arm__
        NetCdf3Reader* netCdf3Reader = NetCdf3Reader::NewNetCdf3Reader( "./Resources/NetCdfReader_Test.nc" );
        TS_ASSERT( netCdf3Reader );

        if( NULL != netCdf3Reader )
        {
            float theFloats[3][3];
            NetCdf3Reader::NetCdfVar* var( netCdf3Reader->findVar( "distance" ) );
            TS_ASSERT( var );
            if( var )
            {
                TS_ASSERT( netCdf3Reader->read2DArray( theFloats, NetCdf3::NC_FLOAT, *var, 30, 32, 30, 32 ) );
                TS_ASSERT_DELTA( theFloats[0][0], 182.2367, 1e-4 );
                TS_ASSERT_DELTA( theFloats[0][1], 181.5249, 1e-4 );
                TS_ASSERT_DELTA( theFloats[0][2], 180.8149, 1e-4 );
                TS_ASSERT_DELTA( theFloats[1][0], 181.5502, 1e-4 );
                TS_ASSERT_DELTA( theFloats[1][1], 180.8359, 1e-4 );
                TS_ASSERT_DELTA( theFloats[1][2], 180.1232, 1e-4 );
                TS_ASSERT_DELTA( theFloats[2][0], 180.8680, 1e-4 );
                TS_ASSERT_DELTA( theFloats[2][1], 180.1511, 1e-4 );
                TS_ASSERT_DELTA( theFloats[2][2], 179.4357, 1e-4 );
            }
            delete netCdf3Reader;
        }
//#endif
    }
};

#endif // _NETCDF3READER_TEST_H
