/*Copyright (C) 2010-2012 Duncan Deveaux

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 "PhysicsWorld.hpp"
#include "PhysicsObject.hpp"

PhysicsWorld::PhysicsWorld() : m_gravity(0), m_airFriction(0)
{
    
}

PhysicsWorld::PhysicsWorld(const Box &worldBox, float gravity, float airFriction) :
m_worldBox(worldBox), m_gravity(gravity), m_airFriction(airFriction)
{
    
}

void PhysicsWorld::update(float frameTime)
{
    float elapsedTime = frameTime / 1000;
    
    for (unsigned int i = 0; i < m_objectsList.size(); i++)
    {
        PhysicsObject *object = m_objectsList[i];
        Vector &pulse = m_objectsPulse[i];
        
        //Pulse
        if (pulse.x != 0) object->moveXPosition(pulse.x * elapsedTime);
        if (pulse.y != 0) object->moveYPosition(pulse.y * elapsedTime);
        
            //alterations
        Vector altered = pulse;
        
        float airFriction = m_airFriction * elapsedTime;
        if (altered.x > 0)
        {
            if (altered.x - airFriction < 0) altered.x = 0;
            else altered.x -= airFriction;
        }
        else if (altered.x < 0)
        {
            if (altered.x + airFriction > 0) altered.x = 0;
            else altered.x += airFriction;
        }
        
        if (!object->isOnGround()) altered.y += m_gravity * elapsedTime;
        else altered.y = 0;
        
        pulse = altered;
    }
}

void PhysicsWorld::debug()
{
    std::vector<PhysicsObject*>::iterator it;
    
    for (it = m_objectsList.begin(); it != m_objectsList.end(); it++)
    {
        Box box = (*it)->getBox();
        
        Polygon debug = Polygon::rectangle(box.left, box.top, box.width, box.height, Color(0, 0, 0, 0), Color(122, 122, 122));
        debug.draw();
    }
}

void PhysicsWorld::addObject(PhysicsObject &object)
{
    m_objectsList.push_back(&object);
    m_objectsPulse.push_back(Vector());
}

void PhysicsWorld::removeObject(PhysicsObject &object)
{
    for (unsigned int i = 0; i < m_objectsList.size(); i++)
    {
        if (m_objectsList[i] == &object)
        {
            m_objectsList.erase(m_objectsList.begin() + i);
            m_objectsPulse.erase(m_objectsPulse.begin() + i);
            
            i--;
        }
    }
}

void PhysicsWorld::pulseObject(PhysicsObject &object, float xPulse, float yPulse)
{
    for (unsigned int i = 0; i < m_objectsList.size(); i++)
    {
        if (m_objectsList[i] == &object)
        {
            m_objectsPulse[i].x += xPulse;
            m_objectsPulse[i].y += yPulse;
        }
    }
}

std::vector<PhysicsObject*> &PhysicsWorld::getObjects()
{
    return m_objectsList;
}

void PhysicsWorld::setWorldBox(const Box &worldBox)
{
    m_worldBox = worldBox;
}

const Box &PhysicsWorld::getWorldBox() const
{
    return m_worldBox;
}

void PhysicsWorld::setGravityForce(float gravity)
{
    m_gravity = gravity;
}

float PhysicsWorld::getGravityForce() const
{
    return m_gravity;
}

void PhysicsWorld::setAirFriction(float airFriction)
{
    m_airFriction = airFriction;
}

float PhysicsWorld::getAirFriction() const
{
    return m_airFriction;
}
