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

#include "SuffixTrieTerminatingSymbol.h"
#include <exception/CommonException.h>

#include <alib/iostream>
#include <alib/algorithm>
#include <sstream>

#include <sax/FromXMLParserHelper.h>
#include "../common/IndexFromXMLParser.h"
#include "../common/IndexToXMLComposer.h"
#include <object/Object.h>

#include <registration/ValuePrinterRegistration.hpp>
#include <registration/XmlRegistration.hpp>

namespace indexes {

SuffixTrieTerminatingSymbol::SuffixTrieTerminatingSymbol ( ext::set < DefaultSymbolType > alphabet, DefaultSymbolType terminatingSymbol ) : SuffixTrieTerminatingSymbol ( std::move ( alphabet ), std::move ( terminatingSymbol ), SuffixTrieNodeTerminatingSymbol ( { } ) ) {
}

SuffixTrieTerminatingSymbol::SuffixTrieTerminatingSymbol ( ext::set < DefaultSymbolType > alphabet, DefaultSymbolType terminatingSymbol, SuffixTrieNodeTerminatingSymbol tree ) : core::Components < SuffixTrieTerminatingSymbol, ext::set < DefaultSymbolType >, component::Set, GeneralAlphabet, DefaultSymbolType, component::Value, TerminatingSymbol > ( std::move ( alphabet ), std::move ( terminatingSymbol ) ), m_tree ( nullptr ) {
	setTree ( std::move ( tree ) );
}

SuffixTrieTerminatingSymbol::SuffixTrieTerminatingSymbol ( DefaultSymbolType terminatingSymbol, SuffixTrieNodeTerminatingSymbol tree ) : SuffixTrieTerminatingSymbol ( tree.computeMinimalAlphabet ( ) + ext::set < DefaultSymbolType > { terminatingSymbol }, terminatingSymbol, tree ) {
}

SuffixTrieTerminatingSymbol::SuffixTrieTerminatingSymbol ( const SuffixTrieTerminatingSymbol & other ) : core::Components < SuffixTrieTerminatingSymbol, ext::set < DefaultSymbolType >, component::Set, GeneralAlphabet, DefaultSymbolType, component::Value, TerminatingSymbol > ( other.getAlphabet ( ), other.getTerminatingSymbol ( ) ), m_tree ( other.m_tree->clone ( ) ) {
	this->m_tree->attachTree ( this );
}

SuffixTrieTerminatingSymbol::SuffixTrieTerminatingSymbol ( SuffixTrieTerminatingSymbol && other ) noexcept : core::Components < SuffixTrieTerminatingSymbol, ext::set < DefaultSymbolType >, component::Set, GeneralAlphabet, DefaultSymbolType, component::Value, TerminatingSymbol > ( std::move ( other.accessComponent < GeneralAlphabet > ( ).get ( ) ), std::move ( other.accessComponent < TerminatingSymbol > ( ).get ( ) ) ), m_tree ( other.m_tree ) {
	this->m_tree->attachTree ( this );
	other.m_tree = nullptr;
}

SuffixTrieTerminatingSymbol & SuffixTrieTerminatingSymbol::operator =( const SuffixTrieTerminatingSymbol & other ) {
	if ( this == & other )
		return * this;

	* this = SuffixTrieTerminatingSymbol ( other );

	return * this;
}

SuffixTrieTerminatingSymbol & SuffixTrieTerminatingSymbol::operator =( SuffixTrieTerminatingSymbol && other ) noexcept {
	std::swap ( this->m_tree, other.m_tree );
	std::swap ( accessComponent < GeneralAlphabet > ( ).get ( ), other.accessComponent < GeneralAlphabet > ( ).get ( ) );
	std::swap ( accessComponent < TerminatingSymbol > ( ).get ( ), other.accessComponent < TerminatingSymbol > ( ).get ( ) );

	return * this;
}

SuffixTrieTerminatingSymbol::~SuffixTrieTerminatingSymbol ( ) noexcept {
	delete m_tree;
}

const SuffixTrieNodeTerminatingSymbol & SuffixTrieTerminatingSymbol::getRoot ( ) const {
	return * m_tree;
}

SuffixTrieNodeTerminatingSymbol & SuffixTrieTerminatingSymbol::getRoot ( ) {
	return * m_tree;
}

void SuffixTrieTerminatingSymbol::setTree ( SuffixTrieNodeTerminatingSymbol tree ) {
	delete this->m_tree;
	this->m_tree = std::move ( tree ).clone ( );

	if ( !this->m_tree->attachTree ( this ) ) {
		delete this->m_tree;
		throw exception::CommonException ( "Input symbols not in the alphabet." );
	}
}

std::ostream & operator << ( std::ostream & out, const SuffixTrieTerminatingSymbol & instance ) {
	return out << "(SuffixTrieTerminatingSymbol " << * ( instance.m_tree ) << ")";
}

SuffixTrieTerminatingSymbol::operator std::string ( ) const {
	std::stringstream ss;
	ss << * this;
	return ss.str ( );
}

} /* namespace indexes */

namespace core {

indexes::SuffixTrieTerminatingSymbol xmlApi < indexes::SuffixTrieTerminatingSymbol >::parse ( ext::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, xmlTagName ( ) );
	ext::set < DefaultSymbolType > rankedAlphabet = indexes::IndexFromXMLParser::parseAlphabet ( input );
	DefaultSymbolType terminatingSymbol = core::xmlApi < DefaultSymbolType >::parse ( input );
	indexes::SuffixTrieNodeTerminatingSymbol * root = indexes::IndexFromXMLParser::parseSuffixTrieNodeTerminatingSymbol ( input );
	indexes::SuffixTrieTerminatingSymbol res ( std::move ( rankedAlphabet ), terminatingSymbol, std::move ( * root ) );

	delete root;
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, xmlTagName ( ) );
	return res;
}

bool xmlApi < indexes::SuffixTrieTerminatingSymbol >::first ( const ext::deque < sax::Token >::const_iterator & input ) {
	return sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, xmlTagName ( ) );
}

std::string xmlApi < indexes::SuffixTrieTerminatingSymbol >::xmlTagName ( ) {
	return "SuffixTrieTerminatingSymbol";
}

void xmlApi < indexes::SuffixTrieTerminatingSymbol >::compose ( ext::deque < sax::Token > & output, const indexes::SuffixTrieTerminatingSymbol & index ) {
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::START_ELEMENT );
	indexes::IndexToXMLComposer::composeAlphabet ( output, index.getAlphabet ( ) );
	core::xmlApi < DefaultSymbolType >::compose ( output, index.getTerminatingSymbol ( ) );
	indexes::IndexToXMLComposer::composeNode ( output, index.getRoot ( ) );
	output.emplace_back ( xmlTagName ( ), sax::Token::TokenType::END_ELEMENT );
}

} /* namespace core */

namespace {

auto valuePrinter = registration::ValuePrinterRegister < indexes::SuffixTrieTerminatingSymbol > ( );

auto xmlWrite = registration::XmlWriterRegister < indexes::SuffixTrieTerminatingSymbol > ( );
auto xmlRead = registration::XmlReaderRegister < indexes::SuffixTrieTerminatingSymbol > ( );

auto xmlGroup = registration::XmlRegisterTypeInGroup < object::Object, indexes::SuffixTrieTerminatingSymbol > ( );

} /* namespace */
