/*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_CLIENT_HOST
#define DEF_CLIENT_HOST

#include "Channel.hpp"
#include "KickReason.hpp"
#include <enet/enet.h>

class Address;
class Message;

class ClientHost
{
    public:
        /// Receives message reception callbacks
        class MessageReceiver
        {
            public:
                virtual ~MessageReceiver() {}
                virtual void messageReceivedCallback(const ENetPacket &packet,
                                                     Channel channel) = 0;
        };

        /// Receives server connection and disconnection callbacks
        class ConnectionReceiver
        {
            public:
                virtual ~ConnectionReceiver() {}
                virtual void serverConnectedCallback() = 0;
                virtual void serverDisconnectingCallback(KickReason reason) = 0;
                virtual void serverDisconnectedCallback(KickReason reason) = 0;
        };

        ClientHost();
        ClientHost(const ClientHost &copied) = delete;
        ClientHost &operator=(const ClientHost &copied) = delete;
        ~ClientHost();
        void destroy();

        bool init();
        bool connect(const Address &address);
        void setMessageReceiver(MessageReceiver *receiver);
        void setConnectionReceiver(ConnectionReceiver *receiver);

        void listen();
        void send(const Message &message, Channel channel) const;

        void disconnect(KickReason reason); ///< Disconnect with a reason
        void disconnectNow(); ///< Disconnect now not awaiting ACK

        void reset(); ///< Reset the host
        void reset(KickReason reason); ///< Reset the host with a reason

    private:
        void receive(const ENetPacket &packet, enet_uint8 channelID) const;

        ENetHost *m_enetClient;
        ENetPeer *m_serverPeer;

        MessageReceiver *m_messageReceiver;
        ConnectionReceiver *m_connectionReceiver;
};

#endif
