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

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

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

void Player::render(sf::RenderWindow &renderWindow)
{
    m_animations.render(renderWindow);
}

void Player::update()
{
    //Update attacks
    Animation *currentAnimation = m_animations.getCurrentAnimation();
    if (m_condition.isAttacking() && currentAnimation->getCurrentFrameIx() == currentAnimation->getFramesNo() - 1)
    {   //Attack's end
        PhysicsObject *hitObject = m_physicsEngine->objectHitTest(this);
        if (hitObject != NULL) //hit
            hitObject->takeAHit(m_strength);
        
        m_condition.setAttack(false);
    }
    
    //Update jumps
        //Note : The player is subject to gravity
    if (m_condition.isJumping())
    {
        if (m_jumpEnergy > 0) //The player still has energy to jump
        {
            m_physicsEngine->moveObjectY(this, getYPosition() - m_jumpEnergy);
            m_jumpEnergy--; //He loose a part of energy
        }
        
        if (m_physicsEngine->isOnGround(this))
        {
            m_condition.setJump(false);
            m_jumpEnergy = m_basicJumpEnergy; //Get back his jump energy
        }
    }
    
    //Update animations
    m_animations.update();
}

void Player::move(int direction)
{
    //Change animation (if needed)
    if (!m_condition.isMoving())
    {
        m_animations.startAnimation(1);
        m_condition.setMove(true);
    }
    
    //Change direction
    if (m_animations.getDirection() != direction)
        m_animations.setDirection(direction);
    
    //Move
    if (direction == 0)
        m_physicsEngine->moveObjectX(this, getXPosition() - m_speed);
    else if (direction == 1)
        m_physicsEngine->moveObjectX(this, getXPosition() + m_speed);
}

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

void Player::jump()
{
    //Will be updated in update()
    if (!m_condition.isJumping() && m_physicsEngine->isOnGround(this))
        m_condition.setJump(true);
}

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

void Player::takeAHit(float strength)
{
    //Take a hit
    int remainingLives = m_health - strength;
    setHealth(remainingLives);
    
    //Launch hit animation
    if (!m_animations.isAnimationBlocking())
        m_animations.startAnimation(3, true);
    
    //Launch hit sound
    m_soundEngine->playSound("data/sound/characters/" + m_name + "/takeAHit.ogg");
}

//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_basicJumpEnergy = jumpEnergy;
}

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

//PhysicsObject virtual methods
const sf::Vector2f &Player::getOrigin() const
{
    return m_animations.getAnimationOrigin();
}

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

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

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();
}