/*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_PEER_INFO_LAYER
#define DEF_PEER_INFO_LAYER

#include "Graphics/Drawable/Drawable.hpp"
#include "Graphics/Drawable/Polygon.hpp"
#include "Graphics/Drawable/Sprite.hpp"
#include "Graphics/Drawable/Text.hpp"
#include "Network/Serialization/PeerData.hpp"
#include <vector>
#include <cstdint>

struct PeerData;
class TextureManager;
class FontManager;
class Font;
struct Vector;

/// Describes the layout of a peer info row: size and positioning of cells
struct RowLayout
{
    float width; ///< Width of each row
    float height; ///< Height of each row
    float icons; ///< y-position of the icons in each row
    float usernames; ///< y-position of the usernames in each row
    float pings; ///< y-position of the pings in each row
};

/// Header to label the content of each peer information row
class PeerInfoHeader : public Drawable
{
    public:
        PeerInfoHeader() = default;
        PeerInfoHeader(const RowLayout &layout, Font &font);
        void draw() override;

        float getWidth() const;
        float getHeight() const;

    private:
        Polygon m_background;
        Text m_character, m_username, m_ping;
        float m_width = 0.f, m_height = 0.f;
};

/// Shows the information of a connected peer (character, username, and ping)
class PeerInfoRow : public Drawable
{
    public:
        PeerInfoRow(const RowLayout &layout, const PeerData &peerData,
                    TextureManager &textureManager, Font &font);

        void draw() override;
        void setPing(std::uint32_t ping);

        float getHeight() const;

    private:
        Polygon m_background;
        Sprite m_icon;
        Text m_username, m_ping;
        const float m_height;
};

/// Header to indicate the start of the spectators section of the layer
class SpectatorHeader : public Drawable
{
    public:
        SpectatorHeader() = default;
        SpectatorHeader(float width, float height, float padding, Font &font);

        void draw() override;
        void setWidth(float width);

        float getHeight() const;

    private:
        Text m_text;
        Polygon m_background;
        float m_height = 0.f, m_padding = 0.f;
};

/// Shows the information of a connected spectator in a reduced format
/// (only character and username)
class SpectatorBadge : public Drawable
{
    public:
        SpectatorBadge(float height, float padding, const PeerData &peerData,
                       TextureManager &textureManager, Font &font);
        void draw() override;

        float getWidth() const;
        float getHeight() const;

    private:
        Sprite m_icon;
        Text m_username;

        const float m_width, m_height;
        Polygon m_background;
};

/// Peer information layer which can be shown in networked games,
/// lists the character, usernames, and ping of players and spectators
class PeerInfoLayer : public Drawable
{
    public:
        PeerInfoLayer();
        void draw() override;

        void reset(); ///< Reset peers
        void setPeers(const std::vector<PeerData> &players,
                      const std::vector<PeerData> &spectators,
                      const Vector &viewSize,
                      TextureManager &textureManager,
                      FontManager &fontManager);

        void updatePings(const std::vector<std::uint32_t> &pings);

        float getWidth() const;
        float getHeight() const;

    private:
        void updatePositions(float viewWidth);

        PeerInfoHeader m_header;
        std::vector<PeerInfoRow> m_players;
        SpectatorHeader m_spectatorHeader;
        std::vector<SpectatorBadge> m_spectators;

        float m_width, m_height;
};

#endif
