#include "dataChannelTestUtility.h"

#include "../../software/signal_processing/system/data_channel.h"
#include <fstream>
#include <gtest/gtest.h>

void dataChannelRead( uint32_t base, float * data ) {
    for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) {
        data_channel_read( base, reinterpret_cast< uint32_t * >( & data[ i ] ) );
    }
}

void dataChannelRead( uint32_t base, uint32_t * data ) {
    for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) {
        data_channel_read( base, & data[ i ] );
    }
}

uint32_t dataChannelRead( uint32_t base ) {
    uint32_t data;
    data_channel_read( base, & data );
    return data;
}

void dataChannelCheck( const float * data, const float * expected ) {
    for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) {
        ASSERT_NEAR( data[ i ], expected[ i ], 1e-1 ) << " with i = " << i;
    }
}

void dataChannelCheck( const uint32_t * data, const uint32_t * expected ) {
    for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) {
        ASSERT_EQ( data[ i ], expected[ i ] ) << " with i = " << i;
    }
}

void dataChannelFill( uint32_t base, const float * data ) {
    for ( uint32_t i = 0; i < DATA_CHANNEL_DEPTH; ++i ) {
        data_channel_write( base, * reinterpret_cast< const uint32_t * >( & data[ i ] ) );
    }
}

void dataChannelReadAndWriteToFile( const void * data, const char * filename ) {
    std::ofstream out;
    out.open( filename, std::ios::out );

    auto float_data = reinterpret_cast< const float * >( data );
    auto u32_data = reinterpret_cast< const uint32_t * >( data );

    out << "float_data = [" << std::setprecision(6) << std::fixed << std::scientific << float_data[ 0 ];
    for ( uint32_t i = 1; i < DATA_CHANNEL_DEPTH; ++i ) {
        out << "," << float_data[ i ];
    }
    out << "]" << std::endl;

    out << "hex_data = [" << std::hex << "0x" << u32_data[ 0 ];
    for ( uint32_t i = 1; i < DATA_CHANNEL_DEPTH; ++i ) {
        out << ",0x" <<  u32_data[ i ];
    }
    out << "]" << std::endl;

    out.close();
}

void dataChannelReadAndWriteToFile( uint32_t data, const char * filename ) {
    std::ofstream out;
    out.open( filename, std::ios::out );

    auto float_data = reinterpret_cast< const float * >( & data );
    auto u32_data = reinterpret_cast< const uint32_t * >( & data );

    out << "float_data = [" << std::setprecision(6) << std::fixed << std::scientific << float_data[ 0 ];
    out << "]" << std::endl;

    out << "hex_data = [" << std::hex << "0x" << u32_data[ 0 ];
    out << "]" << std::endl;

    out.close();
}

void dataChannelCheckAndWriteToFile( uint32_t base, const float * expected, const char * filename ) {
    float data[ DATA_CHANNEL_DEPTH ];
    memset( data, 0.0, sizeof( float ) * DATA_CHANNEL_DEPTH );
    dataChannelRead( base, data );
    dataChannelReadAndWriteToFile( data, filename );
    dataChannelCheck( data, expected );
}

void dataChannelWriteToFile( uint32_t base, const char * filename ) {
    float data[ DATA_CHANNEL_DEPTH ];
    memset( data, 0.0, sizeof( float ) * DATA_CHANNEL_DEPTH );
    dataChannelRead( base, data );
    dataChannelReadAndWriteToFile( data, filename );
}

void dataChannelCheckAndWriteToFile( uint32_t base, const uint32_t * expected, const char * filename ) {
    uint32_t data[ DATA_CHANNEL_DEPTH ];
    memset( data, 0, sizeof( uint32_t ) * DATA_CHANNEL_DEPTH );
    dataChannelRead( base, data );
    dataChannelReadAndWriteToFile( data, filename );
    dataChannelCheck( data, expected );
}

void dataChannelCheck( uint32_t base, uint32_t expected, const char * filename ) {
    uint32_t data = dataChannelRead( base );
    ASSERT_EQ( data, expected );
}
