/*
 * AutomatonNormalize.h
 *
 *  Created on: Mar 31, 2017
 *      Author: Jan Travnicek
 */

#pragma once

#include <alib/deque>
#include <alib/vector>
#include <alib/set>
#include <alib/multiset>
#include <alib/map>

#include <regexp/unbounded/UnboundedRegExpStructure.h>
#include <alphabet/common/SymbolNormalize.h>

#include <common/DefaultStateType.h>
#include <common/DefaultSymbolType.h>
#include <common/symbol_or_epsilon.hpp>

namespace automaton {

/**
 * This class contains methods to print XML representation of automata to the output stream.
 */
class AutomatonNormalize {
public:
	template < class StateType >
	static ext::multiset < DefaultStateType > normalizeStates ( ext::multiset < StateType > && states );

	template < class StateType >
	static ext::set < DefaultStateType > normalizeStates ( ext::set < StateType > && states );

	template < class StateType >
	static ext::vector < DefaultStateType > normalizeStates ( ext::vector < StateType > && states );

	template < class StateType >
	static DefaultStateType normalizeState ( StateType && state);

	template < class SymbolType >
	static common::symbol_or_epsilon < DefaultSymbolType > normalizeSymbolEpsilon ( common::symbol_or_epsilon < SymbolType > && symbol );

	template < class SymbolType >
	static regexp::UnboundedRegExpStructure < DefaultSymbolType > normalizeRegExp ( regexp::UnboundedRegExpStructure < SymbolType > && regexp );

};

template < class StateType >
ext::multiset < DefaultStateType > AutomatonNormalize::normalizeStates ( ext::multiset < StateType > && states ) {
	ext::multiset < DefaultStateType > res;
	for ( StateType && state : ext::make_mover ( states ) )
		res.insert ( normalizeState ( std::move ( state ) ) );

	return res;
}

template < class StateType >
ext::set < DefaultStateType > AutomatonNormalize::normalizeStates ( ext::set < StateType > && states ) {
	ext::set < DefaultStateType > res;
	for ( StateType && state : ext::make_mover ( states ) )
		res.insert ( normalizeState ( std::move ( state ) ) );

	return res;
}

template < class StateType >
ext::vector < DefaultStateType > AutomatonNormalize::normalizeStates ( ext::vector < StateType > && states ) {
	ext::vector < DefaultStateType > res;
	for ( StateType & state : states )
		res.push_back ( normalizeState ( std::move ( state ) ) );

	return res;
}

template < class StateType >
DefaultStateType AutomatonNormalize::normalizeState ( StateType && state) {
	return DefaultStateType ( std::forward < StateType > ( state ) );
}

template < class SymbolType >
common::symbol_or_epsilon < DefaultSymbolType > AutomatonNormalize::normalizeSymbolEpsilon ( common::symbol_or_epsilon < SymbolType > && symbol ) {
	if ( symbol.is_epsilon ( ) )
		return common::symbol_or_epsilon < DefaultSymbolType > ( );
	else
		return common::symbol_or_epsilon < DefaultSymbolType > ( alphabet::SymbolNormalize::normalizeSymbol ( std::move ( symbol ).getSymbol ( ) ) );
}

template < class SymbolType >
regexp::UnboundedRegExpStructure < DefaultSymbolType > AutomatonNormalize::normalizeRegExp ( regexp::UnboundedRegExpStructure < SymbolType > && regexp ) {
	return std::move ( regexp ).normalize ( );

}

} /* namespace automaton */


