/*Copyright (C) 2010-2023 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/>.
*/

#ifndef DEF_ARENA
#define DEF_ARENA

#include "Platform.hpp"
#include "Structs/Box.hpp"
#include "Structs/Vector.hpp"
#include <cstddef>
#include <map>
#include <list>
#include <vector>
#include <string>

/// Arena provides the option to subscribe all platforms to a physics world
class PhysicsWorld;
class SoundInterface; ///< For enabling platform sound effects
class PhysicsObjectStatus; ///< To return and update platforms

/// A fighting arena's information. It has a size, physics properties,
/// can contain platforms and specify players spawn position.
class Arena
{
    public:
        Arena();

        void addPlatform(const Box &srcBox, const Vector &drawSize,
                         const Box &bodyBox, const Vector &spawnPosition,
                         const std::string &material, bool hitable=false,
                         bool fixed=false);

        /// Apply an updated list of platform status
        void applyPlatformStatus(const std::vector<PhysicsObjectStatus> &status);

        /// Configure a physics world to match with the arena parameters
        void applyToPhysics(PhysicsWorld &physicsWorld) const;

        /// Pass the provided sound interface to the known platforms
        void applySoundInterface(SoundInterface *soundInterface);

        /// Subscribe the arena's platforms to a physics world
        void subscribePlatforms(PhysicsWorld &physicsWorld);

        /// Unsubscribe the platforms from a physics world,
        /// useful for fight scene reset
        void unsubscribePlatforms(PhysicsWorld &physicsWorld) const;

        const std::list<Platform> &getPlatforms() const;

        /// Retrieve the list of platform status
        std::vector<PhysicsObjectStatus> getPlatformStatus() const;

        void setBackground(const std::string &texturePath, const Box &source);
        const std::string &getTexturePath() const;
        const Box &getBakgroundSource() const;

        void setAmbient(const std::string &ambient);
        const std::string &getAmbient() const;

        void setWidth(float width);
        float getWidth() const;

        void setHeight(float height);
        float getHeight() const;

        void setGround(float ground);
        float getGround() const;

        void setGroundMaterial(const std::string &material);
        const std::string &getGroundMaterial() const;

        void setGravity(float gravity);
        void setAirFriction(float airFriction);

        void setMinCameraWidth(float minWidth);
        float getMinCameraWidth() const;

        void setPlayerSpawn(std::size_t ix, const Vector &playerSpawn);
        bool getPlayerSpawn(std::size_t ix, Vector &target) const;

    private:
        float m_width, m_height, m_ground;
        std::string m_groundMaterial, m_ambient;

        float m_gravity, m_airFriction;
        float m_minCameraWidth;

        std::list<Platform> m_platformsList;
        std::map<std::size_t, Vector> m_playerSpawns;

        Box m_background;
        std::string m_texturePath;
};

namespace ArenaTools
{
    /// Loads the arena of name \p name from the xml arena description file
    Arena load(const std::string &name);

    /// Return the names of known local arenas
    std::vector<std::string> fetchNames();

    /// Check if \p value is in \p names
    bool validateName(const std::vector<std::string> &names,
                      const std::string &value);
}

#endif
