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

#ifndef LINEAR_STRING_TERMINATING_SYMBOL_H_
#define LINEAR_STRING_TERMINATING_SYMBOL_H_

#include <alib/iostream>
#include <alib/set>
#include <alib/vector>
#include <alib/deque>
#include <alib/compare>

#include <core/components.hpp>

#include <sax/Token.h>
#include <core/xmlApi.hpp>

#include <string/LinearString.h>

namespace string {

class GeneralAlphabet;
class TerminatingSymbol;

/**
 * Represents regular expression parsed from the XML. Regular expression is stored
 * as a tree of LinearStringElement.
 */
class LinearStringTerminatingSymbol final : public ext::CompareOperators < LinearStringTerminatingSymbol >, public core::Components < LinearStringTerminatingSymbol, ext::set < DefaultSymbolType >, component::Set, GeneralAlphabet, DefaultSymbolType, component::Value, TerminatingSymbol > {
	ext::vector < DefaultSymbolType > m_Data;

public:
	explicit LinearStringTerminatingSymbol ( DefaultSymbolType terminatingSymbol );
	explicit LinearStringTerminatingSymbol ( ext::set < DefaultSymbolType > alphabet, DefaultSymbolType terminatingSymbol, ext::vector < DefaultSymbolType > data );
	explicit LinearStringTerminatingSymbol ( DefaultSymbolType terminatingSymbol, ext::vector < DefaultSymbolType > data );
	explicit LinearStringTerminatingSymbol ( DefaultSymbolType terminatingSymbol, const LinearString < > & str );

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

	void extendAlphabet ( const ext::set < DefaultSymbolType > & symbols ) {
		accessComponent < GeneralAlphabet > ( ).add( symbols );
	}

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

	/**
	 * @param element to append
	 */
	void appendSymbol ( DefaultSymbolType symbol );

	/**
	 * @return List of symbols forming string (const version).
	 */
	const ext::vector < DefaultSymbolType > & getContent ( ) const;

	void setContent ( ext::vector < DefaultSymbolType > data );

	/**
	 * @return true if string is an empty word (vector length is 0)
	 */
	bool isEmpty ( ) const;

	int compare ( const LinearStringTerminatingSymbol & other ) const;

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

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

} /* namespace string */

namespace core {

template < >
struct xmlApi < string::LinearStringTerminatingSymbol > {
	static string::LinearStringTerminatingSymbol 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 string::LinearStringTerminatingSymbol & data );
};

template < >
class SetConstraint< string::LinearStringTerminatingSymbol, DefaultSymbolType, string::GeneralAlphabet > {
public:
	static bool used ( const string::LinearStringTerminatingSymbol & str, const DefaultSymbolType & symbol ) {
		const ext::vector<DefaultSymbolType>& content = str.getContent ( );
		return std::find(content.begin(), content.end(), symbol) != content.end();
	}

	static bool available ( const string::LinearStringTerminatingSymbol &, const DefaultSymbolType & ) {
		return true;
	}

	static void valid ( const string::LinearStringTerminatingSymbol &, const DefaultSymbolType & ) {
	}
};

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

	static void valid ( const string::LinearStringTerminatingSymbol &, const DefaultSymbolType & ) {
	}
};

} /* namespace core */

#endif /* LINEAR_STRING_TERMINATING_SYMBOL_H_ */
