/*
 * ObjectsVariant.h
 *
 * Created on: Sep 27, 2017
 * Author: Jan Travnicek
 */

#ifndef _STRING_OBJECTS_VARIANT_H_
#define _STRING_OBJECTS_VARIANT_H_

#include <alib/variant>
#include <core/stringApi.hpp>

namespace core {

template < class ... Types >
struct stringApi < ext::variant < Types ... > > {
	static ext::variant < Types ... > parse ( std::istream & input );
	static bool first ( std::istream & input );
	static void compose ( std::ostream & output, const ext::variant < Types ... > & container );

private:
	class VariantStringApiCallback {
		std::ostream & m_out;

	public:
		VariantStringApiCallback ( std::ostream & out ) : m_out ( out ) {
		}

		template < class ValueType >
		void operator ( ) ( const ValueType & value ) {
			stringApi < ValueType >::compose ( m_out, value );
		}
	};

	template < class T, class R, class ... Ts >
	static ext::variant < Types ... > parse ( std::istream & input ) {
		if ( stringApi < T >::first ( input ) )
			return ext::variant < Types ... > ( stringApi < T >::parse ( input ) );
		else
			return parse < R, Ts ... > ( input );
	}

	template < class T >
	static ext::variant < Types ... > parse ( std::istream & input ) {
		return ext::variant < Types ... > ( stringApi < T >::parse ( input ) );
	}
};

template < class ... Types >
ext::variant < Types ... > stringApi < ext::variant < Types ... > >::parse ( std::istream & input ) {
	return parse < Types ... > ( input );
}

template < class ... Types >
bool stringApi < ext::variant < Types ... > >::first ( std::istream & input ) {
	return ( ... && stringApi < Types >::first ( input ) );
}

template < class ... Types >
void stringApi < ext::variant < Types ... > >::compose ( std::ostream & output, const ext::variant < Types ... > & container ) {
	ext::visit ( VariantStringApiCallback ( output ), container );
}

} /* namespace core */

#endif /* _STRING_OBJECTS_VARIANT_H_ */
