#include <iostream>
#include <unordered_map>
#include <string>

namespace ComponentTypes
{
	const std::string PlayerComponent = "PlayerComponent";
	const std::string GameObjectComponent = "GameObjectComponent"; 
}

class Component
{
public:
	virtual Component* Clone() const = 0;
	virtual std::string ComponentType() const = 0;
};

class Player : public Component
{
public:
	Component* Clone() const
	{
		return new Player(*this);
	}
	
 	std::string ComponentType() const
	{
		return ComponentTypes::PlayerComponent;
	}
};

class GameObject : public Component
{
public:
	Component* Clone() const
	{
		return new GameObject(*this);
	}
	
	std::string ComponentType() const
	{
		return ComponentTypes::GameObjectComponent;
	}
};

class SomeContainer
{
private:
	std::unordered_map<std::string, Component*> m_components;
	
	bool HasComponent(const std::string& componentType) const
	{
		return m_components.find(componentType) != m_components.end();
	}

public:	
	void AddComponent(Component* theComponent)
	{
		if (!HasComponent(theComponent->ComponentType()))
		{
			m_components.insert(std::make_pair(theComponent->ComponentType(), theComponent));
		}
		else
		{
			std::cout << "I didn't add this " << theComponent->ComponentType();
			std::cout << " as I already have one" << std::endl;
		}
	}
	
	Component* GetComponent(const std::string& componentType) const
	{
		return HasComponent(componentType) ? m_components.at(componentType) 
										   : nullptr;
	}
};

int main() 
{
	auto someContainer = SomeContainer();
	
	someContainer.AddComponent(new Player());
	someContainer.AddComponent(new GameObject());

	auto retrievedPlayer = someContainer.GetComponent(ComponentTypes::PlayerComponent);
	std::cout << "Got component: " << retrievedPlayer->ComponentType() << std::endl;
	
	auto retrievedGameObject = someContainer.GetComponent(ComponentTypes::GameObjectComponent);
	std::cout << "Got component: " << retrievedGameObject->ComponentType() << std::endl;
	return 0;
}