/*
 * XmlContainerParserRegistry.cpp
 *
 *  Created on: 19. 8. 2017
 *	  Author: Jan Travnicek
 */

#include <registry/XmlContainerParserRegistry.hpp>

#include <alib/foreach>

#include <exception/CommonException.h>

namespace abstraction {

ext::map < std::string, ext::list < ext::pair < std::string, std::unique_ptr < XmlContainerParserRegistry::Entry > > > > & XmlContainerParserRegistry::getEntries ( ) {
	static ext::map < std::string, ext::list < ext::pair < std::string, std::unique_ptr < Entry > > > > containerGroups;
	return containerGroups;
}

void XmlContainerParserRegistry::unregisterSet ( const std::string & param ) {
	std::string container = "Set";

	auto & group = getEntries ( ) [ container ];
	auto iter = find_if ( group.begin ( ), group.end ( ), [ & ] ( const ext::pair < std::string, std::unique_ptr < Entry > > & entry ) {
			return entry.first == param;
			} );
	if ( iter == group.end ( ) )
		throw exception::CommonException ( "Callback for " + param + " in container " + container + " not registered." );

	group.erase ( iter );
}

void XmlContainerParserRegistry::registerSet ( std::string param, std::unique_ptr < Entry > entry ) {
	std::string container = "Set";

	auto & group = getEntries ( ) [ container ];
	auto iter = find_if ( group.begin ( ), group.end ( ), [ & ] ( const ext::pair < std::string, std::unique_ptr < Entry > > & item ) {
			return item.first == param;
			} );
	if ( iter != group.end ( ) )
		throw exception::CommonException ( "Callback for " + param + " in container " + container + " already registered." );

	group.insert ( group.end ( ), ext::make_pair ( std::move ( param ), std::move ( entry ) ) );
}

bool XmlContainerParserRegistry::hasAbstraction ( const std::string & container ) {
	return getEntries ( ).contains ( container );
}

std::shared_ptr < abstraction::OperationAbstraction > XmlContainerParserRegistry::getAbstraction ( const std::string & container, const std::string & type ) {
	auto group = getEntries ( ).find ( container );
	if ( group == getEntries ( ).end ( ) )
		throw exception::CommonException ( "Entry " + container + " not available" );

	auto iter = std::find_if ( group->second.begin ( ), group->second.end ( ), [ & ] ( const ext::pair < std::string, std::unique_ptr < Entry > > & entry ) {
		return ext::is_same_type ( type, ext::erase_template_info ( entry.first ) );
	} );

	if ( iter == group->second.end ( ) )
		throw exception::CommonException ( "Entry for " + container + " parametrized with " + type + " not available." );

	return iter->second->getAbstraction ( );
}

ext::set < std::string > XmlContainerParserRegistry::listOverloads ( const std::string & container ) {
	auto group = getEntries ( ).find ( container );
	if ( group == getEntries ( ).end ( ) )
		throw exception::CommonException ( "Entry " + container + " not available" );

	ext::set < std::string > res;
	for ( const ext::pair < std::string, std::unique_ptr < Entry > > & entry : group->second )
		res.insert ( entry.first );

	return res;
}

ext::set < std::string > XmlContainerParserRegistry::list ( ) {
	ext::set < std::string > res;

	for ( const std::pair < const std::string, ext::list < ext::pair < std::string, std::unique_ptr < Entry > > > > & groups : getEntries ( ) )
		res.insert ( groups.first );

	return res;
}

} /* namespace abstraction */
