/*
 * Variant.h
 *
 * Created on: Apr 1, 2013
 * Author: Jan Travnicek
 */

#ifndef _XML_OBJECTS_VARIANT_H_
#define _XML_OBJECTS_VARIANT_H_

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

namespace core {

template < typename T >
T parseVariantHelper ( ext::deque < sax::Token >::iterator & ) {
	throw exception::CommonException ( "Can't parse variant type" );
}

template < typename T, typename R, typename ... Ts >
T parseVariantHelper ( ext::deque < sax::Token >::iterator & input ) {
	if ( core::xmlApi < R >::first ( input ) ) return T ( core::xmlApi < R >::parse ( input ) );

	return parseVariantHelper < T, Ts ... > ( input );
}

template < typename T, typename R, typename ... Ts >
T firstVariantHelper ( ext::deque < sax::Token >::iterator & input ) {
	if ( core::xmlApi < R >::first ( input ) ) return true;

	return firstVariantHelper < T, Ts ... > ( input );
}

template < typename T >
void composeVariantHelper ( ext::deque < sax::Token > &, const T & ) {
	throw exception::CommonException ( "Can't compose variant type" );
}

template < typename T, typename R, typename ... Ts >
void composeVariantHelper ( ext::deque < sax::Token > & out, const T & container ) {
	if ( container.template is < R > ( ) )
		return core::xmlApi < R >::compose ( out, container.template get < R > ( ) );

	composeVariantHelper < T, Ts ... > ( out, container );
}

template < typename ... Ts >
struct xmlApi < ext::variant < Ts ... > > {
	static ext::variant < Ts ... > 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 ext::variant < Ts ... > & input );
};

template < typename ... Ts >
ext::variant < Ts ... > xmlApi < ext::variant < Ts ... > >::parse ( ext::deque < sax::Token >::iterator & input ) {
	return parseVariantHelper < ext::variant < Ts ... >, Ts ... > ( input );
}

template < typename ... Ts >
bool xmlApi < ext::variant < Ts ... > >::first ( const ext::deque < sax::Token >::const_iterator & ) {
	return false;
}

template < typename ... Ts >
std::string xmlApi < ext::variant < Ts ... > >::xmlTagName ( ) {
	throw exception::CommonException ( "Variant does not have xmlTagName." );
}

template < typename ... Ts >
void xmlApi < ext::variant < Ts ... > >::compose ( ext::deque < sax::Token > & output, const ext::variant < Ts ... > & input ) {
	composeVariantHelper < ext::variant < Ts ... >, Ts ... > ( output, input );
}

} /* namespace core */

#endif /* _XML_OBJECTS_VARIANT_H_ */
