/*Copyright (C) 2010-2020 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 "WeaponMedium.hpp"
#include "Player/Player.hpp"

WeaponMedium::WeaponMedium(const std::vector<const Player*> &players, TextureManager &textureManager) : m_weaponIx(0)
{
    std::vector<const Player*>::const_iterator it;
    for (it = players.begin(); it != players.end(); it++)
    {
        m_playerSlots[(*it)] = WeaponSlots(5);
    }
    
    m_textureManager = &textureManager;
}

WeaponMedium::~WeaponMedium()
{
    std::map<int, Weapon*>::iterator it;
    for (it = m_weaponsList.begin(); it != m_weaponsList.end(); it++)
        delete it->second;
    
    m_weaponsList.clear();
}

void WeaponMedium::drawWeapons()
{
    std::map<int, Weapon*>::iterator it;
    for (it = m_weaponsList.begin(); it != m_weaponsList.end(); it++)
        it->second->draw();
}

void WeaponMedium::update(float frameTime)
{
    /// Remove weapons to be removed
    std::map<int, const Player*>::iterator it;
    for (it = m_toBeRemoved.begin(); it != m_toBeRemoved.end(); it++)
    {
        int weaponID = it->first;
        Weapon *weapon = m_weaponsList[weaponID];
        PhysicsWorld &world = weapon->getPhysicsWorld();
        
        world.removeObject((*weapon));
        m_weaponsList.erase(weaponID);
        delete weapon;
        
        // Transfer it to the potential new player.
        if (it->second != NULL)
            m_playerSlots[it->second].slots[WEAPON_SHURIKEN] += 1;
    }
    
    m_toBeRemoved.clear();
    
    /// Update graphics
    std::map<int, Weapon*>::iterator weapon_it;
    for (weapon_it = m_weaponsList.begin(); weapon_it !=  m_weaponsList.end(); weapon_it++)
        weapon_it->second->updateGraphics(frameTime);
}

void WeaponMedium::queueForRemoval(int weaponID)
{
    if (m_weaponsList.count(weaponID) == 1 && m_toBeRemoved.count(weaponID) == 0)
        m_toBeRemoved[weaponID] = NULL; // Not giving it away to any player (NULL).
}

void WeaponMedium::requestWeapon(int weaponID, const Player &player)
{
    if (m_weaponsList.count(weaponID) == 1 && m_toBeRemoved.count(weaponID) == 0)
        m_toBeRemoved[weaponID] = (&player);
}

void WeaponMedium::throwShuriken(PhysicsWorld &world, const Player &player)
{
    if (m_playerSlots[&player].slots[WEAPON_SHURIKEN] <= 0)
        return;
    
    const Box &playerBox = player.getBox();
    bool throwRight = !player.getXFlip();
    
    float width = SHURIKEN_WIDTH, height = SHURIKEN_WIDTH;
    
    float x_position = throwRight ? playerBox.left + playerBox.width + 10 : playerBox.left - width - 10;
    float y_position = playerBox.top + playerBox.height / 3;
    
    Box requiredBox( throwRight ? x_position : x_position - WEAPON_THROWING_DISTANCE_X,
                        y_position - WEAPON_THROWING_DISTANCE_Y,
                        width + WEAPON_THROWING_DISTANCE_X,
                        height + 2 * WEAPON_THROWING_DISTANCE_Y );
    
    if (world.isFree(requiredBox))
    {
        Shuriken *shuriken = new Shuriken((*this), m_weaponIx, (*m_textureManager));
        shuriken->setPhysicsWorld(world);
        shuriken->setPosition(x_position, y_position);
        
        m_weaponsList[m_weaponIx] = shuriken;
        
        world.addObject((*shuriken));
        world.pulseObject((*shuriken), (throwRight ? 1800 : -1800), -80);
        
        m_weaponIx++;
        
        // Notify player weapon throw.
        m_playerSlots[&player].slots[WEAPON_SHURIKEN] -= 1;
    }
}

bool WeaponMedium::getSlots(const Player &player, WeaponSlots &dest) const
{
    std::map<const Player*, WeaponSlots>::const_iterator it;
    it = m_playerSlots.find(&player);
    
    if (it != m_playerSlots.end())
    {
        dest = it->second;
        return true;
    }
    
    return false;
}
