/*Copyright (C) 2010 Deveaux Duncan

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "MoteurPhysique.hpp"
#include <iostream>

MoteurPhysique::MoteurPhysique(sf::FloatRect pMondePhysique, int pSol, int pGravite) :
mondePhysique(pMondePhysique), sol(pSol), gravite(pGravite)
{
	
}

void MoteurPhysique::ajouteObjet(ObjetPhysique *pObjet)
{
	listeObjetsPhysiques.push_back(pObjet);
}

void MoteurPhysique::supprimeObjet(ObjetPhysique *pObjet)
{
	std::vector<ObjetPhysique*>::iterator it;
	it = std::find(listeObjetsPhysiques.begin(), listeObjetsPhysiques.end(), pObjet);
	
	if (it != listeObjetsPhysiques.end())
		listeObjetsPhysiques.erase(it);
}

void MoteurPhysique::update()
{
	for (int i = 0; i < listeObjetsPhysiques.size(); i++)
	{
		if (!isATerre(listeObjetsPhysiques[i]))
		{
				float nouveauY = listeObjetsPhysiques[i]->getPositionY() + gravite;
				if (nouveauY > sol) nouveauY = sol;
				
				deplaceObjetY(listeObjetsPhysiques[i], nouveauY);
		}
	}
}

void MoteurPhysique::deplaceObjetX(ObjetPhysique *pObjetADeplacer, float pPositionX)
{
	float oldX = pObjetADeplacer->getPositionX();
	pObjetADeplacer->setPositionX(pPositionX);
	
	if (testCollisionObjet(pObjetADeplacer) != NULL || !testCollisionMonde(pObjetADeplacer))
		pObjetADeplacer->setPositionX(oldX);
}

void MoteurPhysique::deplaceObjetY(ObjetPhysique *pObjetADeplacer, float pPositionY)
{
	float oldY = pObjetADeplacer->getPositionY();
	pObjetADeplacer->setPositionY(pPositionY);
	
	if (testCollisionObjet(pObjetADeplacer) != NULL || !testCollisionMonde(pObjetADeplacer))
		pObjetADeplacer->setPositionY(oldY);
}

ObjetPhysique *MoteurPhysique::testCollisionObjet(ObjetPhysique *pObjetATester)
{
	//Position qui utilise le point d'origine haut gauche de l'objet
	float positionX = pObjetATester->getPositionX() - pObjetATester->getOrigin().x;
	float positionY = pObjetATester->getPositionY() - pObjetATester->getOrigin().y;
	float largeur = pObjetATester->getLargeur();
	float hauteur = pObjetATester->getHauteur();
	
	for (int i = 0; i < listeObjetsPhysiques.size(); i++)
	{
		if (pObjetATester != listeObjetsPhysiques[i])
		{
			float positionXObjetTest = listeObjetsPhysiques[i]->getPositionX() - listeObjetsPhysiques[i]->getOrigin().x;
			float positionYObjetTest = listeObjetsPhysiques[i]->getPositionY() - listeObjetsPhysiques[i]->getOrigin().y;
			float largeurObjetTest = listeObjetsPhysiques[i]->getLargeur();
			float hauteurObjetTest = listeObjetsPhysiques[i]->getHauteur();
			
			if ((positionX + largeur >= positionXObjetTest && positionX <= positionXObjetTest + largeurObjetTest) && (positionY + hauteur >= positionYObjetTest && positionY <= positionYObjetTest + hauteurObjetTest))
				return listeObjetsPhysiques[i];
		}
	}
	
	return NULL;
}

bool MoteurPhysique::testCollisionMonde(ObjetPhysique *pObjetATester)
{
	float x1 = pObjetATester->getPositionX() - pObjetATester->getOrigin().x;
	float y1 = pObjetATester->getPositionY() - pObjetATester->getOrigin().y;
	float x2 = x1 + pObjetATester->getLargeur();
	float y2 = y1 + pObjetATester->getHauteur();
	
	if (mondePhysique.Contains(x1, y1) && mondePhysique.Contains(x2, y2))
		return true;
	
	return false;
}

bool MoteurPhysique::isATerre(ObjetPhysique *pObjetATester)
{
	float positionY = pObjetATester->getPositionY();
	if (positionY < sol)
	{
		pObjetATester->setPositionY(positionY + gravite);
		ObjetPhysique *objetCollision = testCollisionObjet(pObjetATester);
		
		pObjetATester->setPositionY(positionY);
		if(objetCollision == NULL)
			return false;
	}
	
	return true;
}