// Win32Project4.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
//

#include "stdafx.h"
#include <Windows.h>
#include <vector>
#include <iostream>
#include <unordered_map>


#define __SEARCH_TYPE__ 1


enum EnumComponentType
{
	ComponentTypeNone,
	ComponentTypeStats,
	ComponentTypeWeapon,
	ComponentTypeArmor,
	ComponentTypeContainer,
	ComponentTypeDoor
};


class ClassComponent
{
public:
	ClassComponent(EnumComponentType ComponentType)
	{
		m_ComponentType = ComponentType;
	}

	EnumComponentType GetComponentType(void) const
	{
		return m_ComponentType;
	}

	virtual int Toast(void) = 0;
	virtual void IncValue(void) = 0;
	virtual void DecValue(void) = 0;

private:
	EnumComponentType m_ComponentType;
	int m_Value;
};


template <EnumComponentType ComponentType> class TemplateComponent :
	public ClassComponent
{
public:
	TemplateComponent(void) : ClassComponent(ComponentType)
	{
		m_Value = 0;
	}

	static EnumComponentType GetComponentType(void)
	{
		return ComponentType;
	}

	int Toast(void)
	{
		return ComponentType;
	}

	void IncValue(void)
	{
		++m_Value;
	}

	void DecValue(void)
	{
		++m_Value;
	}

private:
	int m_Value;
};


class ClassComponentStats : public TemplateComponent<ComponentTypeStats> {};
class ClassComponentWeapon : public TemplateComponent<ComponentTypeWeapon> {};
class ClassComponentArmor : public TemplateComponent<ComponentTypeArmor> {};
class ClassComponentContainer : public TemplateComponent<ComponentTypeContainer> {};
class ClassComponentDoor : public TemplateComponent<ComponentTypeDoor> {};


class ClassComponentArray;


class ClassComponentArrayCaster
{
public:
	template <class T> operator T*(void)
	{
		return m_pArray->FindComponent<T>();
	}

	friend class ClassComponentArray;
private:
	ClassComponentArrayCaster(ClassComponentArray* pArray)
	{
		m_pArray = pArray;
	}

	ClassComponentArray* m_pArray;
};


class ClassComponentArray
{
public:
	ClassComponentArray(void)
	{
		m_ppComponentArray[0] = &m_Stats;
		m_ppComponentArray[1] = &m_Armor;
		m_ppComponentArray[2] = &m_Weapon;
		m_ppComponentArray[3] = &m_Container;
		m_ppComponentArray[4] = &m_Door;

		m_Vector.assign(5, nullptr);

		for (int i = 0; i < 5; ++i)
		{
			m_Vector[i] = m_ppComponentArray[i];

			m_HashMap[m_ppComponentArray[i]->GetComponentType()] = m_ppComponentArray[i];
		}
	}

	~ClassComponentArray(void)
	{
	}

	template <class T> operator T* (void)
	{
		return FindComponent<T>();
	}

	ClassComponentArrayCaster FindComponent(void)
	{
		return ClassComponentArrayCaster(this);
	}

	void TestInc(void)
	{
		ClassComponentStats* pStats = FindComponent();
		ClassComponentArmor* pArmor = FindComponent();
		ClassComponentWeapon* pWeapon = FindComponent();
		ClassComponentContainer* pContainer = FindComponent();
		ClassComponentDoor* pDoor = FindComponent();

		pStats->IncValue();
		pArmor->IncValue();
		pWeapon->IncValue();
		pContainer->IncValue();
		pDoor->IncValue();
	}

	void TestDec(void)
	{
		ClassComponentStats* pStats = FindComponent();
		ClassComponentArmor* pArmor = FindComponent();
		ClassComponentWeapon* pWeapon = FindComponent();
		ClassComponentContainer* pContainer = FindComponent();
		ClassComponentDoor* pDoor = FindComponent();

		pStats->DecValue();
		pArmor->DecValue();
		pWeapon->DecValue();
		pContainer->DecValue();
		pDoor->DecValue();
	}

	friend class ClassComponentArrayCaster;
private:
	template <class ComponentClassType> ComponentClassType* FindComponent(void)
	{
#if __SEARCH_TYPE__ == 1

		return FindComponent<ComponentClassType>(ComponentClassType::GetComponentType());

#elif __SEARCH_TYPE__ == 2

		for (auto pComponent : m_Vector)
		{
			auto pCheck = dynamic_cast<ComponentClassType*>(pComponent);
			if (pCheck)
			{
				return pCheck;
			}
		}

		return nullptr;

#elif __SEARCH_TYPE__ == 3

		ClassComponent* pComponent = m_HashMap.find(ComponentClassType::GetComponentType())->second;
		return static_cast<ComponentClassType*>(pComponent);

#endif
	}

	template <class ComponentClassType> ComponentClassType* FindComponent(EnumComponentType ComponentType)
	{
		return static_cast<ComponentClassType*>(FindComponent(ComponentType));
	}

	ClassComponent* FindComponent(EnumComponentType ComponentType)
	{
		for (int i = 0; i < 5; ++i)
		{
			if (m_ppComponentArray[i]->GetComponentType() == ComponentType)
			{
				return m_ppComponentArray[i];
			}
		}

		return nullptr;
	}

	ClassComponent* m_ppComponentArray[5];
	std::vector<ClassComponent*> m_Vector;
	std::unordered_map<EnumComponentType, ClassComponent*> m_HashMap;

	ClassComponentStats m_Stats;
	ClassComponentArmor m_Armor;
	ClassComponentWeapon m_Weapon;
	ClassComponentContainer m_Container;
	ClassComponentDoor m_Door;
};


int main()
{
	ClassComponentArray CA;

	LARGE_INTEGER PC1;
	QueryPerformanceCounter(&PC1);

	DWORD TC1 = GetTickCount();

	for (int i = 0; i < 10000000; ++i)
	{
		CA.TestInc();
	}

	for (int i = 0; i < 10000000; ++i)
	{
		CA.TestDec();
	}

	LARGE_INTEGER PC2;
	QueryPerformanceCounter(&PC2);

	DWORD TC2 = GetTickCount();

	LARGE_INTEGER D;
	D.QuadPart = PC2.QuadPart - PC1.QuadPart;

	std::cout << D.QuadPart << std::endl;
	std::cout << TC2 - TC1 << std::endl;

	int i;
	std::cin >> i;
}

