/*
 * ranked_symbol.h
 *
 *  Created on: Apr 10, 2013
 *      Author: Stepan Plachy
 */

#pragma once

#include <alib/tuple>

#include <core/normalize.hpp>

#include <common/DefaultSymbolType.h>

namespace common {

/**
 * Represents symbol in an std.
 */
template < class SymbolType = DefaultSymbolType >
class ranked_symbol {
	SymbolType m_symbol;
	size_t m_rank;

public:
	/**
	 * Creates new symbol with given name and rank.
	 * @param symbol name of the symbol
	 * @param rank of the symbol
	 */
	explicit ranked_symbol ( SymbolType symbol, size_t rank );

	/**
	 * @return name of the symbol
	 */
	const SymbolType & getSymbol ( ) const &;

	/**
	 * @return name of the symbol
	 */
	SymbolType && getSymbol ( ) &&;

	/**
	 * @return rank of the symbol
	 */
	const size_t & getRank ( ) const &;

	/**
	 * @return rank of the symbol
	 */
	size_t getRank ( ) &&;

	explicit operator std::string ( ) const;

	auto operator <=> ( const ranked_symbol & other ) const {
		return ext::tie ( m_symbol, m_rank ) <=> ext::tie ( other.m_symbol, other.m_rank );
	}

	bool operator == ( const ranked_symbol & other ) const {
		return ext::tie ( m_symbol, m_rank ) == ext::tie ( other.m_symbol, other.m_rank );
	}

	ranked_symbol < SymbolType > & operator ++ ( ) {
		++ m_symbol;

		return *this;
	}
};

template < class SymbolType >
ranked_symbol < SymbolType >::ranked_symbol(SymbolType symbol, size_t rank) : m_symbol(std::move(symbol)), m_rank(rank) {

}

template < class SymbolType >
const SymbolType & ranked_symbol < SymbolType >::getSymbol ( ) const & {
	return m_symbol;
}

template < class SymbolType >
SymbolType && ranked_symbol < SymbolType >::getSymbol ( ) && {
	return std::move ( m_symbol );
}

template < class SymbolType >
const size_t & ranked_symbol < SymbolType >::getRank ( ) const & {
	return m_rank;
}

template < class SymbolType >
size_t ranked_symbol < SymbolType >::getRank ( ) && {
	return m_rank;
}

template < class SymbolType >
ranked_symbol < SymbolType >::operator std::string () const {
	return ext::to_string ( m_symbol ) + "_" + ext::to_string ( m_rank );
}

template < class SymbolType >
std::ostream & operator << ( std::ostream & out, const common::ranked_symbol < SymbolType > & symbol ) {
	out << "(ranked_symbol " << symbol.getSymbol ( ) << " #" << symbol.getRank ( ) << ")";
	return out;
}

} /* namespace common */

