/*
 * tree.hpp
 *
 * Created on: Jul 2, 2016
 * Author: Jan Travnicek
 */

#ifndef __TREE_BASE_HPP_
#define __TREE_BASE_HPP_

#include "ptr_vector.hpp"
#include "ptr_array.hpp"

namespace ext {

/**
 * \brief
 * Base class for hierarchy of tree node types. The tree node types can be used to construct tree structures of different types of nodes.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 */
template < class Data >
class BaseNode {
	/**
	 * \brief
	 * Pointer to the parent object of this node.
	 */
	Data * parent;

	template < class D, class C >
	friend class NullaryNode;
	template < class D, class C >
	friend class UnaryNode;
	template < class D, class C >
	friend class BinaryNode;
	template < class D, class C >
	friend class TernaryNode;
	template < class D, std::size_t I, class C >
	friend class AnyaryNode;
	template < class D, class C >
	friend class FixedaryNode;
	template < class D, class C >
	friend class VararyNode;

	/**
	 * \brief
	 * Arrow operator to access fields and methods of the object implementing the actual node of the tree.
	 *
	 * \return pointer to the actual node of the hierarchy
	 */
	Data * operator ->( ) {
		return static_cast < Data * > ( this );
	}

	/**
	 * \brief
	 * Arrow operator to access fields and methods of the object implementing the actual node of the tree.
	 *
	 * \return pointer to the actual node of the hierarchy
	 */
	const Data * operator ->( ) const {
		return static_cast < const Data * > ( this );
	}

public:
	/**
	 * \brief
	 * Constructor of the tree hierarchy base class.
	 */
	BaseNode ( ) : parent ( nullptr ) {
	}

	/**
	 * \brief
	 * Destructor of the tree hierarchy base class.
	 */
	virtual ~BaseNode ( ) noexcept = default;

	/**
	 * \brief
	 * Copy construction does not copy the parent pointer.
	 */
	BaseNode ( const BaseNode & ) : parent ( nullptr ) {
	}

	/**
	 * \brief
	 * Move construction does not copy the parent pointer.
	 */
	BaseNode ( BaseNode && ) noexcept : parent ( nullptr ) {
	}

	/**
	 * \brief
	 * Copy assignment does not change the parent pointer.
	 */
	BaseNode & operator =( const BaseNode & ) {
		return * this;
	}

	/**
	 * \brief
	 * Move assignment does not change the parent pointer.
	 */
	BaseNode & operator =( BaseNode && ) noexcept {
		return * this;
	}

	/**
	 * \brief
	 * Getter of the parent of the node
	 *
	 * \return parent of the node
	 */
	Data * getParent ( ) {
		return parent;
	}

	/**
	 * \brief
	 * Getter of the parent of the node
	 *
	 * \return parent of the node
	 */
	const Data * getParent ( ) const {
		return parent;
	}

};

/**
 * \brief
 * Tree node with any but fixed number of children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam arity the number of child nodes
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, std::size_t arity, class Cast = Data >
class AnyaryNode {
	/**
	 * \brief
	 * Representation of child nodes
	 */
	ext::ptr_array < Data, arity > m_children;

	/**
	 * \brief
	 * Helper method to push this instance as parent to this instance's children.
	 */
	void setParents ( ) {
		for ( Data & child : m_children )
			child->parent = static_cast < Cast * > ( this );
	}

public:
	/**
	 * \brief
	 * Constructor based on array of child nodes.
	 *
	 * \param c the array of child nodes
	 */
	AnyaryNode ( ext::ptr_array < Data, arity > c ) : m_children ( std::move ( c ) ) {
		setParents ( );
	}

	/**
	 * \brief
	 * Destructor of the class.
	 */
	virtual ~AnyaryNode ( ) noexcept = default;

	/**
	 * \brief
	 * Copy constructor.
	 */
	AnyaryNode ( const AnyaryNode & other ) : AnyaryNode ( other.m_children ) {
	}

	/**
	 * \brief
	 * Move constructor.
	 */
	AnyaryNode ( AnyaryNode && other ) noexcept : AnyaryNode ( std::move ( other.m_children ) ) {
	}

