/*
 * SuffixTrieTerminatingSymbol.h
 *
 *  Created on: Nov 23, 2013
 *      Author: Jan Travnicek
 */

#pragma once

#include <alib/vector>
#include <alib/list>
#include <alib/string>
#include <alib/set>
#include <core/components.hpp>
#include "SuffixTrieNodeTerminatingSymbol.h"

namespace indexes {

class GeneralAlphabet;
class TerminatingSymbol;

/**
 * Represents regular expression parsed from the XML. Regular expression is stored
 * as a tree of RegExpElement.
 */
class SuffixTrieTerminatingSymbol final : public core::Components < SuffixTrieTerminatingSymbol, ext::set < DefaultSymbolType >, component::Set, GeneralAlphabet, DefaultSymbolType, component::Value, TerminatingSymbol > {
protected:
	SuffixTrieNodeTerminatingSymbol * m_tree;

public:
	explicit SuffixTrieTerminatingSymbol ( ext::set < DefaultSymbolType > alphabet, DefaultSymbolType terminatingSymbol );
	explicit SuffixTrieTerminatingSymbol ( ext::set < DefaultSymbolType > alphabet, DefaultSymbolType terminatingSymbol, SuffixTrieNodeTerminatingSymbol tree );
	explicit SuffixTrieTerminatingSymbol ( DefaultSymbolType terminatingSymbol, SuffixTrieNodeTerminatingSymbol tree );

	/**
	 * Copy constructor.
	 * @param other tree to copy
	 */
	SuffixTrieTerminatingSymbol ( const SuffixTrieTerminatingSymbol & other );
	SuffixTrieTerminatingSymbol ( SuffixTrieTerminatingSymbol && other ) noexcept;
	SuffixTrieTerminatingSymbol & operator =( const SuffixTrieTerminatingSymbol & other );
	SuffixTrieTerminatingSymbol & operator =( SuffixTrieTerminatingSymbol && other ) noexcept;
	~SuffixTrieTerminatingSymbol ( ) noexcept;

	/**
	 * @return Root node of the regular expression tree
	 */
	const SuffixTrieNodeTerminatingSymbol & getRoot ( ) const;

	/**
	 * @return Root node of the regular expression tree
	 */
	SuffixTrieNodeTerminatingSymbol & getRoot ( );

	/**
	 * Sets the root node of the regular expression tree
	 * @param tree root node to set
	 */
	void setTree ( SuffixTrieNodeTerminatingSymbol tree );

	const ext::set < DefaultSymbolType > & getAlphabet ( ) const {
		return accessComponent < GeneralAlphabet > ( ).get ( );
	}

	const DefaultSymbolType & getTerminatingSymbol ( ) const {
		return accessComponent < TerminatingSymbol > ( ).get ( );
	}

	friend std::ostream & operator << ( std::ostream & out, const SuffixTrieTerminatingSymbol & instance );

	auto operator <=> ( const SuffixTrieTerminatingSymbol & other ) const {
		return std::tie ( * m_tree, getAlphabet(), getTerminatingSymbol() ) <=> std::tie ( * other.m_tree, other.getAlphabet(), other.getTerminatingSymbol() );
	}

	bool operator == ( const SuffixTrieTerminatingSymbol & other ) const {
		return std::tie ( * m_tree, getAlphabet(), getTerminatingSymbol() ) == std::tie ( * other.m_tree, other.getAlphabet(), other.getTerminatingSymbol() );
	}

	explicit operator std::string ( ) const;
};

} /* namespace tree */

namespace core {

template < >
class SetConstraint< indexes::SuffixTrieTerminatingSymbol, DefaultSymbolType, indexes::GeneralAlphabet > {
public:
	static bool used ( const indexes::SuffixTrieTerminatingSymbol & index, const DefaultSymbolType & symbol ) {
		return index.getTerminatingSymbol ( ) == symbol || index.getRoot ( ).testSymbol ( symbol );
	}

	static bool available ( const indexes::SuffixTrieTerminatingSymbol &, const DefaultSymbolType & ) {
		return true;
	}

	static void valid ( const indexes::SuffixTrieTerminatingSymbol &, const DefaultSymbolType & ) {
	}
};

template < >
class ElementConstraint< indexes::SuffixTrieTerminatingSymbol, DefaultSymbolType, indexes::TerminatingSymbol > {
public:
	static bool available ( const indexes::SuffixTrieTerminatingSymbol & index, const DefaultSymbolType & symbol ) {
		return index.getAlphabet ( ).contains ( symbol );
	}

	static void valid ( const indexes::SuffixTrieTerminatingSymbol &, const DefaultSymbolType & ) {
	}
};

template < >
struct xmlApi < indexes::SuffixTrieTerminatingSymbol > {
	static indexes::SuffixTrieTerminatingSymbol parse ( ext::deque < sax::Token >::iterator & input );
	static bool first ( const ext::deque < sax::Token >::const_iterator & input );
	static std::string xmlTagName ( );
	static void compose ( ext::deque < sax::Token > & output, const indexes::SuffixTrieTerminatingSymbol & index );
};

} /* namespace core */

