/*
 * IndexesNormalize.h
 *
 *  Created on: Apr 7, 2017
 *      Author: Jan Travnicek
 */

#pragma once

#include <alib/vector>
#include <alib/tuple>
#include <alib/set>
#include <alib/trie>

#include <alphabet/common/SymbolNormalize.h>

namespace indexes {

/**
 * This class contains methods to print XML representation of automata to the output stream.
 */
class IndexesNormalize {
	template < class SymbolType, class ValueType >
	static ext::trie < DefaultSymbolType, ValueType > normalizeTrieInner ( ext::trie < SymbolType, ValueType > && node ) {
		ext::map < DefaultSymbolType, ext::trie < DefaultSymbolType, ValueType > > children;

		for ( std::pair < SymbolType, ext::trie < SymbolType, ValueType > > && child : ext::make_mover ( node.getChildren ( ) ) ) {
			children.insert ( std::make_pair ( alphabet::SymbolNormalize::normalizeSymbol ( std::move ( child.first ) ), normalizeTrieInner ( std::move ( child.second ) ) ) );
		}

		return ext::trie < DefaultSymbolType, ValueType > ( std::move ( node.getData ( ) ), std::move ( children ) );
	}

	template < class SymbolType, class ValueType >
	static ext::trie < common::ranked_symbol < DefaultSymbolType >, ValueType > normalizeRankedTrieInner ( ext::trie < common::ranked_symbol < SymbolType >, ValueType > && node ) {
		ext::map < common::ranked_symbol < DefaultSymbolType >, ext::trie < common::ranked_symbol < DefaultSymbolType >, ValueType > > children;

		for ( std::pair < common::ranked_symbol < SymbolType >, ext::trie < common::ranked_symbol < SymbolType >, ValueType > > && child : ext::make_mover ( node.getChildren ( ) ) ) {
			children.insert ( std::make_pair ( alphabet::SymbolNormalize::normalizeRankedSymbol ( std::move ( child.first ) ), normalizeRankedTrieInner ( std::move ( child.second ) ) ) );
		}

		return ext::trie < common::ranked_symbol < DefaultSymbolType >, ValueType > ( std::move ( node.getData ( ) ), std::move ( children ) );
	}

public:
	template < class SymbolType >
	static ext::trie < DefaultSymbolType, unsigned > normalizeTrie ( ext::trie < SymbolType, unsigned > && trie );

	template < class SymbolType >
	static ext::trie < DefaultSymbolType, std::optional < unsigned > > normalizeTrie ( ext::trie < SymbolType, std::optional < unsigned > > && trie );

	template < class SymbolType >
	static ext::trie < common::ranked_symbol < DefaultSymbolType >, unsigned > normalizeRankedTrie ( ext::trie < common::ranked_symbol < SymbolType >, unsigned > && trie );

	template < class SymbolType >
	static ext::trie < common::ranked_symbol < DefaultSymbolType >, std::optional < unsigned > > normalizeRankedTrie ( ext::trie < common::ranked_symbol < SymbolType >, std::optional < unsigned > > && trie );

	template < class SymbolType >
    static ext::map < DefaultSymbolType, unsigned > normalizeMap ( ext::map < SymbolType, unsigned > && map );

};

template < class SymbolType >
ext::trie < DefaultSymbolType, unsigned > IndexesNormalize::normalizeTrie ( ext::trie < SymbolType, unsigned > && trie ) {
	return  normalizeTrieInner ( std::move ( trie ) ) ;
}

template < class SymbolType >
ext::trie < DefaultSymbolType, std::optional < unsigned > > IndexesNormalize::normalizeTrie ( ext::trie < SymbolType, std::optional < unsigned > > && trie ) {
	return  normalizeTrieInner ( std::move ( trie ) ) ;
}

template < class SymbolType >
ext::trie < common::ranked_symbol < DefaultSymbolType >, unsigned > IndexesNormalize::normalizeRankedTrie ( ext::trie < common::ranked_symbol < SymbolType >, unsigned > && trie ) {
	return  normalizeRankedTrieInner ( std::move ( trie ) ) ;
}

template < class SymbolType >
ext::trie < common::ranked_symbol < DefaultSymbolType >, std::optional < unsigned > > IndexesNormalize::normalizeRankedTrie ( ext::trie < common::ranked_symbol < SymbolType >, std::optional < unsigned > > && trie ) {
	return  normalizeRankedTrieInner ( std::move ( trie ) ) ;
}

template < class SymbolType >
ext::map < DefaultSymbolType, unsigned >
IndexesNormalize::normalizeMap ( ext::map < SymbolType, unsigned int > && map ) {
    ext::map < DefaultSymbolType, unsigned > res;
    for ( auto && [symbol, val] : ext::make_mover(map) )
        res.insert ( alphabet::SymbolNormalize::normalizeSymbol ( symbol ), val );
    return res;
}

} /* namespace indexes */

