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

#ifndef RANKED_SYMBOL_HPP_
#define RANKED_SYMBOL_HPP_

#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 ( ) &&;

	int compare ( const ranked_symbol & other ) const;

	explicit operator std::string ( ) const;

	bool operator < ( const ranked_symbol & other ) const {
		return compare ( other ) < 0;
	}

	bool operator > ( const ranked_symbol & other ) const {
		return compare ( other ) > 0;
	}

	bool operator <= ( const ranked_symbol & other ) const {
		return compare ( other ) <= 0;
	}

	bool operator >= ( const ranked_symbol & other ) const {
		return compare ( other ) >= 0;
	}

	bool operator == ( const ranked_symbol & other ) const {
		return compare ( other ) == 0;
	}

	bool operator != ( const ranked_symbol & other ) const {
		return compare ( other ) != 0;
	}

	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 >
int ranked_symbol < SymbolType >::compare(const ranked_symbol& other) const {
	auto first = ext::tie ( m_symbol, m_rank );
	auto second = ext::tie ( other.m_symbol, other.m_rank );

	static ext::compare<decltype(first)> comp;
	return comp(first, second);
}

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 */

namespace ext {

template < class T >
struct compare < common::ranked_symbol < T > > {
	int operator ()( const common::ranked_symbol < T > & first, const common::ranked_symbol < T > & second ) const {
		return first.compare ( second );
	}

};

} /* namespace ext */

#endif /* RANKED_SYMBOL_HPP_ */
