/*
 * Tuple.h
 *
 * Created on: May 6, 2016
 * Author: Jan Travnicek
 */

#ifndef OBJECTS_TUPLE_H_
#define OBJECTS_TUPLE_H_

#include <tuple>
#include <string>

#include <core/xmlApi.hpp>
#include <exception/CommonException.h>

namespace container {

/**
 * Basic container from which are derived all other containers.
 * Contains reason why the container occurred.
 */
class ObjectsTuple {
private:
	explicit ObjectsTuple ( );

public:
	static const std::string & getXmlTagName() {
		static std::string xmlTagName = "Tuple";

		return xmlTagName;
	}

	template < class ... Ts >
	static std::tuple < Ts ... > parseRaw ( std::deque < sax::Token >::iterator & input );

	template < class ... Ts >
	static void compose ( std::deque < sax::Token > & out, const std::tuple < Ts ... > & input );
};

template < typename ... Ts >
std::tuple < Ts ... > ObjectsTuple::parseRaw ( std::deque < sax::Token >::iterator & input ) {
	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::START_ELEMENT, ObjectsTuple::getXmlTagName() );

	return std::tuple < Ts ... > { alib::xmlApi < Ts >::parse ( input ) ... }; // NOTE buggy in gcc < 4.9.1

	sax::FromXMLParserHelper::popToken ( input, sax::Token::TokenType::END_ELEMENT, ObjectsTuple::getXmlTagName() );
}

template < class ... Ts, size_t ... I >
void tupleComposeHelper ( std::deque < sax::Token > & out, const std::tuple < Ts ... > & container, std::index_sequence < I ... > ) {
	( void ) std::initializer_list < int > { ( alib::xmlApi < Ts >::compose ( out, std::get < I > ( container ) ), 0 ) ... }; // FEATURE unpack of multiple packs together
}

template < typename ... Ts >
void ObjectsTuple::compose ( std::deque < sax::Token > & out, const std::tuple < Ts ... > & container ) {
	out.emplace_back ( ObjectsTuple::getXmlTagName(), sax::Token::TokenType::START_ELEMENT );

	tupleComposeHelper ( out, container, std::make_index_sequence < std::tuple_size < std::tuple < Ts ... > >::value > { } );

	out.emplace_back ( ObjectsTuple::getXmlTagName(), sax::Token::TokenType::END_ELEMENT );
}

} /* namespace container */

namespace alib {

template < typename ... Ts >
struct xmlApi < std::tuple < Ts ... > > {
	static std::tuple < Ts ... > parse ( std::deque < sax::Token >::iterator & input );
	static bool first ( const std::deque < sax::Token >::const_iterator & input );
	static void compose ( std::deque < sax::Token > & output, const std::tuple < Ts ... > & data );
};

template < typename ... Ts >
std::tuple < Ts ... > xmlApi < std::tuple < Ts ... > >::parse ( std::deque < sax::Token >::iterator & input ) {
	return container::ObjectsTuple::parseRaw < Ts ... > ( input );
}

template < typename ... Ts >
bool xmlApi < std::tuple < Ts ... > >::first ( const std::deque < sax::Token >::const_iterator & input ) {
	return sax::FromXMLParserHelper::isToken ( input, sax::Token::TokenType::START_ELEMENT, container::ObjectsTuple::getXmlTagName() );
}

template < typename ... Ts >
void xmlApi < std::tuple < Ts ... > >::compose ( std::deque < sax::Token > & output, const std::tuple < Ts ... > & input ) {
	return container::ObjectsTuple::compose < Ts ... > ( output, input );
}

} /* namespace alib */

#endif /* OBJECTS_TUPLE_H_ */