/******************************************************************************/
/* ALGORITHMS - INLINE CODE ***************************************************/
/******************************************************************************/

#ifndef _H_EBCL_INLINE_ALGORITHMS
#define _H_EBCL_INLINE_ALGORITHMS
#include <ebcl/Algorithms.hh>
namespace ebcl {


/*= VISITOR ==================================================================*/

// Specialization of the visitor helper for references
template< typename R >
struct T_VisitorHelper_< R , true >
{
	using T_Base = typename std::remove_reference< R >::type;
	using T_Opt = T_Base*;
	using T_StackRef = T_Base*;

	static T_StackRef mkext( R value ) noexcept { return &value; }
	static R deref( T_StackRef ref ) noexcept { return *ref; }
};

// Specialization of the visitor helper for values
template< typename R >
struct T_VisitorHelper_< R , false >
{
	using T_Base = typename std::remove_const< R >::type;
	using T_Opt = T_Optional< T_Base >;
	using T_StackRef = T_Base;

	static T_StackRef mkext( R value ) noexcept { return value; }
	static R deref( T_StackRef ref ) noexcept { return ref; }
};

/*----------------------------------------------------------------------------*/

template< typename T , typename R >
inline T_Visitor< T , R  >::T_Visitor(
		F_NodeBrowser browser ) noexcept
	: nodeBrowser_( std::move( browser ) )
{ }

template< typename T , typename R >
inline void T_Visitor< T , R >::visit(
		R root ,
		F_NodeAction action )
{
	stack_.addNew( root , 0 );

	while ( !stack_.empty( ) ) {
		auto& n( stack_.last( ) );
		switch ( n.state ) {
		    case BEFORE:
			n.state = action( Helper_::deref( n.node ) , false )
				? CHILDREN : AFTER;
			break;

		    case CHILDREN: {
			const T_OptNode child{
				nodeBrowser_( Helper_::deref( n.node ) , n.child ++ ) };
			if ( child ) {
				stack_.addNew( *child , 0 );
			} else {
				n.state = AFTER;
			}
			break;
		    }

		    case AFTER:
			action( Helper_::deref( n.node ) , true );
			stack_.removeLast( );
			break;
		}
	}
}




} // namespace
#endif // _H_EBCL_INLINE_ALGORITHMS