#pragma once

#include <registry/StringWriterRegistry.hpp>
#include <registry/StringReaderRegistry.hpp>

#include <registry/AlgorithmRegistry.hpp>

namespace string {

template < class Group >
class Parse {
public:
	static std::shared_ptr < abstraction::OperationAbstraction > abstractionFromString ( std::string && data ) {
		return abstraction::StringReaderRegistry::getAbstraction ( ext::to_string < Group > ( ), data );
	}

};

class Compose {
public:
	template < class Type >
	static std::shared_ptr < abstraction::OperationAbstraction > abstractionFromType ( const Type & ) {
		return abstraction::StringWriterRegistry::getAbstraction ( ext::to_string < Type > ( ) );
	}

};

} /* namespace string */

namespace registration {

template < class Group, class Type >
class StringReaderRegister {
	ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < abstraction::StringReaderRegistry::Entry > > >::const_iterator iter;

public:
	StringReaderRegister ( ) {
		iter = abstraction::StringReaderRegistry::registerStringReader < Group, Type > ( );
	}

	~StringReaderRegister ( ) {
		abstraction::StringReaderRegistry::unregisterStringReader < Group > ( iter );
	}
};

template < class Group >
class StringReaderGroupRegister {
public:
	StringReaderGroupRegister ( ) {
		abstraction::AlgorithmRegistry::registerWrapper < string::Parse < Group >, abstraction::UnspecifiedType, std::string && > ( string::Parse < Group >::abstractionFromString, std::array < std::string, 1 > { { "arg0" } } );
		abstraction::AlgorithmRegistry::setDocumentationOfWrapper < string::Parse < Group >, std::string && > (
"String parsing of datatype in " + ext::to_string < Group > ( ) + " category.\n\
\n\
@param arg0 the parsed string\n\
@return value parsed from @p arg0" );
	}

	~StringReaderGroupRegister ( ) {
		abstraction::AlgorithmRegistry::unregisterWrapper < string::Parse < Group >, std::string && > ( );
	}
};

template < class Type >
class StringWriterRegister {
public:
	StringWriterRegister ( ) {
		abstraction::StringWriterRegistry::registerStringWriter < Type > ( );
		abstraction::AlgorithmRegistry::registerWrapper < string::Compose, std::string, const Type & > ( string::Compose::abstractionFromType, std::array < std::string, 1 > { { "arg0" } } );
		abstraction::AlgorithmRegistry::setDocumentationOfWrapper < string::Compose, const Type & > (
"String composing algorithm.\n\
\n\
@param arg0 the composed value\n\
@return the @p arg0 in string representation" );
	}

	~StringWriterRegister ( ) {
		abstraction::StringWriterRegistry::unregisterStringWriter < Type > ( );
		abstraction::AlgorithmRegistry::unregisterWrapper < string::Compose, const Type & > ( );
	}
};

template < class Group, class Type >
class StringReaderRegisterTypeInGroup {
	typename ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < typename core::stringApi < Group >::GroupReader > > >::const_iterator iter;

public:
	StringReaderRegisterTypeInGroup ( ) {
		iter = core::stringApi < Group >::template registerStringReader < Type > ( );
	}

	~StringReaderRegisterTypeInGroup ( ) {
		core::stringApi < Group >::unregisterStringReader ( iter );
	}
};

template < class Group, class Type >
class StringWriterRegisterTypeInGroup {
public:
	StringWriterRegisterTypeInGroup ( ) {
		core::stringApi < Group >::template registerStringWriter < Type > ( );
	}

	~StringWriterRegisterTypeInGroup ( ) {
		core::stringApi < Group >::template unregisterStringWriter < Type > ( );
	}
};

} /* namespace registration */

