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

Arena::Arena()
{
    
}

Arena::Arena(const sf::Sprite &background, float ground, float gravity) :
m_background(background), m_ground(ground), m_gravity(gravity)
{
    
}

void Arena::addPlatform(const Platform &platform, int platformIx)
{
    if (platformIx == -1)
        m_platformsList.push_back(platform);
    
    else if (platformIx >= 0 && platformIx <= static_cast<int>(m_platformsList.size()) - 1)
        m_platformsList[platformIx] = platform;
}

void Arena::removePlatform(int platformIx)
{
    if (platformIx >= 0 && platformIx <= static_cast<int>(m_platformsList.size()) - 1)
        m_platformsList.erase(m_platformsList.begin() + platformIx);
}

void Arena::render(sf::RenderWindow &renderWindow)
{
    renderWindow.Draw(m_background);
    
    for (unsigned int i = 0; i < m_platformsList.size(); i++)
    {
        m_platformsList[i].render(renderWindow);
    }
}

void Arena::applyToPhysics(PhysicsEngine &physicsEngine)
{
    //Configure a physics engine's parameters to match with the arena specific ones
    physicsEngine.setGroundPosition(m_ground);
    physicsEngine.setGravityForce(m_gravity);
}

void Arena::subscribeObjects(PhysicsEngine &physicsEngine)
{
    //Subscribe arena's platforms in a physics engine
    for (unsigned int i = 0; i < m_platformsList.size(); i++)
    {
        physicsEngine.addObject(&m_platformsList[i]);
    }
}

//Static methods
Arena Arena::loadFromXML(const std::string &name, const std::string &xmlPath)
{
    //ImageManager initialization
    ImageManager *imageManager = ImageManager::getInstance();
    
    //TinyXML initialization
    TiXmlDocument xmlFile;
    xmlFile.LoadFile(xmlPath.c_str());
    
    TiXmlHandle hdl(&xmlFile);
    TiXmlElement *xmlElement = hdl.FirstChildElement().FirstChildElement().ToElement();
    
    int nodeIx = 0;
    while (xmlElement)
    {
        std::string itemName = xmlElement->Attribute("name");
        if (itemName == name)
        {
            //Arena initialization
            Arena arena;
            
            //Get main informations
            sf::Sprite background;
            float ground;
            float gravity;
            
            background.SetImage(*imageManager->getImage( xmlElement->Attribute("background") ));
            xmlElement->QueryFloatAttribute("ground", &ground);
            xmlElement->QueryFloatAttribute("gravity", &gravity);
            
                //Update arena
            arena.setBackground(background);
            arena.setGround(ground);
            arena.setGravity(gravity);
            
            //Get detailled informations
            TiXmlHandle arenaHdl = hdl.FirstChildElement().Child(nodeIx);
            
                //Spawns
            TiXmlElement *spawnsElement = arenaHdl.FirstChildElement("spawns").FirstChildElement().ToElement();
            
            while (spawnsElement)
            {
                //Get informations
                int playerIx;
                float x, y;
                
                spawnsElement->QueryIntAttribute("playerIx", &playerIx);
                spawnsElement->QueryFloatAttribute("x", &x);
                spawnsElement->QueryFloatAttribute("y", &y);
                
                //Add them to arena
                arena.setPlayerSpawn(static_cast<unsigned int>(playerIx), sf::Vector2f(x, y));
                
                spawnsElement = spawnsElement->NextSiblingElement();
            }
            
                //Platforms
            TiXmlElement *platformsElement = arenaHdl.FirstChildElement("platforms").FirstChildElement().ToElement();
            
            while (platformsElement)
            {
                //Get informations
                sf::Sprite texture;
                float width, height;
                float x, y;
                
                texture.SetImage(*imageManager->getImage( platformsElement->Attribute("texture") ));
                platformsElement->QueryFloatAttribute("width", &width);
                platformsElement->QueryFloatAttribute("height", &height);
                platformsElement->QueryFloatAttribute("x", &x);
                platformsElement->QueryFloatAttribute("y", &y);
                
                //Create and add platform to the arena
                Platform platform(width, height, texture);
                platform.setXPosition(x);
                platform.setYPosition(y);
                
                arena.addPlatform(platform);
                
                platformsElement = platformsElement->NextSiblingElement();
            }
            
            return arena;
        }
        
        nodeIx++;
        xmlElement = xmlElement->NextSiblingElement();
    }
    
    return Arena();
}

//Get and set methods
    //Graphics
void Arena::setBackground(const sf::Sprite &background)
{
    m_background = background;
}

const sf::Sprite &Arena::getBackground() const
{
    return m_background;
}

    //Physics
void Arena::setGround(float ground)
{
    m_ground = ground;
}

float Arena::getGround() const
{
    return m_ground;
}

void Arena::setGravity(float gravity)
{
    m_gravity = gravity;
}

float Arena::getGravity() const
{
    return m_gravity;
}

    //Others
void Arena::setPlayerSpawn(unsigned int ix, const sf::Vector2f &playerSpawn)
{
    m_playerSpawns[ix] = playerSpawn;
}

bool Arena::getPlayerSpawn(unsigned int ix, sf::Vector2f &target) const
{
    std::map<unsigned int, sf::Vector2f>::const_iterator it = m_playerSpawns.find(ix);
    
    if (it != m_playerSpawns.end())
    {
        target = it->second;
        return true;
    }
    
    return false;
}