/*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_SERVER_EVENT
#define DEF_SERVER_EVENT

#include "Fight/FightRules.hpp"
#include "Network/Serialization/MatchmakingStrategy.hpp"
#include "Tools/Utf8.hpp"
#include <list>
#include <string>
#include <cstdint>

/// A message sent by a server to welcome a peer
class WelcomeEvent
{
    public:
        enum : size_t { MaxWelcomeLength = 128 };

        WelcomeEvent() = default;
        explicit WelcomeEvent(const Utf8::utf8_string &message);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        Utf8::utf8_string m_message;
};

/// A message sent by a server to describe the rules to a peer
class RulesEvent
{
    public:
        RulesEvent() = default;
        explicit RulesEvent(const FightRules &rules);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        void writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        FightRules m_rules;
};

/// Describes a peer connected event
class PeerConnectedEvent
{
    public:
        PeerConnectedEvent() = default;
        explicit PeerConnectedEvent(const Utf8::utf8_string &username);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        Utf8::utf8_string m_username;
};

/// Describes a peer disconnected event
class PeerDisconnectedEvent
{
    public:
        PeerDisconnectedEvent() = default;
        explicit PeerDisconnectedEvent(const Utf8::utf8_string &username);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        Utf8::utf8_string m_username;
};

/// Describes a peer kicked for inactivity event
class PeerInactiveEvent
{
    public:
        PeerInactiveEvent() = default;
        explicit PeerInactiveEvent(const Utf8::utf8_string &username);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        Utf8::utf8_string m_username;
};

/// Informs that matchmaking has been performed
class MatchmakingEvent
{
    public:
        MatchmakingEvent();
        explicit MatchmakingEvent(const MatchmakingStrategy::Type &strategy);

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        MatchmakingStrategy::Type m_strategy;
};

/// Informs that a new game will start shortly
class GameScheduledEvent
{
    public:
        std::string getLog() const;
};

/// A server event, sent to clients as information to be printed in logs
class ServerEvent
{
    public:
        enum class Type : std::uint8_t
        {
            NoEvent = 0,
            Welcome = 1,
            Rules = 2,
            PeerConnected = 3,
            PeerDisconnected = 4,
            PeerInactive = 5,
            Matchmaking = 6,
            GameScheduled = 7
        };

        enum : std::uint8_t
        {
            TypeLimit = static_cast<std::uint8_t>(Type::GameScheduled)
        };

        ServerEvent();
        explicit ServerEvent(const WelcomeEvent &welcome);
        explicit ServerEvent(const RulesEvent &rules);
        explicit ServerEvent(const PeerConnectedEvent &peerConnected);
        explicit ServerEvent(const PeerDisconnectedEvent &peerDisconnected);
        explicit ServerEvent(const PeerInactiveEvent &peerInactive);
        explicit ServerEvent(const MatchmakingEvent &matchmaking);
        explicit ServerEvent(const GameScheduledEvent &gameScheduled);
        ServerEvent(const ServerEvent &copied) = delete;
        ServerEvent &operator=(const ServerEvent &copied) = delete;
        ~ServerEvent();

        /// Read/write from buffer
        bool readFromBuffer(std::list<std::uint8_t> &bytes);
        bool writeToBuffer(std::list<std::uint8_t> &dst) const;

        std::string getLog() const;

    private:
        Type m_eventType;
        union
        {
            WelcomeEvent *m_welcome; ///< A welcome message sent to a client
            RulesEvent *m_rules; ///< A rules message sent to a client
            PeerConnectedEvent *m_peerConnected; ///< A peer has connected
            PeerDisconnectedEvent *m_peerDisconnected; ///< A peer has disconnected
            PeerInactiveEvent *m_peerInactive; ///< A peer was kick for inactivity
            MatchmakingEvent *m_matchmaking; ///< Matchmaking was performed
            GameScheduledEvent *m_gameScheduled; ///< A game has been scheduled
        };
};

#endif
