//
// LDASTools frameCPP - A library implementing the LIGO/Virgo frame
// specification
//
// Copyright (C) 2018 California Institute of Technology
//
// LDASTools frameCPP is free software; you may redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 (GPLv2) of the
// License or at your discretion, any later version.
//
// LDASTools frameCPP is distributed in the hope that it will be useful, but
// without any warranty or even the implied warranty of merchantability
// or fitness for a particular purpose. See the GNU General Public
// License (GPLv2) for more details.
//
// Neither the names of the California Institute of Technology (Caltech),
// The Massachusetts Institute of Technology (M.I.T), The Laser
// Interferometer Gravitational-Wave Observatory (LIGO), nor the names
// of its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// You should have received a copy of the licensing terms for this
// software included in the file LICENSE located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE
//

#include <framecpp_config.h>

#include "../src/vect.hh"
#include "test.hh"

using FrameCPP::Vect;

/**
 * This checks to see if the default constructor has the expected attributes.
 */

bool
deftest( Vect& v )
{
    TSTART;

    TEST( v.getName( ) == "none" );
    TEST( v.getCompress( ) == Vect::NONE );
    TEST( v.getType( ) == FR_VECT_2S );
    TEST( v.getNData( ) == 0 );
    TEST( v.getNBytes( ) == 0 );
    TEST( v.getData( ) == 0 );
    TEST( v.getNDim( ) == 0 );

    try
    {
        v.getDimension( 0 );
        RES = false;
    }
    catch ( range_error& )
    {
    }

    TEST( v.getUnitY( ) == "" );
    TEND;
}

/**
 * This runs a variety of tests on a default constructed object.
 */
bool
defcon( )
{
    TSTART;

    //    cout << "Testing default constructor... ";
    {
        Vect v;
        TEST2( "Initial construction", deftest( v ) );

        // check expansion, should do nothing
        v.expand( );
        TEST2( "expansion of default", deftest( v ) );

        // check assignment & copy constructor to & from.
        v = v;
        TEST2( "assignment to self", deftest( v ) );

        Vect v2;
        v2 = v;
        TEST2( "assignment of default to default", deftest( v2 ) );

        REAL_8 data[ 8 ] = { 1.1243, 16.4562, 2346.7687, 12.326,
                             134.56, 24306.7, 134.13982, 137.78 };
        INT_4U dims[ 2 ] = { 2, 4 };
        Vect   v3( "test data", FR_VECT_8R, 2, dims, data, "unity" );
        v2 = v3;
        v2 = v;
        TEST2( "assignment of default to vect", deftest( v2 ) );
    }

    TMSGEND;
}

bool
bigtest( )
{
    TSTART;

    //    cout << "Testing large arrays... ";

    REAL_8* array = 0;

    array = new REAL_8[ 1000 ];
    for ( int i = 0; i < 1000; ++i )
    {
        array[ i ] = i;
    }
    unsigned int dims[ 3 ] = { 10, 10, 10 };

    Vect* p;
    p = new Vect( "test", 3, dims, array, "unity" );

    Vect va[ 10 ];
    for ( int i = 0; i < 10; ++i )
    {
        va[ i ] = *p;
    }

    delete p;
    delete[] array;

    TMSGEND;
}

bool
compressionTest( )
{
    const unsigned int ARRAY_SIZE = 10000;

    TSTART;

    //    cout << "Testing compression... " << flush;

    INT_2U* array = 0;

    array = new INT_2U[ ARRAY_SIZE ];
    for ( unsigned int i = 0; i < ARRAY_SIZE; i++ )
    {
        array[ i ] = i;
    }

    unsigned int dims[ 1 ] = { ARRAY_SIZE };
    Vect*        p = new Vect( "test", 1, dims, array, "unity" );

    RES = RES &&
        ( memcmp( array, p->getData( ), ARRAY_SIZE * sizeof( INT_2S ) ) == 0 );

#ifdef not_def
    cout << endl;
    for ( int i = 0; i < ARRAY_SIZE; ++i )
    {
        cout << reinterpret_cast< INT_2S* >( p->getData( ) )[ i ] << " ";
    }
    cout << endl;
#endif

    p->compress( Vect::GZIP, 9 );
    cout << "GZIP: ";
    cout << static_cast< float >( p->getNBytes( ) ) /
            ( p->getNData( ) * sizeof( INT_2S ) ) * 100.0
         << " " << endl;
    p->expand( );
    p->compress( Vect::DIFF );
    cout << "DIFF: ";
    cout << static_cast< float >( p->getNBytes( ) ) /
            ( p->getNData( ) * sizeof( INT_2S ) ) * 100.0
         << " " << endl;
    p->expand( );
    p->compress( Vect::GZIP_DIFF, 9 );
    cout << "GZIP_DIFF: ";
    cout << static_cast< float >( p->getNBytes( ) ) /
            ( p->getNData( ) * sizeof( INT_2S ) ) * 100.0
         << " " << endl;
    p->expand( );
    p->compress( Vect::DIFF_ZERO_SUPPRESS_SHORT );
    cout << "DIFF_ZERO_SUPPRESS_SHORT: ";
    cout << static_cast< float >( p->getNBytes( ) ) /
            ( p->getNData( ) * sizeof( INT_2S ) ) * 100.0
         << " " << endl;
    p->expand( );
    p->compress( Vect::DIFF_ZERO_SUPPRESS_SHORT_DIFF_GZIP_OTHER );
    cout << "DIFF_ZERO_SUPPRESS_SHORT_DIFF_GZIP_OTHER: ";
    cout << static_cast< float >( p->getNBytes( ) ) /
            ( p->getNData( ) * sizeof( INT_2S ) ) * 100.0
         << " " << endl;
    p->expand( );

#ifdef not_def
    cout << endl;
    for ( int i = 0; i < ARRAY_SIZE; ++i )
    {
        cout << reinterpret_cast< INT_2S* >( p->getData( ) )[ i ] << " ";
    }
    cout << endl;
#endif

    RES = RES &&
        ( memcmp( array, p->getData( ), ARRAY_SIZE * sizeof( INT_2S ) ) == 0 );

    delete[] array;
    delete p;

    TMSGEND;
}

main( )
{
    FrameCPP::Vect v;

    TSTART;
    TEST( defcon( ) );
    TEST( bigtest( ) );
    TEST( compressionTest( ) );

    if ( RES )
        return 0;
    else
        return 1;
}
