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

#ifndef _STRING_OBJECTS_SET_H_
#define _STRING_OBJECTS_SET_H_

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

#include <container/ContainerFromStringLexer.h>

namespace core {

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

template<class ValueType >
ext::set < ValueType > stringApi < ext::set < ValueType > >::parse ( std::istream & input ) {
	container::ContainerFromStringLexer::Token token = container::ContainerFromStringLexer::next ( input );
	if(token.type != container::ContainerFromStringLexer::TokenType::SET_BEGIN)
		throw exception::CommonException("Expected SET_BEGIN token.");

	token = container::ContainerFromStringLexer::next ( input );

	ext::set<ValueType> objectsSet;
	if(token.type != container::ContainerFromStringLexer::TokenType::SET_END) while(true) {
		container::ContainerFromStringLexer::putback(input, token);
		ValueType innerObject = stringApi < ValueType >::parse ( input );
		objectsSet.insert ( std::move ( innerObject ) );

		token = container::ContainerFromStringLexer::next(input);
		if(token.type != container::ContainerFromStringLexer::TokenType::COMMA)
			break;

		token = container::ContainerFromStringLexer::next(input);
	}

	if(token.type != container::ContainerFromStringLexer::TokenType::SET_END)
		throw exception::CommonException("Expected SET_END token.");
	return objectsSet;
}

template<class ValueType >
bool stringApi < ext::set < ValueType > >::first ( std::istream & input ) {
	container::ContainerFromStringLexer::Token token = container::ContainerFromStringLexer::next ( input );
	bool res = token.type == container::ContainerFromStringLexer::TokenType::SET_BEGIN;
	container::ContainerFromStringLexer::putback ( input, token );
	return res;
}

template<class ValueType >
void stringApi < ext::set < ValueType > >::compose ( std::ostream & output, const ext::set < ValueType > & container ) {
	output << '{';
	bool first = true;
	for(const ValueType & innerObject : container) {
		if(!first)
			output << ", ";
		else
			first = false;
		stringApi < ValueType >::compose ( output, innerObject );
	}
	output << '}';
}

} /* namespace core */

#endif /* _STRING_OBJECTS_SET_H_ */
