#include <iostream>

#include "Collisionhandler.h"
#include "glfuncs.h"
#include "Level.h"
#include <cmath>

#include <vector>


using namespace std;

CollisionHandler* CollisionHandler::_instance = NULL;

CollisionHandler::CollisionHandler()
:_currentLevel( NULL )
{
}

CollisionHandler* CollisionHandler::instance()
{
	if( _instance == NULL )
		_instance = new CollisionHandler();
	return _instance;
}

bool CollisionHandler::checkCollision( Object *o )
{
	bool collided = false;
	vector<Object *> objects = ObjsColliding(o);

	for(vector< Object* >::iterator i = objects.begin(); i != objects.end(); i++ )
	{
		//non solid objects don't collide with one another
		if( (o->solid() )||(*i)->solid() )
		{
			o->collide( (*i) );
			(*i)->collide( o );
			collided = true;
		}
	}

	return collided;
}

std::vector<Object*> CollisionHandler::ObjsColliding( Object *o, bool solidOnly)
{
	vector<Object*> returnme;
	
	Level* level = Level::instance();
	if( level == NULL )
		return returnme;

	bool collided = false;
	vector< Object* >& objects = level->getObjects();
	Tile* t;
	SDL_Rect box = o->getBox();

	for( int i = box.x / Level::tileWidth; i < ceil( (double)( box.x + box.w ) / Level::tileWidth ); i++ )
	{
		for( int j = box.y / Level::tileHeight; j < ceil( (double)( box.y + box.h ) / Level::tileHeight ); j++ )
		{
			t = level->getTile( i, j );

			if( t != NULL && o->collidable() && t->collidable() )
			{
				/*o->collide( t );
				t->collide( o );

				collided = true;*/
				returnme.push_back(t);
			}
		}
	}

	for( vector< Object* >::iterator i = objects.begin(); i != objects.end(); i++ )
	{
		// FIXME need some way to only call the collide function of the soonest collision
		if( o != (*i) && glfuncs::intersect( box, (*i)->getBox() ) && o->collidable() && (*i)->collidable() &&
			/*!(o->getType() == PLAYER && (*i)->getType() == BOSS) &&*/ !(o->getType() == BOSS && (*i)->getType() == PLAYER) )
		{
			/*o->collide( (*i) );
			(*i)->collide( o );

			collided = true;*/
			returnme.push_back(*i);
		}
	}

	if(solidOnly)
	{
		for( vector<Object *>::iterator i = returnme.begin(); i!= returnme.end();)
		{
			if(!(*i)->solid())
				i = returnme.erase(i);
			else
				i++;
		}
	}
	return returnme;
}