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

#pragma once

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

#include <container/ContainerFromStringLexer.h>

namespace core {

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

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

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

	ext::vector<ValueType> objectsVector;
	if(token.type != container::ContainerFromStringLexer::TokenType::VECTOR_END) while(true) {
		container::ContainerFromStringLexer::putback(input, token);
		ValueType innerObject = stringApi < ValueType >::parse ( input );
		objectsVector.push_back ( 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::VECTOR_END)
		throw exception::CommonException("Expected VECTOR_END token.");
	return objectsVector;
}

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

template<class ValueType >
void stringApi < ext::vector < ValueType > >::compose ( std::ostream & output, const ext::vector < 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 */

