/*
 * TreeToStringComposerCommon.h
 *
 * Created on: Sep 27, 2017
 * Author: Jan Travnicek
 */

#ifndef _TREE_TO_STRING_COMPOSER_COMMON_H_
#define _TREE_TO_STRING_COMPOSER_COMMON_H_

#include <ostream>
#include <alib/vector>

#include <core/stringApi.hpp>

namespace tree {

class TreeToStringComposerCommon {
public:
	template < class SymbolType >
	static void compose ( std::ostream &, const ext::tree < common::ranked_symbol < SymbolType > > & node );
	template < class SymbolType >
	static void compose ( std::ostream &, const common::ranked_symbol < SymbolType > & subtreeWildcard, const ext::tree < common::ranked_symbol < SymbolType > > & node );
	template < class SymbolType >
	static void compose ( std::ostream &, const ext::tree < SymbolType > & node );
	template < class SymbolType >
	static void compose ( std::ostream &, const SymbolType & subtreeWildcard, const ext::tree < SymbolType > & node );
};

template < class SymbolType >
void TreeToStringComposerCommon::compose ( std::ostream & out, const ext::tree < common::ranked_symbol < SymbolType> > & node ) {
	core::stringApi < SymbolType >::compose ( out, node.getData ( ).getSymbol ( ) );

	out << " " << ext::to_string ( node.getData ( ).getRank ( ) );

	for ( const ext::tree < common::ranked_symbol < SymbolType > > & child : node ) {
		out << " ";
		compose ( out, child );
	}
}

template < class SymbolType >
void TreeToStringComposerCommon::compose ( std::ostream & out, const common::ranked_symbol < SymbolType > & subtreeWildcard, const ext::tree < common::ranked_symbol < SymbolType > > & node ) {
	if ( node.getData ( ) == subtreeWildcard ) {
		out << "#S";
	} else {
		core::stringApi < SymbolType >::compose ( out, node.getData ( ).getSymbol ( ) );

		out << " " << ext::to_string ( node.getData ( ).getRank ( ) );

		for ( const ext::tree < common::ranked_symbol < SymbolType > > & child : node ) {
			out << " ";
			compose ( out, subtreeWildcard, child );
		}
	}
}

template < class SymbolType >
void TreeToStringComposerCommon::compose ( std::ostream & out, const ext::tree < SymbolType > & node ) {
	core::stringApi < SymbolType >::compose ( out, node.getData ( ) );

	for ( const ext::tree < SymbolType > & child : node ) {
		out << " ";
		compose ( out, child );
	}

	out << " |";
}

template < class SymbolType >
void TreeToStringComposerCommon::compose ( std::ostream & out, const SymbolType & subtreeWildcard, const ext::tree < SymbolType > & node ) {
	if ( node.getData ( ) == subtreeWildcard ) {
		out << "#S |";
	} else {
		core::stringApi < SymbolType >::compose ( out, node.getData ( ) );

		for ( const ext::tree < SymbolType > & child : node ) {
			out << " ";
			compose ( out, subtreeWildcard, child );
		}

		out << " |";
	}
}

} /* namespace tree */

#endif /* _TREE_TO_STRING_COMPOSER_COMMON_H_ */
