#include <alib/list>
#include <alib/variant>
#include "StringTest.h"

#include "sax/SaxParseInterface.h"
#include "sax/SaxComposeInterface.h"

#include "string/String.h"
#include "string/LinearString.h"
#include "string/xml/LinearString.h"
#include "string/CyclicString.h"
#include "string/xml/CyclicString.h"
#include "string/Epsilon.h"
#include "string/xml/Epsilon.h"

#include "factory/XmlDataFactory.hpp"

#include "alphabet/BlankSymbol.h"

#include <primitive/Character.h>
#include <primitive/xml/Character.h>
#include <container/ObjectsSet.h>
#include <container/xml/ObjectsSet.h>

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( StringTest, "string" );
CPPUNIT_TEST_SUITE_REGISTRATION ( StringTest );

void StringTest::setUp ( ) {
}

void StringTest::tearDown ( ) {
}

void StringTest::testCopyConstruct ( ) {
	string::LinearString < > string;

	string.accessComponent < string::GeneralAlphabet > ( ).set( { DefaultSymbolType ( "1" ), DefaultSymbolType ( "2" ), DefaultSymbolType ( "3" ) } );
	string.setContent ( { DefaultSymbolType ( "1" ), DefaultSymbolType ( "2" ), DefaultSymbolType ( "1" ) } );
	string::LinearString < > string2 ( string );

	CPPUNIT_ASSERT ( string == string2 );

	string::LinearString < > string3 ( std::move ( string ) );

	CPPUNIT_ASSERT ( string2 == string3 );
}

void StringTest::testXMLParser ( ) {

	string::LinearString < > string;

	string.accessComponent < string::GeneralAlphabet > ( ).set( { DefaultSymbolType ( "1" ), DefaultSymbolType ( "2" ), DefaultSymbolType ( "3" ) } );
	string.setContent ( { DefaultSymbolType ( "1" ), DefaultSymbolType ( "2" ), DefaultSymbolType ( "1" ) } );

	{
		ext::deque < sax::Token > tokens = factory::XmlDataFactory::toTokens ( string );
		std::string tmp = sax::SaxComposeInterface::composeMemory ( tokens );

		std::cout << tmp << std::endl;

		ext::deque < sax::Token > tokens2 = sax::SaxParseInterface::parseMemory ( tmp );
		string::LinearString < > string2 = factory::XmlDataFactory::fromTokens ( std::move( tokens2 ) );

		CPPUNIT_ASSERT ( string == string2 );
	}
	{
		std::string tmp = factory::XmlDataFactory::toString ( string );
		std::cout << tmp << std::endl;
		string::LinearString < > string2 = factory::XmlDataFactory::fromString ( tmp );

		CPPUNIT_ASSERT ( string == string2 );
	}
}

void StringTest::testStringInMap ( ) {
	ext::map < ext::variant < string::Epsilon < >, int >, int > testMap;
	ext::variant < string::Epsilon < >, int > epsVar {
		string::Epsilon < > { }
	};

	CPPUNIT_ASSERT ( string::Epsilon < >::EPSILON == epsVar.get < string::Epsilon < > > ( ) );
	CPPUNIT_ASSERT ( epsVar.get < string::Epsilon < > > ( ) == string::Epsilon < >::EPSILON );

	std::pair < ext::variant < string::Epsilon < >, int >, int > epsVarPair = std::make_pair ( epsVar, 10 );
	CPPUNIT_ASSERT ( string::Epsilon < >::EPSILON == epsVarPair.first.get < string::Epsilon < > > ( ) );
	CPPUNIT_ASSERT ( epsVarPair.first.get < string::Epsilon < > > ( ) == string::Epsilon < >::EPSILON );

	testMap.insert ( std::make_pair ( ext::variant < string::Epsilon < >, int > { string::Epsilon < > { }
									  }, 10 ) );
	CPPUNIT_ASSERT ( testMap.find ( ext::variant < string::Epsilon < >, int > { string::Epsilon < > { }
									} ) != testMap.end ( ) );

	for ( const auto & entry : testMap ) {
		CPPUNIT_ASSERT ( entry.first.is < string::Epsilon < > > ( ) );

		if ( entry.first.is < string::Epsilon < > > ( ) )
			CPPUNIT_ASSERT ( string::Epsilon < >::EPSILON == entry.first.get < string::Epsilon < > > ( ) );

		CPPUNIT_ASSERT ( entry.first.get < string::Epsilon < > > ( ) == string::Epsilon < >::EPSILON );
	}
}

void StringTest::testNormalize ( ) {
	string::LinearString < char > s1 ( ext::vector < char > { 'a', 'b' } );
	string::LinearString < > s2 = core::normalize < string::LinearString < char > >::eval ( string::LinearString < char > ( s1 ) );

	std::string tmp1 = factory::XmlDataFactory::toString ( s1 );
	std::cout << tmp1 << std::endl;
	string::LinearString < > s1x = factory::XmlDataFactory::fromString ( tmp1 );

	std::string tmp2 = factory::XmlDataFactory::toString ( s2 );
	std::cout << tmp2 << std::endl;
	string::LinearString < > s2x = factory::XmlDataFactory::fromString ( tmp2 );

	CPPUNIT_ASSERT ( s1x == s2x );
}

void StringTest::testNormalize2 ( ) {
	string::LinearString < object::Object > s1 ( ext::vector < object::Object > { object::Object ( 'a' ), object::Object ( 'b' ) } );
	string::LinearString < > s2 = core::normalize < string::LinearString < object::Object > >::eval ( string::LinearString < object::Object > ( s1 ) );

	std::string tmp1 = factory::XmlDataFactory::toString ( s1 );
	std::cout << tmp1 << std::endl;
	string::LinearString < > s1x = factory::XmlDataFactory::fromString ( tmp1 );

	std::string tmp2 = factory::XmlDataFactory::toString ( s2 );
	std::cout << tmp2 << std::endl;
	string::LinearString < > s2x = factory::XmlDataFactory::fromString ( tmp2 );

	CPPUNIT_ASSERT ( s1 == s1x );
	CPPUNIT_ASSERT ( s1 == s2x );
}

void StringTest::testNormalize3 ( ) {
	string::LinearString < ext::set < char > > s1 ( ext::vector < ext::set < char > > { ext::set < char > { 'a' }, ext::set < char > { 'b' } } );
	string::LinearString < > s2 = core::normalize < string::LinearString < ext::set < char > > >::eval ( string::LinearString < ext::set < char > > ( s1 ) );

	std::string tmp1 = factory::XmlDataFactory::toString ( s1 );
	std::cout << tmp1 << std::endl;
	string::LinearString < > s1x = factory::XmlDataFactory::fromString ( tmp1 );

	std::string tmp2 = factory::XmlDataFactory::toString ( s2 );
	std::cout << tmp2 << std::endl;
	string::LinearString < > s2x = factory::XmlDataFactory::fromString ( tmp2 );

	CPPUNIT_ASSERT ( s1x == s2x );

	string::LinearString < object::Object > ref ( ext::vector < object::Object > { object::Object ( container::ObjectsSet < object::Object > ( ext::set < object::Object > { object::Object ( primitive::Character ( 'a' ) ) } ) ), object::Object ( container::ObjectsSet < object::Object > ( ext::set < object::Object > { object::Object ( primitive::Character ( 'b' ) ) } ) ) } );

	std::cout << s1x << std::endl;
	std::cout << ref << std::endl;

	CPPUNIT_ASSERT ( s1x == ref );
}