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

#pragma once

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

#include <container/ContainerFromStringLexer.h>

namespace core {

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

template<class FirstType, class SecondType >
std::pair < FirstType, SecondType > stringApi < std::pair < FirstType, SecondType > >::parse ( std::istream & input ) {
	container::ContainerFromStringLexer::Token token = container::ContainerFromStringLexer::next ( input );
	if(token.type != container::ContainerFromStringLexer::TokenType::PAIR_BEGIN)
		throw exception::CommonException("Expected PAIR_BEGIN token.");

	FirstType firstObject = stringApi < FirstType >::parse ( input );

	token = container::ContainerFromStringLexer::next(input);
	if(token.type != container::ContainerFromStringLexer::TokenType::COMMA)
		throw exception::CommonException("Excepted COMMA token.");

	SecondType secondObject = stringApi < SecondType >::parse ( input );

	token = container::ContainerFromStringLexer::next(input);
	if(token.type != container::ContainerFromStringLexer::TokenType::PAIR_END)
		throw exception::CommonException("Expected PAIR_END token.");

	return std::make_pair ( std::move ( firstObject ), std::move ( secondObject ) );
}

template<class FirstType, class SecondType >
bool stringApi < std::pair < FirstType, SecondType > >::first ( std::istream & input ) {
	container::ContainerFromStringLexer::Token token = container::ContainerFromStringLexer::next ( input );
	bool res = token.type == container::ContainerFromStringLexer::TokenType::PAIR_BEGIN;
	container::ContainerFromStringLexer::putback ( input, token );
	return res;
}

template<class FirstType, class SecondType >
void stringApi < std::pair < FirstType, SecondType > >::compose ( std::ostream & output, const std::pair < FirstType, SecondType > & container ) {
	output << "(";

	stringApi < FirstType >::compose ( output, container.first );

	output << ", ";

	stringApi < SecondType >::compose ( output, container.second );

	output << ")";
}

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

template<class FirstType, class SecondType >
ext::pair < FirstType, SecondType > stringApi < ext::pair < FirstType, SecondType > >::parse ( std::istream & input ) {
	std::pair < FirstType, SecondType > tmp = stringApi < std::pair < FirstType, SecondType > >::parse ( input );
	return ext::make_pair ( tmp.first, tmp.second );
}

template<class FirstType, class SecondType >
bool stringApi < ext::pair < FirstType, SecondType > >::first ( std::istream & input ) {
	return stringApi < std::pair < FirstType, SecondType > >::first ( input );
}

template<class FirstType, class SecondType >
void stringApi < ext::pair < FirstType, SecondType > >::compose ( std::ostream & output, const ext::pair < FirstType, SecondType > & container ) {
	stringApi < std::pair < FirstType, SecondType > >::compose ( output, container );
}

} /* namespace core */

