/*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(), m_health(100), m_strength(0), m_speed(0), m_jumpEnergy(0), m_soundEngine(NULL)
{
    
}

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), m_soundEngine(NULL)
{
    
}

void Player::loadGraphics(TextureManager &textureManager)
{
    std::string graphicsPath = "data/gfx/characters/" + m_name + "/";
    m_moves.load(graphicsPath + "data.xml", graphicsPath, textureManager, (*this));
    m_moves.update(0); //Initial update (origin, ...)
    
    //Init physics box
    setWidth(m_moves.getWidth());
    setHeight(m_moves.getHeight());
}

void Player::draw()
{
    if (!m_moves.getXFlip()) m_moves.setXPosition(m_box.left);
    else m_moves.setXPosition(m_box.left + m_box.width);
    
    m_moves.setYPosition(m_box.top + m_box.height);
    
    m_moves.draw();
}

void Player::update()
{
    setWidth(m_moves.getWidth(), m_moves.getXFlip());
    setHeight(m_moves.getHeight(), true);
}

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

void Player::move(int direction, float frameTime)
{
    if (!isKo() && m_moves.getAction() == ACTION_DEFAULT)
    {
        //Change state (if needed)
        if (m_moves.getState() != STATE_MOVING)
            m_moves.setState(STATE_MOVING);
        
        //Change direction
        m_moves.setXFlip(!direction);
        
        //Move
        float elapsedTime = static_cast<float>(frameTime) / 1000;
        
        if (direction == 0)
            moveXPosition(-m_speed * elapsedTime);
        else if (direction == 1)
            moveXPosition(m_speed * elapsedTime);
    }
}

void Player::stop()
{
    //Go back to default state
    m_moves.setState(STATE_DEFAULT);
}

void Player::jump()
{
    if (m_physicsWorld != NULL && (!isKo() && isOnGround()))
        m_physicsWorld->pulseObject((*this), 0, -m_jumpEnergy);
}

void Player::punch()
{
    if (m_moves.getState() != STATE_KO && m_moves.getAction() == ACTION_DEFAULT)
        m_moves.punch();
}

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;
    
    if (m_physicsWorld != NULL)
        m_physicsWorld->pulseObject((*this), pulse, 0);
    
    //Launch hit sound
    m_soundEngine->playSound("data/sound/characters/" + m_name + "/takeAHit.ogg");
    
    if (!isKo() && remainingLives <= 0) //Ko
        m_moves.setState(STATE_FALLING, STATE_KO);
}

bool Player::isKo() const
{
    return (m_moves.getState() == STATE_FALLING || m_moves.getState() == STATE_KO);
}

//Attacks callback
void Player::hit(const HitBox &hitBox)
{
    Box relativeBox = hitBox.box;
    relativeBox.left = m_box.left + relativeBox.left;
    relativeBox.top = m_box.top + relativeBox.top;
    
    if (m_moves.getXFlip())
        relativeBox.left = m_box.left - ((relativeBox.left + relativeBox.width) - (m_box.left + m_box.width));
    
    std::vector<PhysicsObject*> hitObjects = hitTest(relativeBox);
    
    for (unsigned int i = 0; i < hitObjects.size(); i++) //Pum ! ;)
    {
        if (m_box.left < hitObjects[i]->getBox().left)
            hitObjects[i]->takeAHit(m_strength * hitBox.factor, 0);
        else
            hitObjects[i]->takeAHit(m_strength * hitBox.factor, 1);
    }
}

//Engines methods
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;
}
