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

AnimationManager::AnimationManager() :
m_ixAnimation(-1), m_ixBackAnimation(0), m_blockingAnimation(false), m_animationLaunched(false), m_direction(0)
{
    
}

void AnimationManager::render(sf::RenderWindow &renderWindow)
{
    if (m_ixAnimation != -1) //An animation was started
        m_animationsList[m_ixAnimation].render(renderWindow); //Render it
}

void AnimationManager::update()
{
    if (m_ixAnimation != -1) //An animation was started
    {
        //Start new animation if the old blocking one is finished
        if (m_blockingAnimation)
        {
            if (m_animationsList[m_ixAnimation].getCurrentFrameIx() == m_animationsList[m_ixAnimation].getFramesNo() - 1)
            {
                m_blockingAnimation = false;
                startAnimation(m_ixBackAnimation, false);
            }
        }
        
        //Change frame
        if (!m_animationLaunched)
            m_animationsList[m_ixAnimation].next();
        else //An animation was just launched
            m_animationLaunched = false;
        
        //Origin
        updateOrigin();
    }
}

void AnimationManager::addAnimation(const Animation &animation, int animationIx)
{
    if (animationIx == -1)
        m_animationsList.push_back(animation);
    
    else if (animationIx >= 0 && animationIx <= static_cast<int>(m_animationsList.size()) - 1)
        m_animationsList[animationIx] = animation;
}

void AnimationManager::removeAnimation(int animationIx)
{
    if (animationIx >= 0 && animationIx <= static_cast<int>(m_animationsList.size()) - 1)
        m_animationsList.erase(m_animationsList.begin() + animationIx);
}

void AnimationManager::startAnimation(int animationIx, bool blocking, int ixBackAnimation)
{
    //Will be updated in update()
    if (animationIx >= 0 && animationIx <= static_cast<int>(m_animationsList.size()) - 1) //Requested animation exists
    {
        if (!m_blockingAnimation)
        {
            //Change animation
            m_ixAnimation = animationIx;
            if (blocking)
            {
                m_ixBackAnimation = ixBackAnimation;
                m_blockingAnimation = true;
            }
            
            //Reset animation
            m_animationsList[m_ixAnimation].goToFrame(0);
            m_animationLaunched = true;
        }
    }
}

AnimationManager AnimationManager::loadFromXML(const std::string &xmlPath, const std::string &animationsPath)
{
    //AnimationManager initialization
    AnimationManager animationManager;
    
    //TinyXML initialization
    TiXmlDocument animationsListXMLFile( xmlPath.c_str() );
    animationsListXMLFile.LoadFile();
    
    TiXmlHandle handleXML(&animationsListXMLFile);
    TiXmlElement *animationsListXMLElements = handleXML.FirstChildElement().FirstChildElement().FirstChildElement().Element();
    
    while (animationsListXMLElements)
    {
        //Get informations about the animation (path, frames number)
        std::string animationName = animationsPath + animationsListXMLElements->Attribute("name") + "/";
        int framesNo;
        animationsListXMLElements->QueryIntAttribute("framesNo", &framesNo);
        
        //Create animation and add it the animation manager
        animationManager.addAnimation( Animation::loadFromDir(animationName, framesNo) );
        
        animationsListXMLElements = animationsListXMLElements->NextSiblingElement();
    }
    
    return animationManager;
}

//Get and set methods
    //Public
Animation *AnimationManager::getCurrentAnimation()
{
    return &m_animationsList[m_ixAnimation];
}

bool AnimationManager::isAnimationBlocking() const
{
    return m_blockingAnimation;
}

const sf::Vector2f &AnimationManager::getAnimationOrigin() const
{
    return m_animationsList[m_ixAnimation].getOrigin();
}

void AnimationManager::setDirection(int direction)
{
    if (direction == 0 || direction == 1)
    {
        m_direction = direction;
        
        //Adapt animation's direction
        int newX;
        if (getDirection() == 0)
            newX = getXPosition() + getWidth();
        else
            newX = getXPosition() - getWidth();
        
        setXPosition(newX);
        setFlipX(m_direction);
        
        //Origin
        updateOrigin();
    }
}

int AnimationManager::getDirection() const
{
    return m_direction;
}

float AnimationManager::getWidth() const
{
    return m_animationsList[m_ixAnimation].getWidth();
}

float AnimationManager::getHeight() const
{
    return m_animationsList[m_ixAnimation].getHeight();
}

void AnimationManager::setXPosition(float position)
{
    for (unsigned int i = 0; i < m_animationsList.size(); i++)
    {
        m_animationsList[i].setXPosition(position);
    }
}

float AnimationManager::getXPosition() const
{
    return m_animationsList[m_ixAnimation].getXPosition();
}

void AnimationManager::setYPosition(float position)
{
    for (unsigned int i = 0; i < m_animationsList.size(); i++)
    {
        m_animationsList[i].setYPosition(position);
    }
}

float AnimationManager::getYPosition() const
{
    return m_animationsList[m_ixAnimation].getYPosition();
}

    //Private
void AnimationManager::setOrigin(const sf::Vector2f &localPosition)
{
    for (unsigned int i = 0; i < m_animationsList.size(); i++)
    {
        m_animationsList[i].setOrigin(localPosition);
    }
}

void AnimationManager::setFlipX(bool flipX)
{
    for (unsigned int i = 0; i < m_animationsList.size(); i++)
    {
        m_animationsList[i].flipX(flipX);
    }
}

void AnimationManager::updateOrigin()
{
    //Set frame's origin
    int yOrigin;
    yOrigin = getHeight();
    
    int xOrigin;
    if (getDirection() == 0) xOrigin = getWidth();
    else xOrigin = 0;
    
    setOrigin( sf::Vector2f(xOrigin, yOrigin) );
}