#include <catch2/catch.hpp>

#include <string/String.h>
#include <stringology/compression/LZ77Compression.h>
#include <stringology/compression/LZ77Decompression.h>

#include <iostream>
#include <tuple>


TEST_CASE ( "LZ77 Compression", "[unit][algo][stringology][compression]" ) {
	SECTION ( "Compress and Decompress" ) {
		auto testcase = GENERATE (
				std::make_pair ( "aabaacaaaaaababab", std::vector < std::tuple < unsigned, unsigned, char > > { std::make_tuple(0, 0, 'a' ), std::make_tuple(1, 1, 'b' ), std::make_tuple(3, 2, 'c' ), std::make_tuple(3, 2, 'a' ), std::make_tuple(1, 3, 'b' ), std::make_tuple(2, 3, 'b' ) } ),
				std::make_pair ( "aacaacabcabaaac", std::vector < std::tuple < unsigned, unsigned, char > > { std::make_tuple(0, 0, 'a' ), std::make_tuple(1, 1, 'c' ), std::make_tuple(3, 4, 'b' ), std::make_tuple(3, 3, 'a' ), std::make_tuple(1, 2, 'c' ) } ) );

		string::LinearString < char > string = string::stringFrom ( testcase.first );
		std::vector < std::tuple < unsigned, unsigned, char > > res = stringology::compression::LZ77Compression::compress ( string, 6, 4 );
		const std::vector < std::tuple < unsigned, unsigned, char > > & expectedOutput = testcase.second;

		/* compress */
		for ( const std::tuple < unsigned, unsigned, char > & resItem : res )
			INFO ( std::get < 0 > ( resItem ) << " " << std::get < 1 > ( resItem ) << " " << std::get < 2 > ( resItem ) );

		CHECK ( res == expectedOutput );

		/* decompress */
		string::LinearString < char > decompressed = stringology::compression::LZ77Decompression::decompress ( res );
		CHECK ( decompressed == string );
	}

	SECTION ( "Decompress" ) {
		std::string string = "";
		string::LinearString < char > input = string::stringFrom ( string );

		std::vector < std::tuple < unsigned, unsigned, char > > out = stringology::compression::LZ77Compression::compress ( input, 6, 4 );
		string::LinearString < char > res = stringology::compression::LZ77Decompression::decompress ( out );

		CHECK ( input == res );
	}
}
