/*
 * StringReaderRegistry.hpp
 *
 *  Created on: 11. 7. 2017
 *	  Author: Jan Travnicek
 */

#ifndef _STRING_READER_REGISTRY_HPP_
#define _STRING_READER_REGISTRY_HPP_

#include <alib/memory>
#include <alib/string>
#include <alib/map>
#include <alib/list>
#include <alib/algorithm>
#include <alib/typeinfo>

#include <abstraction/OperationAbstraction.hpp>

#include <core/stringApi.hpp>

namespace abstraction {

class StringReaderRegistry {
public:
	class Entry {
	public:
		virtual std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const = 0;

		virtual ~Entry ( ) = default;
	};

private:
	template < class Return >
	class EntryImpl : public Entry {
	public:
		EntryImpl ( ) = default;

		std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( ) const override;
	};

	static ext::map < std::string, ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < Entry > > > > & getEntries ( );

public:
	static void unregisterStringReader ( const std::string & group, ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < Entry > > >::const_iterator iter );

	template < class Group >
	static void unregisterStringReader ( ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < Entry > > >::const_iterator iter ) {
		std::string group = ext::to_string < Group > ( );
		unregisterStringReader ( group, iter );
	}

	static ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < Entry > > >::const_iterator registerStringReader ( std::string group, std::function < bool ( std::istream & ) > first, std::unique_ptr < Entry > entry );

	template < class Group, class ReturnType >
	static ext::list < std::pair < std::function < bool ( std::istream & ) >, std::unique_ptr < Entry > > >::const_iterator registerStringReader ( ) {
		return registerStringReader ( ext::to_string < Group > ( ), core::stringApi < ReturnType >::first, std::unique_ptr < Entry > ( new EntryImpl < ReturnType > ( ) ) );
	}

	static std::shared_ptr < abstraction::OperationAbstraction > getAbstraction ( const std::string & group, const std::string & str );
};

} /* namespace abstraction */

#include <abstraction/StringReaderAbstraction.hpp>

namespace abstraction {

template < class Return >
std::shared_ptr < abstraction::OperationAbstraction > StringReaderRegistry::EntryImpl < Return >::getAbstraction ( ) const {
	return std::make_shared < abstraction::StringReaderAbstraction < Return > > ( );
}

} /* namespace abstraction */

#endif /* _STRING_READER_REGISTRY_HPP_ */