	/**
	 * \brief
	 * Copy operator of assignment.
	 */
	AnyaryNode & operator =( const AnyaryNode & other ) {
		* this = AnyaryNode ( other );
		return * this;
	}

	/**
	 * \brief
	 * move operator of assignment.
	 */
	AnyaryNode & operator =( AnyaryNode && other ) noexcept {
		using std::swap;

		swap ( this->m_children, other.m_children );

		setParents ( );

		return * this;
	}

	/**
	 * \brief
	 * Getter of the child nodes.
	 *
	 * \return child nodes
	 */
	const ext::ptr_array < Data, arity > & getChildren ( ) & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the child nodes.
	 *
	 * \return child nodes
	 */
	const ext::ptr_array < Data, arity > & getChildren ( ) const & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the child nodes.
	 *
	 * \return child nodes
	 */
	ext::ptr_array < Data, arity > && getChildren ( ) && {
		return std::move ( m_children );
	}

	/**
	 * \brief
	 * Getter of the child node based on compile time index.
	 *
	 * \tparam N the index of the node
	 *
	 * \return child node at given index
	 */
	template < size_t N >
	const Data & getChild ( ) const {
		return std::get < N > ( m_children );
	}

	/**
	 * \brief
	 * Getter of the child node based on compile time index.
	 *
	 * \tparam N the index of the node
	 *
	 * \return child node at given index
	 */
	template < size_t N >
	Data & getChild ( ) {
		return std::get < N > ( m_children );
	}

	/**
	 * \brief
	 * Setter of the child nodes.
	 *
	 * \param c child nodes
	 */
	void setChildren ( ext::ptr_array < Data, arity > c ) {
		m_children = std::move ( c );
		setParents ( );
	}

