//
// LDASTools frameCPP - Test Dimension class public API
//
// This test verifies that the Dimension class public API methods are properly
// implemented and link correctly. This addresses the issue where GetNx(),
// GetDx(), GetStartX(), GetUnitX(), SetNx(), SetDx(), SetStartX(), and
// operators were declared but not defined, causing linker errors.
//

#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>

#include "framecpp/Dimension.hh"

#include <iostream>

using namespace FrameCPP;

// Test fixture for Dimension tests
struct DimensionFixture
{
    DimensionFixture( )
    {
        FrameCPP::Initialize( );
    }
};

BOOST_FIXTURE_TEST_SUITE( DimensionTestSuite, DimensionFixture )

//=============================================================================
// Constructor Tests
//=============================================================================

BOOST_AUTO_TEST_CASE( test_default_constructor )
{
    Dimension dim;

    // Default constructor should initialize to well-defined values
    // Verify against the public constants defined in Dimension class
    BOOST_CHECK_EQUAL( dim.GetNx( ), Dimension::DEFAULT_NX );
    BOOST_CHECK_EQUAL( dim.GetDx( ), Dimension::DEFAULT_DX );
    BOOST_CHECK_EQUAL( dim.GetStartX( ), Dimension::DEFAULT_STARTX );
    BOOST_CHECK_EQUAL( dim.GetUnitX( ), "" ); // Empty string by design
}

BOOST_AUTO_TEST_CASE( test_parameterized_constructor )
{
    const Dimension::nx_type     expected_nx = 1024;
    const Dimension::dx_type     expected_dx = 1.0 / 16384.0;
    const char*                  expected_unit = "sec";
    const Dimension::startX_type expected_start = 1234567890.5;

    Dimension dim( expected_nx, expected_dx, expected_unit, expected_start );

    // Verify all values are correctly set
    BOOST_CHECK_EQUAL( dim.GetNx( ), expected_nx );
    BOOST_CHECK_EQUAL( dim.GetDx( ), expected_dx );
    BOOST_CHECK_EQUAL( dim.GetUnitX( ), expected_unit );
    BOOST_CHECK_EQUAL( dim.GetStartX( ), expected_start );
}

BOOST_AUTO_TEST_CASE( test_copy_constructor )
{
    Dimension original( 2048, 0.0001, "meters", 42.0 );
    Dimension copy( original );

    // Verify copy has same values
    BOOST_CHECK_EQUAL( copy.GetNx( ), original.GetNx( ) );
    BOOST_CHECK_EQUAL( copy.GetDx( ), original.GetDx( ) );
    BOOST_CHECK_EQUAL( copy.GetUnitX( ), original.GetUnitX( ) );
    BOOST_CHECK_EQUAL( copy.GetStartX( ), original.GetStartX( ) );
}

//=============================================================================
// Getter Method Tests
//=============================================================================

BOOST_AUTO_TEST_CASE( test_getter_GetNx )
{
    Dimension dim( 512, 1.0, "Hz", 0.0 );

    BOOST_CHECK_EQUAL( dim.GetNx( ), 512 );
}

BOOST_AUTO_TEST_CASE( test_getter_GetDx )
{
    const double dx_value = 1.0 / 8192.0;
    Dimension    dim( 100, dx_value, "sec", 0.0 );

    BOOST_CHECK_EQUAL( dim.GetDx( ), dx_value );
}

BOOST_AUTO_TEST_CASE( test_getter_GetStartX )
{
    const double start_value = 1000000000.123456;
    Dimension    dim( 100, 1.0, "sec", start_value );

    BOOST_CHECK_EQUAL( dim.GetStartX( ), start_value );
}

BOOST_AUTO_TEST_CASE( test_getter_GetUnitX )
{
    const char* unit_string = "strain";
    Dimension   dim( 100, 1.0, unit_string, 0.0 );

    BOOST_CHECK_EQUAL( dim.GetUnitX( ), unit_string );
}

//=============================================================================
// Setter Method Tests
//=============================================================================

BOOST_AUTO_TEST_CASE( test_setter_SetNx )
{
    Dimension dim( 100, 1.0, "sec", 0.0 );

    const Dimension::nx_type new_nx = 4096;
    dim.SetNx( new_nx );

    BOOST_CHECK_EQUAL( dim.GetNx( ), new_nx );
}

BOOST_AUTO_TEST_CASE( test_setter_SetDx )
{
    Dimension dim( 100, 1.0, "sec", 0.0 );

    const Dimension::dx_type new_dx = 0.000125;
    dim.SetDx( new_dx );

    BOOST_CHECK_EQUAL( dim.GetDx( ), new_dx );
}

BOOST_AUTO_TEST_CASE( test_setter_SetStartX )
{
    Dimension dim( 100, 1.0, "sec", 0.0 );

    const Dimension::startX_type new_start = 9876543210.5;
    dim.SetStartX( new_start );

    BOOST_CHECK_EQUAL( dim.GetStartX( ), new_start );
}

BOOST_AUTO_TEST_CASE( test_setters_combined )
{
    Dimension dim; // Default constructor

    // Set all values using setters
    dim.SetNx( 8192 );
    dim.SetDx( 0.5 );
    dim.SetStartX( 100.25 );

    // Verify all values
    BOOST_CHECK_EQUAL( dim.GetNx( ), 8192 );
    BOOST_CHECK_EQUAL( dim.GetDx( ), 0.5 );
    BOOST_CHECK_EQUAL( dim.GetStartX( ), 100.25 );
}

//=============================================================================
// Operator Tests
//=============================================================================

