#include "RegExpTest.h"
#include <list>

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

#include "regexp/RegExpFromStringParser.h"
#include "regexp/unbounded/UnboundedRegExp.h"

#include "regexp/glushkov/GlushkovTraversal.h"

#include <factory/StringDataFactory.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 ( RegExpTest, "regexp" );
CPPUNIT_TEST_SUITE_REGISTRATION ( RegExpTest );

void RegExpTest::setUp ( ) {
}

void RegExpTest::tearDown ( ) {
}

void RegExpTest::testFirst ( ) {
	{
		std::string input = "#E* #0*";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		std::set < regexp::UnboundedRegExpSymbol > first = regexp::GlushkovTraversal::first ( indexedRegExp );

		CPPUNIT_ASSERT ( first.size ( ) == 0 );
	}
	{
		std::string input = "#E* a";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		std::set < regexp::UnboundedRegExpSymbol > first = regexp::GlushkovTraversal::first ( indexedRegExp );

		CPPUNIT_ASSERT ( first.size ( ) == 1 );
	}
}

void RegExpTest::testLast ( ) {
	{
		std::string input = "a+a";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		std::set < regexp::UnboundedRegExpSymbol > last = regexp::GlushkovTraversal::last ( indexedRegExp );

		CPPUNIT_ASSERT ( last.size ( ) == 2 );
	}
	{
		std::string input = "(a+a)b";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		std::set < regexp::UnboundedRegExpSymbol > last = regexp::GlushkovTraversal::last ( indexedRegExp );

		std::cout << last << std::endl;
		CPPUNIT_ASSERT ( last.size ( ) == 1 );
	}
}

void RegExpTest::testFollow ( ) {
	{
		std::string input = "(a+a)b";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		auto symbolsIter = indexedRegExp.getAlphabet ( ).begin ( );

		std::set < regexp::UnboundedRegExpSymbol > follow1 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow1.size ( ) == 1 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow2 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow2.size ( ) == 1 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow3 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow3.size ( ) == 0 );
	}
	{
		std::string input = "a+a* (b+a)* c";
		regexp::UnboundedRegExp regexp ( static_cast < const regexp::UnboundedRegExp & > ( alib::StringDataFactory::fromString < regexp::RegExp > ( input ).getData ( ) ) );
		regexp::UnboundedRegExp indexedRegExp = regexp::GlushkovTraversal::index ( regexp );

		auto symbolsIter = indexedRegExp.getAlphabet ( ).begin ( );

		std::set < regexp::UnboundedRegExpSymbol > follow1 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow1.size ( ) == 0 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow2 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow2.size ( ) == 4 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow3 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow3.size ( ) == 3 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow4 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow4.size ( ) == 3 );

		symbolsIter++;
		std::set < regexp::UnboundedRegExpSymbol > follow5 = regexp::GlushkovTraversal::follow ( indexedRegExp, regexp::UnboundedRegExpSymbol ( * symbolsIter ) );

		CPPUNIT_ASSERT ( follow5.size ( ) == 0 );
	}
}