// ObjectManager.cpp
// Verwaltung von ObjectManager

#include <iostream>
#include <sstream>

#include "objectmanager.h"
#include "debuglogger.h"
#include "game.h"

extern Stats stats;

ObjectManager::ObjectManager() {
	m_objCount = 0;
	m_asteroidsCount = 0;
	m_saucerCount = 0;
	m_shotsCount = 0;

	m_updateCounter = 0;

	m_objects = new vector<GameObject*>();
}

ObjectManager::~ObjectManager() {
	delete m_objects;
}

void ObjectManager::Add(GameObject* o) {
	m_objects->push_back(o);
}

vector<GameObject*>* ObjectManager::GetObjects() {
	return m_objects;
}

void ObjectManager::ResetFlags() {
	vector<GameObject*>::iterator it = m_objects->begin();
	for (; it != m_objects->end(); it++) {
		(*it)->flagUpdate = 0;
	}
}

void ObjectManager::AutoUpdate(int frames) {
	vector<GameObject*>::iterator itOld = m_objects->begin();

	for (; itOld != m_objects->end(); itOld++) {
		(*itOld)->AutoIntegrationScheme(frames);
	}	
}

void ObjectManager::Update(ObjectManager* gameObj) {
	int loop_runs = 0;
	int obj_found_count = 0;
	int	obj_new_count = 0;
	int obj_gone_count = 0;
	int delta_dist2 = 112; // Achtung: Quadrat des Abstandes!
	bool found_something;
	Vector2 dist;

	m_updateCounter++;

	this->ResetFlags();
	gameObj->ResetFlags();
	
	GameObject *newObj, *oldObj;
	vector<GameObject*>* objectsNew = gameObj->GetObjects();
	vector<GameObject*>* objectsOld = this->m_objects;
		
	// Neue Liste durchlaufen...
	for (int i = 0; i < objectsNew->size(); i++)
	{
		newObj = objectsNew->at(i);
		found_something = false;
		
		// Alte Liste durchlaufen mit variabler Genauigkeit 
		// d_dist = 4, 8,... < 112
		for (int d_dist2 = 2; d_dist2 < 400; d_dist2 *= 2)
		{ 
			for (int j = 0; j < objectsOld->size(); j++)
			{
				loop_runs++;
				oldObj = objectsOld->at(j);
				
				dist = newObj->pos - (oldObj->pos + oldObj->vel);
				ModuloScreen(&dist);
	
				if (dist.length2() < d_dist2 && // Position
					newObj->radius == oldObj->radius && // Größe
					!oldObj->flagUpdate) 				// Noch nicht verwendet
				{
					obj_found_count++;
					
					// Neueste Orts-Info wird aufs alte Objekt übertragen, 
					// danach wird das alte Objekt kopiert
					oldObj->PositionalUpdate(newObj);
					oldObj->flagUpdate = true;
					found_something = true;
					
					*newObj = *oldObj; 
									
					break;
				}		
				
				
			} // for oldObjects
			
			if (found_something) break;
		}
		
		
		if (newObj->objecttype == TYPE_ASTEROID)
		{
			switch (newObj->sf) 
			{
				case 0:
					stats.IncSmallAsteroids();
					break;
				case 15:
					stats.IncMediumAsteroids();
					break;
				default:
					stats.IncLargeAsteroids();
					break;						
			
			}
		}
	
	} // for newObjects
	
	for (int i = 0; i < objectsNew->size(); i++)
		if (!(objectsNew->at(i)->flagUpdate))
			objectsNew->at(i)->pos = objectsNew->at(i)->temp;
			
	m_objects->swap(*objectsNew);
	gameObj->ClearDelete();
		
}



// Liste leeren und enthaltene Objekte löschen 
void ObjectManager::ClearDelete() {
	vector<GameObject*>::iterator itOld = m_objects->begin();
	for (; itOld != m_objects->end(); itOld++) {
		delete *itOld;
	}
	m_objects->clear();	
}

GameObject* ObjectManager::operator[](const unsigned int i) {
	if (i >= m_objects->size())
		return NULL;
	return m_objects->at(i);
}

unsigned int ObjectManager::count() {
	return m_objects->size();
}

void ObjectManager::copyFrom(ObjectManager* source)
{
	ClearDelete();
	for (int i = 0; i < source->count(); i++)
		m_objects->push_back(source->m_objects->at(i));
}

