#ifndef TREE_TEST_BASE_H_
#define TREE_TEST_BASE_H_

#include <cppunit/extensions/HelperMacros.h>
#include <alib/compare>
#include <alib/tree>

class TreeBaseTest : public CppUnit::TestFixture {
	CPPUNIT_TEST_SUITE ( TreeBaseTest );
	CPPUNIT_TEST ( testRegexps );
	CPPUNIT_TEST ( testRankedTree );
	CPPUNIT_TEST ( testUnrankedTree );
	CPPUNIT_TEST_SUITE_END ( );

public:
	class RegExpElement : public ext::BaseNode < RegExpElement > {
	};

	class RegExpAlternation : public RegExpElement, public ext::VararyNode < RegExpElement, RegExpAlternation > {
	public:
		RegExpAlternation ( RegExpElement && left, RegExpElement && right ) : VararyNode < RegExpElement, RegExpAlternation > ( ) {
			pushBackChild ( std::move ( left ) );
			pushBackChild ( std::move ( right ) );
		}

	};


	class RegExpConcatenation : public RegExpElement, public ext::BinaryNode < RegExpElement, RegExpConcatenation > {
	public:
		RegExpConcatenation ( RegExpElement && left, RegExpElement && right ) : BinaryNode < RegExpElement, RegExpConcatenation > ( std::move ( left ), std::move ( right ) ) {
		}

	};

	class RegExpIteration : public RegExpElement, public ext::UnaryNode < RegExpElement, RegExpIteration > {
	public:
		RegExpIteration ( RegExpElement && element ) : UnaryNode < RegExpElement, RegExpIteration > ( std::move ( element ) ) {
			std::cout << "Here" << std::endl;
		}

	};

	class RegExpSymbol : public RegExpElement, public ext::NullaryNode < RegExpElement, RegExpSymbol > {
		char m_symbol;

	public:
		RegExpSymbol ( char symbol ) : m_symbol ( symbol ) {
		}

		char getSymbol ( ) const {
			return m_symbol;
		}

	};

	class RegExpEpsilon : public RegExpElement {
	};

	class RegExpEmpty : public RegExpElement {
	};

	class RegExp {
		std::shared_ptr < RegExpElement > root;
	};

	class UnrankedTreeNode : public ext::BaseNode < UnrankedTreeNode >, public ext::VararyNode < UnrankedTreeNode > {
		char m_symbol;

	public:
		UnrankedTreeNode ( char symbol, ext::ptr_vector < UnrankedTreeNode > c ) : VararyNode < UnrankedTreeNode > ( std::move ( c ) ), m_symbol ( symbol ) {
		}

		char getSymbol ( ) const {
			return m_symbol;
		}

	};

	class UnrankedTree {
		UnrankedTreeNode root;
	};

	class RankedTreeNode : public ext::BaseNode < RankedTreeNode >, public ext::FixedaryNode < RankedTreeNode > {
		char m_symbol;
		unsigned m_arity;

	public:
		RankedTreeNode ( char symbol, unsigned arity, ext::ptr_vector < RankedTreeNode > c ) : FixedaryNode < RankedTreeNode > ( std::move ( c ) ), m_symbol ( symbol ), m_arity ( arity ) {
			if ( getChildren ( ).size ( ) != m_arity )
				throw "Arity != size";
		}

		char getSymbol ( ) const {
			return m_symbol;
		}

	};

	class RankedTree {
		RankedTreeNode root;
	};

public:
	void setUp ( );
	void tearDown ( );

	void testRegexps ( );
	void testRankedTree ( );
	void testUnrankedTree ( );
};

#endif // TREE_TEST_BASE_H_