#include <stdlib.h>
#include <string.h>
#include "core.h"
#include "log.h"
#include "ientity.h"
#include "entitymanager.h"
#include "world.h"
#include "camera.h"

// World

World::World()
{
	m_isUpdating = false;
}

World::~World()
{
	DestroyWorld();
}

void World::DestroyWorld()
{
	// Run destroyer
	UpdateDestroyList();

	for (int i = 0; i < m_entities.size(); ++i)
	{
		delete m_entities[i];
		m_entities[i] = 0;
	}

	m_entities.clear();
}

void World::Update(float dt)
{
	// Run destroyer
	UpdateDestroyList();

	m_isUpdating = true;

	// Update entities
	for (int i = 0; i < m_entities.size(); i++)
	{
		m_entities[i]->SetDirty();
		m_entities[i]->Update(dt);
	}

	for (int i = 0; i < m_entities.size(); i++)
	{
		m_entities[i]->UpdateTransform();
	}

	m_isUpdating = false;
}

void World::Render()
{
	Camera* camera = g_cameraManager.GetActiveCamera();
	if (!camera)
		return;

	Frustum& frustum = camera->GetFrustum();

	// Render entities
	for (int i = 0; i < m_entities.size(); i++)
	{
		//if (frustum.CullBoundingBox(m_entities[i]->GetBoundingBox()))
		//	continue;

		m_entities[i]->Render();
	}
}

void World::UpdateDestroyList()
{
	// Update deleting list
	if (!m_entitiesToDelete.empty())
	{
		for (int i = 0; i < m_entitiesToDelete.size(); i++)
		{
			DeleteEntity(FindEntityId(m_entitiesToDelete[i]));
		}

		m_entitiesToDelete.clear();
	}
}

void World::AddEntity(IEntityBase* pEntity)
{
	m_entities.push_back(pEntity);
}

IEntityBase* World::CreateEntity(const char* classname)
{
	IEntityBase* entity = nullptr;

	if (classname != nullptr)
	{
		// Get entity factory.
		entity = g_entityManager->CreateEntity(classname);
	}

	if (entity == nullptr)
	{
		Core::Warning("World::CreateEntity: Can't create entity with unknown %s classname.", classname);
		return nullptr;
	}

	m_entities.push_back(entity);

	//entity->Spawn();

	return entity;
}

void World::DeleteEntity(int index)
{
	if (m_isUpdating)
	{
		Msg("World::DeleteEntity: illegal call in world update!");
		SDL_assert_always(0);
		return;
	}

	if (0 > index || index >= GetNumEntities())
	{
		Msg("World::DeleteEntity: invalid entity index %d", index);
		SDL_assert_always(0);
		return;
	}

	delete m_entities[index];
	m_entities.erase(m_entities.begin() + index);
}

int World::GetNumEntities()
{
	return (int)m_entities.size();
}

IEntityBase* World::GetEntity(int index)
{
	return m_entities[index];
}

int World::FindEntityId(IEntityBase* pEntity)
{
	for (int i = 0; i < GetNumEntities(); i++)
	{
		if (m_entities[i] == pEntity)
			return i;
	}

	return -1;
}

IEntityBase* World::FindEntityByClassName(const char* pClassname)
{
	for (int i = 0; i < GetNumEntities(); i++)
	{
		if (strcmp(m_entities[i]->GetClassname(), pClassname) == 0)
			return m_entities[i];
	}

	return nullptr;
}

void World::MarkEntityToDelete(IEntityBase* pEntity)
{
	m_entitiesToDelete.push_back(pEntity);
}

void World::MarkEntityToDeleteId(int index)
{
	MarkEntityToDelete(GetEntity(index));
}

World* g_world = nullptr;
