/*
 * GlushkovPos.h
 *
 *  Created on: 14. 4. 2016
 *	  Author: Tomas Pecka
 */

#ifndef RTE_GLUSHKOV_POS_H_
#define RTE_GLUSHKOV_POS_H_

#include <common/ranked_symbol.hpp>

#include <rte/formal/FormalRTE.h>
#include <rte/formal/FormalRTEElements.h>

namespace rte {

class GlushkovPos {
public:
	/**
	 * @return bool true if symbol pointer is in this subtree
	 */
	template < class SymbolType >
	static bool pos ( const common::ranked_symbol < SymbolType > & symbol, const rte::FormalRTE < SymbolType > & rte );

	template < class SymbolType >
	class Formal {
	public:
		static bool visit ( const rte::FormalRTEAlternation < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF );
		static bool visit ( const rte::FormalRTESubstitution < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF );
		static bool visit ( const rte::FormalRTEIteration < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF );
		static bool visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF );
		static bool visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF );
		static bool visit ( const rte::FormalRTEEmpty < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbSearch );
	};
};

template < class SymbolType >
bool GlushkovPos::pos ( const common::ranked_symbol < SymbolType > & symbol, const rte::FormalRTE < SymbolType > & rte ) {
	return rte.getRTE ( ).getStructure ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbol );
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTEAlternation < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF ) {
	return node.getLeftElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF ) || node.getRightElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF );
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTESubstitution < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF ) {
	return node.getLeftElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF ) || node.getRightElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF );
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTEIteration < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF ) {
	return node.getElement ( ).template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF );
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF ) {
	if ( symbolF == node.getSymbol ( ) ) return true;

	for ( const rte::FormalRTEElement < SymbolType > & element : node.getElements ( ) )
		if ( element.template accept < bool, GlushkovPos::Formal < SymbolType > > ( symbolF ) )
			return true;

	return false;
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, const common::ranked_symbol < SymbolType > & symbolF ) {
	return symbolF == node.getSymbol ( );
}

template < class SymbolType >
bool GlushkovPos::Formal < SymbolType >::visit ( const rte::FormalRTEEmpty < SymbolType > & /* node */, const common::ranked_symbol < SymbolType > & /* symbolF */ ) {
	return false;
}

} /* namespace rte */

#endif /* RTE_GLUSHKOV_POS_H_ */
