/*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 "Player.hpp"

Player::Player() : PhysicsObject()
{
    
}

Player::Player(const std::string &name, float health, float strength, float speed, float jumpEnergy) :
PhysicsObject(), m_name(name), m_health(health), m_strength(strength), m_speed(speed), m_jumpEnergy(jumpEnergy)
{
    
}

void Player::loadGraphics(TextureManager &textureManager)
{
    std::string graphicsPath = "data/gfx/characters/" + m_name + "/";
    
    m_animations = AnimationGroup::loadFromXML(graphicsPath + "animations.xml", graphicsPath, textureManager);
    m_animations.startAnimation(0);
    
    m_currentPosition = 0;
}

void Player::draw()
{
    m_animations.updateOrigin();
    m_animations.draw();
}

void Player::update()
{
    //Update attacks
    if (m_condition.isAttacking() && m_animations.animationFinished()) //Attack's end
    {
        std::vector<PhysicsObject*> hitObjects = m_physicsEngine->objectHitTest(this, m_animations.getBox());
        for (unsigned int i = 0; i < hitObjects.size(); i++)
        {
            if (getXPosition() - getXOrigin() < hitObjects[i]->getXPosition() - hitObjects[i]->getXOrigin())
                hitObjects[i]->takeAHit(m_strength, 0);
            else
                hitObjects[i]->takeAHit(m_strength, 1);
        }
        
        m_condition.setAttack(false);
    }
}

void Player::updateGraphics(float frameTime)
{
    m_animations.update(frameTime);
}

void Player::move(int direction, float frameTime)
{
    if (!m_condition.isKo())
    {
        //Change animation (if needed)
        if (!m_condition.isMoving())
        {
            m_animations.startAnimation(1);
            m_condition.setMove(true);
        }
        
        //Change direction
        m_animations.setXFlip(!direction);
        
        //Move
        float elapsedTime = static_cast<float>(frameTime) / 1000;
        
        if (direction == 0)
            m_physicsEngine->moveObjectX(this, -m_speed * elapsedTime);
        else if (direction == 1)
            m_physicsEngine->moveObjectX(this, m_speed * elapsedTime);
    }
}

void Player::stop()
{
    m_animations.startAnimation(0);
    m_condition.setMove(false);
}

void Player::jump()
{
    if (!m_condition.isKo() && m_physicsEngine->isOnGround(this))
        m_physicsEngine->pulseObject(this, 0, -m_jumpEnergy);
}

void Player::attack()
{
    //Will be updated in update()
    if ( !m_condition.isKo() && (!m_animations.animationBlocking() && !m_condition.isAttacking()) )
    {
        m_animations.startAnimation(2, true);
        m_condition.setAttack(true);
    }
}

void Player::takeAHit(float strength, int side)
{
    //Alter life
    int remainingLives = m_health - strength;
    setHealth(remainingLives);
    
    //Pulse
    float pulse = 40 * strength;
    if (side == 1) pulse *= -1;
    
    m_physicsEngine->pulseObject(this, pulse, 0);
    
    //Launch hit sound
    m_soundEngine->playSound("data/sound/characters/" + m_name + "/takeAHit.ogg");
    
    if (!m_condition.isKo() && remainingLives <= 0) //Ko
    {
        m_condition.setAttack(false);
        m_condition.setMove(false);
        
        m_animations.startAnimation(3, true, 4, true);
        m_currentPosition = 4;
        
        m_condition.setKo(true);
    }
}

//Engines methods
void Player::setPhysicsEngine(PhysicsEngine &physicsEngine)
{
    m_physicsEngine = &physicsEngine;
}

const PhysicsEngine &Player::getPhysicsEngine() const
{
    return *m_physicsEngine;
}

void Player::setSoundEngine(SoundEngine &soundEngine)
{
    m_soundEngine = &soundEngine;
}

const SoundEngine &Player::getSoundEngine() const
{
    return *m_soundEngine;
}

//Get and set methods
const std::string &Player::getName() const
{
    return m_name;
}

void Player::setHealth(float health)
{
    if (health < 0)
        m_health = 0;
    
    else if (health > 100)
        m_health = 100;
    
    else
        m_health = health;
}

float Player::getHealth() const
{
    return m_health;
}

void Player::setStrength(float strength)
{
    if (strength >= 0)
        m_strength = strength;
}

float Player::getStrength() const
{
    return m_strength;
}

void Player::setSpeed(float speed)
{
    if (speed >= 0)
        m_speed = speed;
}

float Player::getSpeed() const
{
    return m_speed;
}

void Player::setJumpEnergy(float jumpEnergy)
{
    if (jumpEnergy >= 0)
        m_jumpEnergy = jumpEnergy;
}

float Player::getJumpEnergy() const
{
    return m_jumpEnergy;
}

//PhysicsObject virtual methods
void Player::setXPosition(float position)
{
    m_animations.setXPosition(position);
}

float Player::getXPosition() const
{
    return m_animations.getXPosition();
}

void Player::setYPosition(float position)
{
    m_animations.setYPosition(position);
}

float Player::getYPosition() const
{
    return m_animations.getYPosition();
}

float Player::getXOrigin() const
{
    return 0;
}

float Player::getYOrigin() const
{
    return m_animations.getBox(m_currentPosition).height;
}

float Player::getWidth() const
{
    return m_animations.getBox(m_currentPosition).width;
}

float Player::getHeight() const
{
    return m_animations.getBox(m_currentPosition).height;
}
