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

#ifndef RTE_GLUSHKOV_INDEXATE_H_
#define RTE_GLUSHKOV_INDEXATE_H_

#include <common/ranked_symbol.hpp>
#include <alib/pair>

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

namespace rte {

class GlushkovIndexate {
public:
	/**
	 * @param rte rte to index
	 * @return FormalRTE with indexed elements
	 */
	template < class SymbolType >
	static FormalRTE < ext::pair < SymbolType, unsigned > > index ( const rte::FormalRTE < SymbolType > & rte ) {
		unsigned i = 1;

		return FormalRTE < ext::pair < SymbolType, unsigned > > ( FormalRTEStructure < ext::pair < SymbolType, unsigned > > ( rte.getRTE ( ).getStructure ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i ) ) );
	}

	template < class SymbolType >
	class Formal {
	public:
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTEAlternation < SymbolType > & node, unsigned & i );
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTESubstitution < SymbolType > & node, unsigned & i );
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTEIteration < SymbolType > & node, unsigned & i );
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, unsigned & i );
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, unsigned & i );
		static ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > visit ( const rte::FormalRTEEmpty < SymbolType > & node, unsigned & i );
	};

};

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, unsigned & i ) {
	ext::pair < SymbolType, unsigned > sps = ext::make_pair ( node.getSymbol ( ).getSymbol ( ), i ++ );
	ext::ptr_vector < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > children;
	for ( const rte::FormalRTEElement < SymbolType > & e : node.getElements ( ) ) {
		children.push_back ( ( FormalRTEElement < ext::pair < SymbolType, unsigned > > && ) e.template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i ) );
	}

	return ext::ptr_value < FormalRTESymbolAlphabet < ext::pair < SymbolType, unsigned > > > ( FormalRTESymbolAlphabet < ext::pair < SymbolType, unsigned > > ( common::ranked_symbol < ext::pair < SymbolType, unsigned > > ( sps , node.getSymbol ( ).getRank ( ) ), std::move ( children ) ) );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, unsigned & ) {
	return ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > ( FormalRTESymbolSubst < ext::pair < SymbolType, unsigned > > ( common::ranked_symbol < ext::pair < SymbolType, unsigned > > ( ext::make_pair ( node.getSymbol ( ).getSymbol ( ), 0u ), node.getSymbol ( ).getRank ( ) ) ) );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTEAlternation < SymbolType > & node, unsigned & i ) {
	ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > left = node.getLeftElement ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i );
	ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > right = node.getRightElement ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i );
	return ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > ( FormalRTEAlternation < ext::pair < SymbolType, unsigned > > ( std::move ( left ), std::move ( right ) ) );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTESubstitution < SymbolType > & node, unsigned & i ) {
	ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > left = node.getLeftElement ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i );
	ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > right = node.getRightElement ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i );
	FormalRTESymbolSubst < ext::pair < SymbolType, unsigned > > substSymbol ( common::ranked_symbol < ext::pair < SymbolType, unsigned > > ( ext::make_pair ( node.getSubstitutionSymbol ( ).getSymbol ( ).getSymbol ( ), 0u ), node.getSubstitutionSymbol ( ).getSymbol ( ).getRank ( ) ) );
	return ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > ( FormalRTESubstitution < ext::pair < SymbolType, unsigned > > ( std::move ( left ), std::move ( right ), std::move ( substSymbol ) ) );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTEIteration < SymbolType > & node, unsigned & i ) {
	ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > > element = node.getElement ( ).template accept < ext::ptr_value < rte::FormalRTEElement < ext::pair < SymbolType, unsigned > > >, GlushkovIndexate::Formal < SymbolType > > ( i );
	FormalRTESymbolSubst < ext::pair < SymbolType, unsigned > > substSymbol ( common::ranked_symbol < ext::pair < SymbolType, unsigned > > ( ext::make_pair ( node.getSubstitutionSymbol ( ).getSymbol ( ).getSymbol ( ), 0u ), node.getSubstitutionSymbol ( ).getSymbol ( ).getRank ( ) ) );
	return ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > ( FormalRTEIteration < ext::pair < SymbolType, unsigned > > ( std::move ( element ), std::move ( substSymbol ) ) );
}

template < class SymbolType >
ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > GlushkovIndexate::Formal < SymbolType >::visit ( const rte::FormalRTEEmpty < SymbolType > &, unsigned & ) {
	return ext::ptr_value < FormalRTEElement < ext::pair < SymbolType, unsigned > > > ( FormalRTEEmpty < ext::pair < SymbolType, unsigned > > ( ) );
}

} /* namespace rte */

#endif /* RTE_GLUSHKOV_INDEXATE_H_ */
