/*
 * GlushkovPos.h
 *
 *  Created on: 13. 3. 2014
 *	  Author: Tomas Pecka
 */

#ifndef GLUSHKOV_POS_H_
#define GLUSHKOV_POS_H_

#include <regexp/unbounded/UnboundedRegExp.h>

#include <regexp/unbounded/UnboundedRegExpAlternation.h>
#include <regexp/unbounded/UnboundedRegExpConcatenation.h>
#include <regexp/unbounded/UnboundedRegExpElement.h>
#include <regexp/unbounded/UnboundedRegExpEmpty.h>
#include <regexp/unbounded/UnboundedRegExpEpsilon.h>
#include <regexp/unbounded/UnboundedRegExpIteration.h>
#include <regexp/unbounded/UnboundedRegExpSymbol.h>

namespace regexp {

/**
 * RegExp tree traversal utils for Glushkov algorithm.
 *
 * Thanks to http://www.sciencedirect.com/science/article/pii/S030439759700296X for better follow() solution.
 */
class GlushkovPos {
public:
	/**
	 * @return bool true if symbol is in this regexp
	 */
	template < class SymbolType >
	static bool pos ( const UnboundedRegExpSymbol < SymbolType > & symbol, const regexp::UnboundedRegExp < SymbolType > & node );

	template < class SymbolType >
	class Unbounded {
	public:
		static bool visit ( const regexp::UnboundedRegExpAlternation < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol );
		static bool visit ( const regexp::UnboundedRegExpConcatenation < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol );
		static bool visit ( const regexp::UnboundedRegExpIteration < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol );
		static bool visit ( const regexp::UnboundedRegExpSymbol < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol );
		static bool visit ( const regexp::UnboundedRegExpEmpty < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbSearch );
		static bool visit ( const regexp::UnboundedRegExpEpsilon < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbSearch );
	};
};

template < class SymbolType >
bool GlushkovPos::pos ( const UnboundedRegExpSymbol < SymbolType > & symbol, const regexp::UnboundedRegExp < SymbolType > & node ) {
	return node.getRegExp ( ).getStructure ( ).template accept < bool, GlushkovPos::Unbounded < SymbolType > > ( symbol );
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpAlternation < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol ) {
	return std::any_of ( node.getElements ( ).begin ( ), node.getElements ( ).end ( ), [ & ] ( const UnboundedRegExpElement < SymbolType > & element ) {
		return element.template accept < bool, GlushkovPos::Unbounded < SymbolType > > ( symbol );
	} );
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpConcatenation < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol ) {
	return std::any_of ( node.getElements ( ).begin ( ), node.getElements ( ).end ( ), [ & ] ( const UnboundedRegExpElement < SymbolType > & element ) {
		return element.template accept < bool, GlushkovPos::Unbounded < SymbolType > > ( symbol );
	} );
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpIteration < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol ) {
	return node.getElement ( ).template accept < bool, GlushkovPos::Unbounded < SymbolType > > ( symbol );
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpSymbol < SymbolType > & node, const regexp::UnboundedRegExpSymbol < SymbolType > & symbol ) {
	return symbol == node;
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpEmpty < SymbolType > & /* node */, const regexp::UnboundedRegExpSymbol < SymbolType > & /* symbol */ ) {
	return false;
}

template < class SymbolType >
bool GlushkovPos::Unbounded < SymbolType >::visit ( const regexp::UnboundedRegExpEpsilon < SymbolType > & /* node */, const regexp::UnboundedRegExpSymbol < SymbolType > & /* symbol */ ) {
	return false;
}

} /* namespace regexp */

#endif /* GLUSHKOV_POS_H_ */
