#include "ZeroRunLengthEncodingTest.h"

#include <common/ZeroRunLengthEncoding.hpp>

#define CPPUNIT_IMPLY( x, y )			CPPUNIT_ASSERT ( !( x ) || ( y ) )
#define CPPUNIT_EXCLUSIVE_OR( x, y )	CPPUNIT_ASSERT ( ( !( x ) && ( y ) ) || ( ( x ) && !( y ) ) )

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( ZeroRunLengthEncodingTest, "common" );
CPPUNIT_TEST_SUITE_REGISTRATION ( ZeroRunLengthEncodingTest );

void ZeroRunLengthEncodingTest::setUp ( ) {
}

void ZeroRunLengthEncodingTest::tearDown ( ) {
}

void ZeroRunLengthEncodingTest::testVectorCompatibility() {
	std::vector < bool > orig;
	for ( int i = 0; i < 1000; ++i ) {
		orig.push_back ( false );
	}
	for ( int i = 0; i < 20; ++i ) {
		orig.push_back ( true );
		orig.push_back ( true );
		orig.push_back ( false );
		orig.push_back ( true );
		orig.push_back ( true );
		orig.push_back ( false );
		orig.push_back ( true );
		orig.push_back ( false );
		orig.push_back ( false );
		orig.push_back ( true );
	}
	for ( int i = 0; i < 1000; ++i ) {
		orig.push_back ( false );
	}
	orig.push_back ( true );
	orig.push_back ( true );
	orig.push_back ( false );
	orig.push_back ( true );
	orig.push_back ( true );
	orig.push_back ( false );
	orig.push_back ( true );
	orig.push_back ( false );
	orig.push_back ( false );
	orig.push_back ( true );

	common::ZeroRunLengthEncoding compressed ( orig );
	std::vector < bool > copy ( compressed );

	std::cout << orig << std::endl;
	std::cout << copy << std::endl;
	std::cout << compressed.data ( ) << std::endl;

	CPPUNIT_ASSERT ( orig == copy );
}

void testOffset ( int /* offset */ ) {
/*	unsigned long long shadow = 0x2A76B147D6521C87ULL;
	std::vector < bool > data;

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8 + offset; ++ i ) {
		data.push_back ( true );
	}

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	data >>= sizeof ( unsigned long long ) * 6 - 1;

	std::vector < bool > ref;
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 2 + offset; ++ i ) {
		ref.push_back ( true );
	}

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	ref.resize ( 128 + offset );

	std::cout << "data = " << data << std::endl;
	std::cout << "ref  = " << ref << std::endl;

	CPPUNIT_ASSERT ( data == ref );*/
}

void ZeroRunLengthEncodingTest::testShifts2() {
/*	unsigned long long shadow = 0x2A76B147D6521C87ULL;
	std::vector < bool > data;

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	shadow >>= 10;
	data >>= 10;

	std::vector < bool > ref;
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	// std::cout << "data = " << data << std::endl;
	// std::cout << "ref  = " << ref << std::endl;

	CPPUNIT_ASSERT ( data == ref );

	for ( unsigned long i = - sizeof ( unsigned long long ) / 2 ; i < sizeof ( unsigned long long ) * 8; ++ i )
		testOffset ( i ); */
}

void ZeroRunLengthEncodingTest::testShifts3() {
/*	unsigned long long shadow = 0x2A76B147D6521C87ULL;
	std::vector < bool > data;

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	std::vector < bool > data2 = data;
	data2 >>= 64;

	data >>= 32;
	data >>= 16;
	data >>= 8;
	data >>= 4;
	data >>= 2;
	data >>= 1;
	data >>= 1;

	std::cout << "data  = " << data  << std::endl;
	std::cout << "data2 = " << data2 << std::endl;

	data2 >>= 1;
	data2 >>= 2;
	data2 >>= 4;
	data2 >>= 8;
	data2 >>= 16;
	data2 >>= 32;
	data2 >>= 1;

	data >>= 27;
	data >>= 17;
	data >>= 13;
	data >>= 7;

	std::cout << "data  = " << data  << std::endl;
	std::cout << "data2 = " << data2 << std::endl;

	CPPUNIT_ASSERT ( data2 == data );*/
}

void testOffset2 ( size_t size, size_t shift ) {
	unsigned long long shadow = 0x2A76B147D6521C87ULL;
	std::vector < bool > ref;
	while ( ref.size ( ) < size ) {
		for ( size_t i = 0; i < sizeof ( unsigned long long ) * 8; ++i ) {
			ref.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
		}
		for ( size_t i = 0; i < 100; ++i ) {
			ref.push_back ( false );
		}
	}
	ref.resize ( size );

	common::ZeroRunLengthEncoding data = ref;
	data <<= shift;
	ref <<= shift;

	std::cout << "size = " << size << std::endl;
	std::cout << "shift = " << shift << std::endl;
	std::cout << "data = " << data.data ( ) << std::endl;
	std::cout << "ref = " << common::ZeroRunLengthEncoding ( ref ).data ( ) << std::endl;

	CPPUNIT_ASSERT ( data == common::ZeroRunLengthEncoding ( ref ) );
}

void ZeroRunLengthEncodingTest::testShifts4() {
	for ( size_t shift = 0 ; shift < 100; ++ shift ) {
		testOffset2 ( 0, shift );
		testOffset2 ( 31, shift );
		testOffset2 ( 32, shift );
		testOffset2 ( 33, shift );
		testOffset2 ( 63, shift );
		testOffset2 ( 64, shift );
		testOffset2 ( 65, shift );
		testOffset2 ( 1023, shift );
		testOffset2 ( 1024, shift );
		testOffset2 ( 1025, shift );
		testOffset2 ( 2000, shift );

	}
}

void ZeroRunLengthEncodingTest::testShifts5() {
	unsigned long long shadow = 0x2A76B147D6521C87ULL;
	common::ZeroRunLengthEncoding data;

	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}
	for ( unsigned i = 0; i < sizeof ( unsigned long long ) * 8; ++ i ) {
		data.push_back ( ( bool ) ( shadow & ( 1ULL << i ) ) );
	}

	common::ZeroRunLengthEncoding data2 = data;
	data2 <<= 64;

	data <<= 32;
	data <<= 16;
	data <<= 8;
	data <<= 4;
	data <<= 2;
	data <<= 1;
	data <<= 1;

	std::cout << "data  = " << data.data ( )  << std::endl;
	std::cout << "data2 = " << data2.data ( ) << std::endl;

	data2 <<= 1;
	data2 <<= 2;
	data2 <<= 4;
	data2 <<= 8;
	data2 <<= 16;
	data2 <<= 32;
	data2 <<= 1;

	data <<= 27;
	data <<= 17;
	data <<= 13;
	data <<= 7;

	std::cout << "data  = " << data.data ( )  << std::endl;
	std::cout << "data2 = " << data2.data ( ) << std::endl;

	CPPUNIT_ASSERT ( data2 == data );
}