/*
 * DotConverterRTE.h
 *
 *  Created on: 15. 3. 2019
 *	  Author: Tomas Pecka
 */

#ifndef DOT_CONVERTER_RTE_H
#define DOT_CONVERTER_RTE_H

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

namespace convert {

class DotConverterRTE {
public:
	template < class SymbolType >
	static std::string convertInternal ( const rte::FormalRTE < SymbolType > & rte, const std::string & nodePrefix = "" );

	template < class SymbolType >
	class Formal {
	public:
		static unsigned visit ( const rte::FormalRTEAlternation < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
		static unsigned visit ( const rte::FormalRTESubstitution < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
		static unsigned visit ( const rte::FormalRTEIteration < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
		static unsigned visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
		static unsigned visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
		static unsigned visit ( const rte::FormalRTEEmpty < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix );
	};
};

template < class SymbolType >
std::string DotConverterRTE::convertInternal ( const rte::FormalRTE < SymbolType > & rte, const std::string & nodePrefix ) {
	std::stringstream oss;
	unsigned nodeIdCounter = 0;
	rte.getRTE ( ).getStructure ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );
	return oss.str ( );
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTEAlternation < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	unsigned id = nodeIdCounter ++;

	oss << nodePrefix << id << "[label=\"+\", shape=plaintext];" << std::endl;

	size_t lId = node.getLeftElement  ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );
	size_t rId = node.getRightElement ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );

	oss << nodePrefix << id << " -> " << nodePrefix << lId << ";" << std::endl;
	oss << nodePrefix << id << " -> " << nodePrefix << rId << ";" << std::endl;
	return id;
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTESubstitution < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	unsigned id = nodeIdCounter ++;

	oss << nodePrefix << id << "[label=\". " << node.getSubstitutionSymbol( ).getSymbol ( ).getSymbol ( ) << "\", shape=plaintext];" << std::endl;

	size_t lId = node.getLeftElement  ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );
	size_t rId = node.getRightElement ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );

	oss << nodePrefix << id << " -> " << nodePrefix << lId << ";" << std::endl;
	oss << nodePrefix << id << " -> " << nodePrefix << rId << ";" << std::endl;
	return id;
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTEIteration < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	unsigned id = nodeIdCounter ++;

	oss << nodePrefix << id << "[label=\"* " << node.getSubstitutionSymbol( ).getSymbol ( ).getSymbol ( ) << "\", shape=plaintext];" << std::endl;

	unsigned childId = node.getElement ( ).template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );

	oss << nodePrefix << id << " -> " << nodePrefix << childId << ";" << std::endl;
	return id;
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTESymbolAlphabet < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	unsigned id = nodeIdCounter ++;

	oss << nodePrefix << id << "[label=\"" << node.getSymbol( ).getSymbol ( ) << "\", shape=plaintext];" << std::endl;

	for ( const auto & child : node.getChildren ( ) ) {
		unsigned childId = child.template accept < unsigned, DotConverterRTE::Formal < SymbolType > > ( oss, nodeIdCounter, nodePrefix );
		oss << nodePrefix << id << " -> " << nodePrefix << childId << ";" << std::endl;
	}

	return id;
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTESymbolSubst < SymbolType > & node, std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	oss << nodePrefix << nodeIdCounter << "[label=\"" << node.getSymbol ( ).getSymbol ( ) << "\", shape=plaintext];" << std::endl;
	return nodeIdCounter ++;
}

template < class SymbolType >
unsigned DotConverterRTE::Formal < SymbolType >::visit ( const rte::FormalRTEEmpty < SymbolType > & , std::stringstream & oss, unsigned & nodeIdCounter, const std::string & nodePrefix ) {
	oss << nodePrefix << nodeIdCounter << "[label=\"#0\", shape=plaintext];" << std::endl;
	return nodeIdCounter ++;
}

} /* namespace convert */

#endif /* DOT_CONVERTER_RTE_H */
