/*
 * RankedTree.cpp
 *
 *  Created on: Nov 23, 2013
 *      Author: Stepan Plachy
 */

#include "RankedTree.h"

#include <iostream>
#include <algorithm>
#include <sstream>

#include "../unranked/UnrankedTree.h"

#include <sax/FromXMLParserHelper.h>
#include "../common/TreeFromXMLParser.h"
#include "../common/TreeToXMLComposer.h"
#include "../Tree.h"
#include "../RankedTreeWrapper.h"
#include <object/Object.h>
#include <XmlApi.hpp>
#include <cast/CastApi.hpp>

namespace tree {

RankedTree::RankedTree ( std::set < alphabet::RankedSymbol > alphabet, RankedNode tree ) : std::Components < RankedTree, alphabet::RankedSymbol, std::tuple < GeneralAlphabet >, std::tuple < > > ( std::make_tuple ( std::move ( alphabet ) ), std::tuple < > ( ) ), tree ( nullptr ) {
	setTree ( std::move ( tree ) );
}

RankedTree::RankedTree ( RankedNode tree ) : RankedTree ( tree.computeMinimalAlphabet ( ), tree ) {
}

RankedTree::RankedTree ( const UnrankedTree & other ) : RankedTree ( other.getRoot ( ).asRanked ( ) ) {
}

RankedTree::RankedTree ( const RankedTree & other ) : std::Components < RankedTree, alphabet::RankedSymbol, std::tuple < GeneralAlphabet >, std::tuple < > > ( std::make_tuple ( other.getAlphabet ( ) ), std::tuple < > ( ) ), tree ( other.tree ) {
	this->tree->attachAlphabet ( & ( this->getAlphabet ( ) ) );
}

RankedTree::RankedTree ( RankedTree && other ) noexcept : std::Components < RankedTree, alphabet::RankedSymbol, std::tuple < GeneralAlphabet >, std::tuple < > > ( std::make_tuple ( std::move ( other.accessComponent < GeneralAlphabet > ( ).get ( ) ) ), std::tuple < > ( ) ), tree ( std::move ( other.tree ) ) {
	this->tree->attachAlphabet ( & ( this->getAlphabet ( ) ) );
}

RankedTreeBase * RankedTree::clone ( ) const {
	return new RankedTree ( * this );
}

RankedTreeBase * RankedTree::plunder ( ) && {
	return new RankedTree ( std::move ( * this ) );
}

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

	* this = RankedTree ( other );

	return * this;
}

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

	return * this;
}

RankedTree::~RankedTree ( ) noexcept {
}

const RankedNode & RankedTree::getRoot ( ) const {
	return * tree;
}

RankedNode & RankedTree::getRoot ( ) {
	return * tree;
}

void RankedTree::setTree ( RankedNode tree ) {
	this->tree = std::make_smart < RankedNode > ( std::move ( tree ) );

	if ( !this->tree->attachAlphabet ( & ( this->getAlphabet ( ) ) ) )
		throw TreeException ( "Input symbols not in the alphabet." );
}

void RankedTree::operator >>( std::ostream & out ) const {
	out << "(RankedTree " << * ( this->tree ) << ")";
}

int RankedTree::compare ( const RankedTree & other ) const {
	auto first = std::tie ( * tree, getAlphabet() );
	auto second = std::tie ( * other.tree, other.getAlphabet() );

	std::compare < decltype ( first ) > comp;

	return comp ( first, second );
}

void RankedTree::nicePrint ( std::ostream & os ) const {
	tree->nicePrint ( os );
}

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

RankedTree RankedTree::parse ( std::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, RankedTree::getXmlTagName() );
	std::set < alphabet::RankedSymbol > rankedAlphabet = TreeFromXMLParser::parseRankedAlphabet ( input );
	RankedNode root = alib::xmlApi < RankedNode >::parse ( input );
	RankedTree tree ( std::move ( rankedAlphabet ), std::move ( root ) );

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, RankedTree::getXmlTagName() );
	return tree;
}

void RankedTree::compose ( std::deque < sax::Token > & out ) const {
	out.emplace_back ( RankedTree::getXmlTagName(), sax::Token::TokenType::START_ELEMENT );
	TreeToXMLComposer::composeAlphabet ( out, getAlphabet ( ) );
	alib::xmlApi < RankedNode >::compose ( out, * tree );
	out.emplace_back ( RankedTree::getXmlTagName(), sax::Token::TokenType::END_ELEMENT );
}

} /* namespace tree */

namespace alib {

auto rankedTreeParserRegister = xmlApi < tree::Tree >::ParserRegister < tree::RankedTree > ();
auto rankedTreeParserRegister2 = xmlApi < tree::RankedTreeWrapper >::ParserRegister < tree::RankedTree > ();
auto rankedTreeParserRegister3 = xmlApi < alib::Object >::ParserRegister < tree::RankedTree > ();

auto RankedTreeFromUnrankedTree = castApi::CastRegister < tree::RankedTree, tree::UnrankedTree > ( );
auto RankedTreeCastBinder = castApi::CastPoolStringBinder < tree::RankedTree > ( tree::RankedTree::getXmlTagName() );

} /* namespace alib */