	/**
	 * \brief
	 * Setter of the child node based on compile time index.
	 *
	 * \tparam N the index of the node
	 *
	 * \return child node at given index
	 */
	template < size_t N >
	void setChild ( const Data & d ) {
		m_children.set ( m_children.cbegin ( ) + N, d );
		std::get < N > ( m_children )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Setter of the child node based on compile time index.
	 *
	 * \tparam N the index of the node
	 *
	 * \return child node at given index
	 */
	template < size_t N >
	void setChild ( Data && d ) {
		m_children.set ( m_children.cbegin ( ) + N, std::move ( d ) );
		std::get < N > ( m_children )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children array
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_array < Data, arity >::iterator begin ( ) {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children array
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_array < Data, arity >::const_iterator begin ( ) const {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children array
	 *
	 * \return end iterator
	 */
	typename ext::ptr_array < Data, arity >::iterator end ( ) {
		return m_children.end ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children array
	 *
	 * \return end iterator
	 */
	typename ext::ptr_array < Data, arity >::const_iterator end ( ) const {
		return m_children.end ( );
	}

};

/**
 * \brief
 * Nullary node is specialisation of Anyary node to no children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class NullaryNode : public AnyaryNode < Data, 0, Cast > {
public:
	/**
	 * \brief
	 * The default constructor of the class.
	 */
	NullaryNode ( ) : AnyaryNode < Data, 0, Cast > ( ext::make_ptr_array < Data > ( ) ) {
	}

};

/**
 * \brief
 * Unary node is specialisation of Anyary node to one child.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class UnaryNode : public AnyaryNode < Data, 1, Cast > {
public:
	/**
	 * \brief
	 * Constructor of the class accepting the child node.
	 *
	 * \param c the to be child node of the new node
	 */
	UnaryNode ( const Data & c ) : AnyaryNode < Data, 1, Cast > ( ext::make_ptr_array ( c ) ) {
	}

	/**
	 * \brief
	 * Constructor of the class accepting the child node.
	 *
	 * \param c the to be child node of the new node
	 */
	UnaryNode ( Data && c ) : AnyaryNode < Data, 1, Cast > ( ext::make_ptr_array ( std::move ( c ) ) ) {
	}

	/**
	 * \brief
	 * Getter of the child of the node.
	 *
	 * \return the child of the node
	 */
	Data & getChild ( ) {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Getter of the child of the node.
	 *
	 * \return the child of the node
	 */
	const Data & getChild ( ) const {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Inherit getChild to this class to distable shadowing.
	 */
	using AnyaryNode < Data, 1, Cast >::getChild;

	/**
	 * \brief
	 * Setter of the child of the node.
	 *
	 * \param c the child of the node
	 */
	void setChild ( const Data & c ) {
		this->template setChild < 0 > ( c );
	}

	/**
	 * \brief
	 * Setter of the child of the node.
	 *
	 * \param c the child of the node
	 */
	void setChild ( Data && c ) {
		this->template setChild < 0 > ( std::move ( c ) );
	}

	/**
	 * \brief
	 * Inherit setChild to this class to distable shadowing.
	 */
	using AnyaryNode < Data, 1, Cast >::setChild;

};

/**
 * \brief
 * Binary node is specialisation of Anyary node to two children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class BinaryNode : public AnyaryNode < Data, 2, Cast > {
public:
	/**
	 * \brief
	 * Constructor of the class accepting the two child nodes.
	 *
	 * \param l the first child node of the new node
	 * \param r the second child node of the new node
	 */
	BinaryNode ( const Data & l, const Data & r ) : AnyaryNode < Data, 2, Cast > ( ext::make_ptr_array ( l, r ) ) {
	}

	/**
	 * \brief
	 * Constructor of the class accepting the two child nodes.
	 *
	 * \param l the first child node of the new node
	 * \param r the second child node of the new node
	 */
	BinaryNode ( Data && l, Data && r ) : AnyaryNode < Data, 2, Cast > ( ext::make_ptr_array ( std::move ( l ), std::move ( r ) ) ) {
	}

	/**
	 * \brief
	 * Getter of the first child of the node.
	 *
	 * \return the first child of the node
	 */
	Data & getLeft ( ) {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Getter of the first child of the node.
	 *
	 * \return the first child of the node
	 */
	const Data & getLeft ( ) const {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Setter of the first child of the node.
	 *
	 * \param l the first child of the node
	 */
	void setLeft ( const Data & l ) {
		this->template setChild < 0 > ( l );
	}

	/**
	 * \brief
	 * Setter of the first child of the node.
	 *
	 * \param l the first child of the node
	 */
	void setLeft ( Data && l ) {
		this->template setChild < 0 > ( std::move ( l ) );
	}

	/**
	 * \brief
	 * Getter of the second child of the node.
	 *
	 * \return the second child of the node
	 */
	Data & getRight ( ) {
		return this->template getChild < 1 > ( );
	}

	/**
	 * \brief
	 * Getter of the second child of the node.
	 *
	 * \return the second child of the node
	 */
	const Data & getRight ( ) const {
		return this->template getChild < 1 > ( );
	}

	/**
	 * \brief
	 * Setter of the second child of the node.
	 *
	 * \param r the second child of the node
	 */
	void setRight ( const Data & r ) {
		this->template setChild < 1 > ( r );
	}

	/**
	 * \brief
	 * Setter of the second child of the node.
	 *
	 * \param r the second child of the node
	 */
	void setRight ( Data && r ) {
		this->template setChild < 1 > ( std::move ( r ) );
	}

};

/**
 * \brief
 * Ternany node is specialisation of Anyary node to three children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class TernaryNode : public AnyaryNode < Data, 3, Cast > {
public:
	/**
	 * \brief
	 * Constructor of the class accepting the three child nodes.
	 *
	 * \param f the first child node of the new node
	 * \param s the second child node of the new node
	 * \param t the third child node of the new node
	 */
	TernaryNode ( const Data & f, const Data & s, const Data & t ) : AnyaryNode < Data, 3, Cast > ( ext::make_ptr_array ( f, s, t ) ) {
	}

	/**
	 * \brief
	 * Constructor of the class accepting the three child nodes.
	 *
	 * \param f the first child node of the new node
	 * \param s the second child node of the new node
	 * \param t the third child node of the new node
	 */
	TernaryNode ( Data && f, Data && s, Data && t ) : AnyaryNode < Data, 3, Cast > ( ext::make_ptr_array ( std::move ( f ), std::move ( s ), std::move ( t ) ) ) {
	}

	/**
	 * \brief
	 * Getter of the first child of the node.
	 *
	 * \return the first child of the node
	 */
	Data & getFirst ( ) {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Getter of the first child of the node.
	 *
	 * \return the first child of the node
	 */
	const Data & getFirst ( ) const {
		return this->template getChild < 0 > ( );
	}

	/**
	 * \brief
	 * Setter of the first child of the node.
	 *
	 * \param f the first child of the node
	 */
	void setFirst ( const Data & f ) {
		this->template setChild < 0 > ( f );
	}

	/**
	 * \brief
	 * Setter of the first child of the node.
	 *
	 * \param f the first child of the node
	 */
	void setFirst ( Data && f ) {
		this->template setChild < 0 > ( std::move ( f ) );
	}

	/**
	 * \brief
	 * Getter of the second child of the node.
	 *
	 * \return the second child of the node
	 */
	Data & getSecond ( ) {
		return this->template getChild < 1 > ( );
	}

	/**
	 * \brief
	 * Getter of the second child of the node.
	 *
	 * \return the second child of the node
	 */
	const Data & getSecond ( ) const {
		return this->template getChild < 1 > ( );
	}

	/**
	 * \brief
	 * Setter of the second child of the node.
	 *
	 * \param s the child of the node
	 */
	void setSecond ( const Data & s ) {
		this->template setChild < 1 > ( s );
	}

	/**
	 * \brief
	 * Setter of the second child of the node.
	 *
	 * \param s the child of the node
	 */
	void setSecond ( Data && s ) {
		this->template setChild < 1 > ( std::move ( s ) );
	}

	/**
	 * \brief
	 * Getter of the third child of the node.
	 *
	 * \return the third child of the node
	 */
	Data & getThird ( ) {
		return this->template getChild < 2 > ( );
	}

	/**
	 * \brief
	 * Getter of the third child of the node.
	 *
	 * \return the third child of the node
	 */
	const Data & getThird ( ) const {
		return this->template getChild < 2 > ( );
	}

	/**
	 * \brief
	 * Setter of the third child of the node.
	 *
	 * \param t the third child of the node
	 */
	void setThird ( const Data & t ) {
		this->template setChild < 2 > ( t );
	}

	/**
	 * \brief
	 * Setter of the third child of the node.
	 *
	 * \param t the third child of the node
	 */
	void setThird ( Data && t ) {
		this->template setChild < 2 > ( std::move ( t ) );
	}

};

/**
 * \brief
 * Fixedary node is tree node that when initialized does not permit change of the number of its children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class FixedaryNode {
	/**
	 * \brief
	 * Representation of child nodes
	 */
	ext::ptr_vector < Data > m_children;

public:
	/**
	 * \brief
	 * Constructor of the node from vector of children.
	 *
	 * \param c the child nodes
	 */
	FixedaryNode ( ext::ptr_vector < Data > c ) : m_children ( std::move ( c ) ) {
		for ( Data & child : m_children )
			child.parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Constructor of the node from pack of children
	 *
	 * \tparam Types ... the types of children
	 *
	 * \param data ... the actual children
	 */
	template < typename ... Types >
	FixedaryNode ( Types && ... data ) : FixedaryNode ( ext::ptr_vector < Data > ( { std::forward < Types > ( data ) ... } ) ) {
	}

	/**
	 * \brief
	 * Destructor of the class.
	 */
	virtual ~FixedaryNode ( ) noexcept = default;

	/**
	 * \brief
	 * Copy constructor of the class.
	 *
	 * \param other the other instance
	 */
	FixedaryNode ( const FixedaryNode & other ) : FixedaryNode ( other.m_children ) {
	}

	/**
	 * \brief
	 * Move constructor of the class.
	 *
	 * \param other the other instance
	 */
	FixedaryNode ( FixedaryNode && other ) noexcept : FixedaryNode ( std::move ( other.m_children ) ) {
	}

	/**
	 * \brief
	 * Copy operator of assignment.
	 *
	 * \param other the other instance
	 */
	FixedaryNode & operator =( const FixedaryNode & other ) {
		* this = FixedaryNode ( other );
		return * this;
	}

	/**
	 * \brief
	 * Move operator of assignment.
	 *
	 * \param other the other instance
	 */
	FixedaryNode & operator =( FixedaryNode && other ) noexcept {
		using std::swap;

		swap ( this->m_children, other.m_children );

		for ( Data & child : m_children )
			child.parent = static_cast < Cast * > ( this );

		return * this;
	}

	/**
	 * \brief
	 * Getter of the vector of children.
	 *
	 * \return the child nodes
	 */
	const ext::ptr_vector < Data > & getChildren ( ) & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the vector of children.
	 *
	 * \return the child nodes
	 */
	const ext::ptr_vector < Data > & getChildren ( ) const & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the child nodes.
	 *
	 * \return child nodes
	 */
	ext::ptr_vector < Data > && getChildren ( ) && {
		return std::move ( m_children );
	}

	/**
	 * \brief
	 * Setter of the vector of children.
	 *
	 * \param c the new child nodes in for of a vector
	 */
	void setChildren ( ext::ptr_vector < Data > c ) {
		if ( c.size ( ) != m_children.size ( ) )
			throw "Arity != size";

		m_children = std::move ( c );

		for ( Data & child : m_children )
			child->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Getter of the child at given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to the child at given index
	 */
	Data & getChild ( size_t index ) {
		return m_children [ index ];
	}

	/**
	 * \brief
	 * Getter of the child at given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to the child at given index
	 */
	const Data & getChild ( size_t index ) const {
		return m_children [ index ];
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param it the position where to change the child
	 */
	template < class PositionIterator >
	void setChild ( Data && d, PositionIterator it ) {
		m_children.set ( it, std::move ( d ) )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param it the position where to change the child
	 */
	template < class PositionIterator >
	void setChild ( const Data & d, PositionIterator it ) {
		m_children.set ( it, d )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param index the position where to change the child
	 */
	void setChild ( const Data & d, size_t index ) {
		setChild ( d, m_children.begin ( ) + index );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param index the position where to change the child
	 */
	void setChild ( Data && d, size_t index ) {
		setChild ( std::move ( d ), m_children.begin ( ) + index );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::iterator begin ( ) {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::const_iterator begin ( ) const {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::iterator end ( ) {
		return m_children.end ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::const_iterator end ( ) const {
		return m_children.end ( );
	}

};

/**
 * \brief
 * Varary node is tree node that can hold any number of children.
 *
 * \tparam Data the base class of the actual tree nodes hierarchy on top of this one
 * \tparam Cast the actual class from the actual tree nodes hierarchy
 */
template < class Data, class Cast = Data >
class VararyNode {
	/**
	 * \brief
	 * Representation of child nodes
	 */
	ext::ptr_vector < Data > m_children;

public:
	/**
	 * \brief
	 * Default constructor. Sets the vector of children to empty vector.
	 */
	VararyNode ( ) = default;

	/**
	 * \brief
	 * Constructor from vector of child nodes.
	 *
	 * \param c the vector of child nodes
	 */
	VararyNode ( ext::ptr_vector < Data > c ) : m_children ( std::move ( c ) ) {
		for ( Data & child : m_children )
			child.parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Destructor of the class.
	 */
	virtual ~VararyNode ( ) noexcept = default;

	/**
	 * \brief
	 * Copy constructor of the class.
	 *
	 * \param other the other instance
	 */
	VararyNode ( const VararyNode & other ) : VararyNode ( other.m_children ) {
	}

	/**
	 * \brief
	 * Move constructor of the class.
	 *
	 * \param other the other instance
	 */
	VararyNode ( VararyNode && other ) noexcept : VararyNode ( std::move ( other.m_children ) ) {
	}

	/**
	 * \brief
	 * Copy operator of assignment.
	 *
	 * \param other the other instance
	 */
	VararyNode & operator =( const VararyNode & other ) {
		* this = VararyNode ( other );
		return * this;
	}

	/**
	 * \brief
	 * Move operator of assignment.
	 *
	 * \param other the other instance
	 */
	VararyNode & operator =( VararyNode && other ) noexcept {
		using std::swap;

		swap ( this->m_children, other.m_children );

		for ( Data & child : m_children )
			child.parent = static_cast < Cast * > ( this );

		return * this;
	}

	/**
	 * \brief
	 * Getter of the vector of children.
	 *
	 * \return the child nodes
	 */
	const ext::ptr_vector < Data > & getChildren ( ) & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the vector of children.
	 *
	 * \return the child nodes
	 */
	const ext::ptr_vector < Data > & getChildren ( ) const & {
		return m_children;
	}

	/**
	 * \brief
	 * Getter of the child nodes.
	 *
	 * \return child nodes
	 */
	ext::ptr_vector < Data > && getChildren ( ) && {
		return std::move ( m_children );
	}

	/**
	 * \brief
	 * Setter of the vector of children.
	 *
	 * \param c the new child nodes in for of a vector
	 */
	void setChildren ( ext::ptr_vector < Data > c ) {
		m_children = std::move ( c );

		for ( Data & child : m_children )
			child.parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Getter of the child at given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to the child at given index
	 */
	Data & getChild ( size_t index ) {
		return m_children [ index ];
	}

	/**
	 * \brief
	 * Getter of the child at given index.
	 *
	 * \param index the index to retrieve
	 *
	 * \return reference to the child at given index
	 */
	const Data & getChild ( size_t index ) const {
		return m_children [ index ];
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param it the position where to change the child
	 */
	template < class PositionIterator >
	void setChild ( const Data & d, PositionIterator it ) {
		m_children.set ( it, d )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param it the position where to change the child
	 */
	template < class PositionIterator >
	void setChild ( Data && d, PositionIterator it ) {
		m_children.set ( it, std::move ( d ) )->parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param index the position where to change the child
	 */
	void setChild ( const Data & d, size_t index ) {
		setChild ( d, m_children.begin ( ) + index );
	}

	/**
	 * \brief
	 * Setter of the single child of the node.
	 *
	 * \param d the new child node
	 * \param index the position where to change the child
	 */
	void setChild ( Data && d, size_t index ) {
		setChild ( std::move ( d ), m_children.begin ( ) + index );
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::reverse_iterator it, const Data & d ) {
		return insert ( typename ext::ptr_vector < Data >::const_reverse_iterator ( it ), d );
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::const_reverse_iterator it, const Data & d ) {
		typename ext::ptr_vector < Data >::reverse_iterator iter = m_children.insert ( it, d );

		iter->parent = static_cast < Cast * > ( this );

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::iterator it, const Data & d ) {
		return insert ( typename ext::ptr_vector < Data >::const_iterator ( it ), d );
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::const_iterator it, const Data & d ) {
		typename ext::ptr_vector < Data >::iterator iter = m_children.insert ( it, d );

		iter->parent = static_cast < Cast * > ( this );

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::reverse_iterator it, Data && d ) {
		return insert ( typename ext::ptr_vector < Data >::const_reverse_iterator ( it ), std::move ( d ) );
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::const_reverse_iterator it, Data && d ) {
		typename ext::ptr_vector < Data >::reverse_iterator iter = m_children.insert ( it, std::move ( d ) );

		iter->parent = static_cast < Cast * > ( this );

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::iterator it, Data && d ) {
		return insert ( typename ext::ptr_vector < Data >::const_iterator ( it ), std::move ( d ) );
	}

	/**
	 * \brief
	 * Inserts a new child at position specified by iterator.
	 *
	 * \param it the position where to insert
	 * \param d the new child to insert
	 *
	 * \return the updated iterator to the inserted child
	 */
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::const_iterator it, Data && d ) {
		typename ext::ptr_vector < Data >::iterator iter = m_children.insert ( it, std::move ( d ) );

		iter->parent = static_cast < Cast * > ( this );

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new children from a given range at position specified by iterator.
	 *
	 * \tparam InputIterator tye type of iterators specifying the range of new children
	 *
	 * \param it the position where to insert
	 * \param first the begining of the children range
	 * \param last the end of the children range
	 *
	 * \return the updated iterator to the inserted child
	 */
	template < class InputIterator >
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::const_reverse_iterator it, InputIterator first, InputIterator last ) {
		size_t size = std::distance ( first, last );

		typename ext::ptr_vector < Data >::reverse_iterator iter = m_children.insert ( it, first, last );

		for ( size_t i = 0; i < size; ++ i ) {
			( iter + i )->parent = static_cast < Cast * > ( this );
		}

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new children from a given range at position specified by iterator.
	 *
	 * \tparam InputIterator tye type of iterators specifying the range of new children
	 *
	 * \param it the position where to insert
	 * \param first the begining of the children range
	 * \param last the end of the children range
	 *
	 * \return the updated iterator to the inserted child
	 */
	template < class InputIterator >
	typename ext::ptr_vector < Data >::reverse_iterator insert ( typename ext::ptr_vector < Data >::reverse_iterator it, InputIterator first, InputIterator last ) {
		return insert ( typename ext::ptr_vector < Data >::const_reverse_iterator ( it ), first, last );
	}

	/**
	 * \brief
	 * Inserts a new children from a given range at position specified by iterator.
	 *
	 * \tparam InputIterator tye type of iterators specifying the range of new children
	 *
	 * \param it the position where to insert
	 * \param first the begining of the children range
	 * \param last the end of the children range
	 *
	 * \return the updated iterator to the inserted child
	 */
	template < class InputIterator >
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::const_iterator it, InputIterator first, InputIterator last ) {
		size_t size = std::distance ( first, last );

		typename ext::ptr_vector < Data >::iterator iter = m_children.insert ( it, first, last );

		for ( size_t i = 0; i < size; ++ i ) {
			( iter + i )->parent = static_cast < Cast * > ( this );
		}

		return iter;
	}

	/**
	 * \brief
	 * Inserts a new children from a given range at position specified by iterator.
	 *
	 * \tparam InputIterator tye type of iterators specifying the range of new children
	 *
	 * \param it the position where to insert
	 * \param first the begining of the children range
	 * \param last the end of the children range
	 *
	 * \return the updated iterator to the inserted child
	 */
	template < class InputIterator >
	typename ext::ptr_vector < Data >::iterator insert ( typename ext::ptr_vector < Data >::iterator it, InputIterator first, InputIterator last ) {
		return insert ( typename ext::ptr_vector < Data >::const_iterator ( it ), first, last );
	}

	/**
	 * \brief
	 * Erases a child specified by an iterator.
	 *
	 * \param it the position where to insert
	 *
	 * \return the updated iterator to node after the erased one
	 */
	typename ext::ptr_vector < Data >::reverse_iterator erase ( typename ext::ptr_vector < Data >::reverse_iterator it ) {
		return m_children.erase ( typename ext::ptr_vector < Data >::const_reverse_iterator ( it ) );
	}

	/**
	 * \brief
	 * Erases a child specified by an iterator.
	 *
	 * \param it the position where to insert
	 *
	 * \return the updated iterator to node after the erased one
	 */
	typename ext::ptr_vector < Data >::reverse_iterator erase ( typename ext::ptr_vector < Data >::const_reverse_iterator it ) {
		return m_children.erase ( it );
	}

	/**
	 * \brief
	 * Erases a child specified by an iterator.
	 *
	 * \param it the position where to insert
	 *
	 * \return the updated iterator to node after the erased one
	 */
	typename ext::ptr_vector < Data >::iterator erase ( typename ext::ptr_vector < Data >::iterator it ) {
		return erase ( typename ext::ptr_vector < Data >::const_iterator ( it ) );
	}

	/**
	 * \brief
	 * Erases a child specified by an iterator.
	 *
	 * \param it the position where to insert
	 *
	 * \return the updated iterator to node after the erased one
	 */
	typename ext::ptr_vector < Data >::iterator erase ( typename ext::ptr_vector < Data >::const_iterator it ) {
		return m_children.erase ( it );
	}

	/**
	 * \brief
	 * Erases a range of children specified by an iterator.
	 *
	 * \param first the position where to insert
	 * \param last the position where to insert
	 *
	 * \return the updated iterator to node after the last erased one
	 */
	typename ext::ptr_vector < Data >::reverse_iterator erase ( typename ext::ptr_vector < Data >::reverse_iterator first, typename ext::ptr_vector < Data >::reverse_iterator last ) {
		return m_children.erase ( typename ext::ptr_vector < Data >::const_reverse_iterator ( first ), typename ext::ptr_vector < Data >::const_reverse_iterator ( last ) );
	}

	/**
	 * \brief
	 * Erases a range of children specified by an iterator.
	 *
	 * \param first the position where to insert
	 * \param last the position where to insert
	 *
	 * \return the updated iterator to node after the last erased one
	 */
	typename ext::ptr_vector < Data >::reverse_iterator erase ( typename ext::ptr_vector < Data >::const_reverse_iterator first, typename ext::ptr_vector < Data >::const_reverse_iterator last ) {
		return m_children.erase ( first, last );
	}

	/**
	 * \brief
	 * Erases a range of children specified by an iterator.
	 *
	 * \param first the position where to insert
	 * \param last the position where to insert
	 *
	 * \return the updated iterator to node after the last erased one
	 */
	typename ext::ptr_vector < Data >::iterator erase ( typename ext::ptr_vector < Data >::iterator first, typename ext::ptr_vector < Data >::iterator last ) {
		return m_children.erase ( typename ext::ptr_vector < Data >::const_iterator ( first ), typename ext::ptr_vector < Data >::const_iterator ( last ) );
	}

	/**
	 * \brief
	 * Erases a range of children specified by an iterator.
	 *
	 * \param first the position where to insert
	 * \param last the position where to insert
	 *
	 * \return the updated iterator to node after the last erased one
	 */
	typename ext::ptr_vector < Data >::iterator erase ( typename ext::ptr_vector < Data >::const_iterator first, typename ext::ptr_vector < Data >::const_iterator last ) {
		return m_children.erase ( first, last );
	}

	/**
	 * \brief
	 * Erases all children.
	 */
	void clear ( ) {
		m_children.clear ( );
	}

	/**
	 * \brief
	 * Appends a new child at the end of the child vector.
	 *
	 * \param d the new child to add
	 */
	void pushBackChild ( const Data & d ) {
		m_children.push_back ( d );
		m_children [ m_children.size ( ) - 1].parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Appends a new child at the end of the child vector.
	 *
	 * \param d the new child to add
	 */
	void pushBackChild ( Data && d ) {
		m_children.push_back ( std::move ( d ) );
		m_children [ m_children.size ( ) - 1].parent = static_cast < Cast * > ( this );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::iterator begin ( ) {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::const_iterator begin ( ) const {
		return m_children.begin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::reverse_iterator rbegin ( ) {
		return m_children.rbegin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the begining of children vector
	 *
	 * \return begin iterator
	 */
	typename ext::ptr_vector < Data >::const_reverse_iterator rbegin ( ) const {
		return m_children.rbegin ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::iterator end ( ) {
		return m_children.end ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::const_iterator end ( ) const {
		return m_children.end ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::reverse_iterator rend ( ) {
		return m_children.rend ( );
	}

	/**
	 * \brief
	 * Getter of an iterator to the end of children vector
	 *
	 * \return end iterator
	 */
	typename ext::ptr_vector < Data >::const_reverse_iterator rend ( ) const {
		return m_children.rend ( );
	}

};

} /* namespace ext */

#endif /* __TREE_BASE_HPP_ */
