/*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, int maxHealth, int maxEnergy, int strength, int speed) :
m_name(name), m_maxHealth(maxHealth), m_maxEnergy(maxEnergy), m_strength(strength), m_speed(speed)
{
    //Init health
    m_oldHealth = m_health = m_maxHealth;
    m_oldEnergy = m_energy = m_maxEnergy;
    m_basicJumpEnergy = m_jumpEnergy = 33;
    
    //Init graphics part (AnimationManager)
    std::string animationsPath = "data/gfx/characters/" + m_name + "/";
    m_animationsManager.load(animationsPath, animationsPath + "animations.xml");
}

void Player::update(const sf::Input &keys)
{
    //Update attacks
    Animation *currentAnimation = m_animationsManager.getCurrentAnimation();
    if (m_condition.isAttacking() && currentAnimation->getCurrentFrameIx() == currentAnimation->getFramesNo() - 2)
    {   //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 moves
    if (keys.IsKeyDown(sf::Key::F)) move(0);
    else if (keys.IsKeyDown(sf::Key::H)) move(1);
    else if (m_condition.isMoving()) stop();
    
    //Other actions
    if (keys.IsKeyDown(sf::Key::W)) jump();
    if (keys.IsKeyDown(sf::Key::A)) attack();
    
    //Update animations
    m_animationsManager.update();
}

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

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

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_animationsManager.isAnimationBlocking() && !m_condition.isAttacking())
    {   //He doesn't do a blocking move.
        m_condition.setAttack(true);
        m_animationsManager.startAnimation(2, true);
    }
}

void Player::takeAHit(int strength)
{
    //Take a hit
    int remainingLives = getHealth() - strength;
    if (remainingLives < 0)
        remainingLives = 0;
            
    setHealth(remainingLives);
    
    //Launch hit animation
    if (!m_animationsManager.isAnimationBlocking())
        m_animationsManager.startAnimation(3, true);
}

//Graphics methods
void Player::startRendering(GraphicsEngine &renderEngine)
{
    m_animationsManager.startRendering(renderEngine);
}

void Player::stopRendering(GraphicsEngine &renderEngine)
{
    m_animationsManager.stopRendering(renderEngine);
}

//Physics methods
void Player::setPhysicsEngine(PhysicsEngine *physicsEngine)
{
    m_physicsEngine = physicsEngine;
}

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

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

void Player::setMaxHealth(int maxHealth)
{
    m_maxHealth = maxHealth;
}

int Player::getMaxHealth() const
{
    return m_maxHealth;
}

void Player::setHealth(int health)
{
    m_health = health;
}

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

void Player::setMaxEnergy(int maxEnergy)
{
    m_maxEnergy = maxEnergy;
}

int Player::getMaxEnergy() const
{
    return m_maxEnergy;
}

void Player::setEnergy(int energy)
{
    m_energy = energy;
}

int Player::getEnergy() const
{
    return m_energy;
}

void Player::setStrength(int strength)
{
    m_strength = strength;
}

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

void Player::setSpeed(int speed)
{
    m_speed = speed;
}

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

void Player::setDirection(int direction)
{
    if (direction == 0 || direction == 1)
    {
        m_animationsManager.setDirection(direction);
    }
}

int Player::getDirection() const
{
    return m_animationsManager.getDirection();
}

//Events methods
bool Player::healthAltered()
{
    if (m_oldHealth != m_health)
    {
        m_oldHealth = m_health;
        return true;
    }
    
    return false;
}

bool Player::energyAltered()
{
    if (m_oldEnergy != m_energy)
    {
            m_oldEnergy = m_energy;
            return true;
    }
    
    return false;
}

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

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

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

void Player::setXPosition(float position)
{
    m_animationsManager.setXPosition(position);
}

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

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

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