#include "collision.h"
#include "sprite.h"
#include "renderer.h"

using namespace Halley;
using namespace Halley::Collision;


Type::Type()
	: mask(::None)
	, radius(0)
{
}


void Checker::reset()
{
	triggers.clear();
}


void Checker::addTriggerMap(spSprite sprite, TriggerMap& map)
{
	size_t s = map.size();
	for (size_t i=0; i<s; i++) {
		Mask mask = map[i].first;
		triggers[mask].push_back(SpriteData(sprite, map[i].second));
	}
}


void Checker::runCollisions(std::map<int, SpriteList>& objects)
{
	for (auto iter = triggers.begin(); iter != triggers.end(); iter++) {
		Mask type = iter->first;

		auto objsIter = objects.find(type);
		if (objsIter != objects.end()) {
			runCollisions(iter->second, objsIter->second);
		}
	}
}


void Checker::runCollisions(SpriteDataList& triggers, SpriteList& objects)
{
	size_t sz = triggers.size();
	for (auto i=objects.begin(); i!=objects.end(); i++) {
		Sprite& b = *(*i);
		Type colB = b.getColType();
		Vector2f bp = b.getPos();

		if (!b.isAlive()) {
		} else {
			for (size_t j=0; j<sz; j++) {
				Sprite& a = *triggers[j].first;
				Type colA = a.getColType();
				Vector2f ap = a.getPos();

				if (!a.isAlive()) {
				} else {
					if (collides(colA, colB, ap, bp)) {
						// Invoke trigger
						triggers[j].second(b);

						// b died, break
						if (b.isAlive()) break;
					}
				}
			}
		}
	}
}


bool Checker::collides(Type& a, Type& b, Vector2f aPos, Vector2f bPos)
{
	const float ar = a.radius;
	const float br = b.radius;
	const float r = ar+br;
	const float ax = aPos.x;
	const float ay = aPos.y;
	const float bx = bPos.x;
	const float by = bPos.y;

	// Square collision detection first
	//if (ay < by-r || ay > by+r) return false;
	//if (ax < bx-r || ax > bx+r) return false;

	// Circle detection
	const float rsq = r*r;
	const float dx = ax - bx;
	const float dy = ay - by;
	const float dsq = dx*dx + dy*dy;
	return dsq < rsq;
}