BOOST_AUTO_TEST_CASE( test_operator_assignment )
{
    Dimension original( 1024, 0.001, "volts", 555.5 );
    Dimension assigned;

    assigned = original;

    // Verify assigned has same values as original
    BOOST_CHECK_EQUAL( assigned.GetNx( ), original.GetNx( ) );
    BOOST_CHECK_EQUAL( assigned.GetDx( ), original.GetDx( ) );
    BOOST_CHECK_EQUAL( assigned.GetUnitX( ), original.GetUnitX( ) );
    BOOST_CHECK_EQUAL( assigned.GetStartX( ), original.GetStartX( ) );
}

BOOST_AUTO_TEST_CASE( test_operator_assignment_self )
{
    Dimension dim( 2048, 0.002, "amperes", 777.7 );

    // Self-assignment should not crash
    dim = dim;

    // Values should remain unchanged
    BOOST_CHECK_EQUAL( dim.GetNx( ), 2048 );
    BOOST_CHECK_EQUAL( dim.GetDx( ), 0.002 );
    BOOST_CHECK_EQUAL( dim.GetUnitX( ), "amperes" );
    BOOST_CHECK_EQUAL( dim.GetStartX( ), 777.7 );
}

BOOST_AUTO_TEST_CASE( test_operator_equality_same_values )
{
    Dimension dim1( 512, 0.125, "meters", 42.0 );
    Dimension dim2( 512, 0.125, "meters", 42.0 );

    BOOST_CHECK( dim1 == dim2 );
    BOOST_CHECK( !( dim1 != dim2 ) );
}

BOOST_AUTO_TEST_CASE( test_operator_equality_different_nx )
{
    Dimension dim1( 512, 0.125, "meters", 42.0 );
    Dimension dim2( 1024, 0.125, "meters", 42.0 );

    BOOST_CHECK( dim1 != dim2 );
    BOOST_CHECK( !( dim1 == dim2 ) );
}

BOOST_AUTO_TEST_CASE( test_operator_equality_different_dx )
{
    Dimension dim1( 512, 0.125, "meters", 42.0 );
    Dimension dim2( 512, 0.250, "meters", 42.0 );

    BOOST_CHECK( dim1 != dim2 );
    BOOST_CHECK( !( dim1 == dim2 ) );
}

BOOST_AUTO_TEST_CASE( test_operator_equality_different_unit )
{
    Dimension dim1( 512, 0.125, "meters", 42.0 );
    Dimension dim2( 512, 0.125, "feet", 42.0 );

    BOOST_CHECK( dim1 != dim2 );
    BOOST_CHECK( !( dim1 == dim2 ) );
}

BOOST_AUTO_TEST_CASE( test_operator_equality_different_start )
{
    Dimension dim1( 512, 0.125, "meters", 42.0 );
    Dimension dim2( 512, 0.125, "meters", 43.0 );

    BOOST_CHECK( dim1 != dim2 );
    BOOST_CHECK( !( dim1 == dim2 ) );
}

//=============================================================================
// Integration Tests
//=============================================================================

BOOST_AUTO_TEST_CASE( test_realistic_time_series_dimension )
{
    // Typical time-series dimension: 16384 samples at 16384 Hz
    const Dimension::nx_type     num_samples = 16384;
    const Dimension::dx_type     sample_rate = 1.0 / 16384.0; // seconds per sample
    const char*                  unit = "sec";
    const Dimension::startX_type gps_time = 1234567890.0;

    Dimension time_dim( num_samples, sample_rate, unit, gps_time );

    BOOST_CHECK_EQUAL( time_dim.GetNx( ), num_samples );
    BOOST_CHECK_EQUAL( time_dim.GetDx( ), sample_rate );
    BOOST_CHECK_EQUAL( time_dim.GetUnitX( ), unit );
    BOOST_CHECK_EQUAL( time_dim.GetStartX( ), gps_time );

    // Calculate total duration
    double total_duration = num_samples * sample_rate;
    BOOST_CHECK_CLOSE( total_duration, 1.0, 0.001 ); // Should be 1 second
}

BOOST_AUTO_TEST_CASE( test_modify_existing_dimension )
{
    // Start with one dimension
    Dimension dim( 1024, 0.01, "Hz", 100.0 );

    // Modify it to new values
    dim.SetNx( 2048 );
    dim.SetDx( 0.005 );
    dim.SetStartX( 200.0 );

    // Verify modifications
    BOOST_CHECK_EQUAL( dim.GetNx( ), 2048 );
    BOOST_CHECK_EQUAL( dim.GetDx( ), 0.005 );
    BOOST_CHECK_EQUAL( dim.GetUnitX( ), "Hz" ); // Unit unchanged
    BOOST_CHECK_EQUAL( dim.GetStartX( ), 200.0 );
}

BOOST_AUTO_TEST_CASE( test_copy_and_modify )
{
    // Create original
    Dimension original( 512, 0.1, "volts", 50.0 );

    // Copy it
    Dimension modified = original;

    // Modify the copy
    modified.SetNx( 1024 );
    modified.SetDx( 0.2 );

    // Original should be unchanged
    BOOST_CHECK_EQUAL( original.GetNx( ), 512 );
    BOOST_CHECK_EQUAL( original.GetDx( ), 0.1 );

    // Modified should have new values
    BOOST_CHECK_EQUAL( modified.GetNx( ), 1024 );
    BOOST_CHECK_EQUAL( modified.GetDx( ), 0.2 );

    // They should not be equal
    BOOST_CHECK( original != modified );
}

BOOST_AUTO_TEST_SUITE_END( )
