#pragma once
#include "AftrConfig.h"
#ifdef AFTR_CONFIG_USE_BOOST

#include <string>
#include <boost/asio.hpp>

namespace Aftr
{

class NetMsg;


//The NetMessengerClient primarily sends TCP or UDP packets to an endpoint. The client can block for a reply,
//but that may be slow, so the typical use case is for the Module to:
// 
// callback_on_NetMsgT_arrived<NetMsgMyAwesomeMsg> callback = [this]( auto msg ) //auto msg is actually a std::shared_ptr<NetMsgMyAwesomeMsg> msg
// {
//   //fmt::print( "NetMsgUpdatePose arrived {:s}\n", msg->toString() );
//   ...do something w/ the data in the msg...
// };
//
//After the specific callback is created, we register that callback with the Module (for example in the GLView's loadMap()).
//Without doing this step, the callback is never invoked.
// 
// this->subscribe_NetMsg_to_callback<NetMsgMyAwesomeMsg>( callback );

class NetMessengerClient
{
public:
   static std::shared_ptr<NetMessengerClient> New( const std::string& host = "127.0.0.1", const std::string& port = "12683" );
   virtual ~NetMessengerClient();

   /// Sends a message from this client to the client's specified end point (host:port).
   /// Any replies generated will be received by the NetMessengerServerListener.
   virtual void sendNetMsgSynchronousTCP( const NetMsg& msg );
   virtual std::shared_ptr<NetMsg> sendNetMsgBlockForReplyTCP( const NetMsg& msg );

   virtual void sendNetMsgSynchronousUDP( const NetMsg& msg );
   virtual std::shared_ptr<NetMsg> sendNetMsgBlockForReplyUDP( const NetMsg& msg );

   bool isTCPSocketOpen() const;
   bool reconnect();

   std::string getLocalIpAddressesStrings() const;
   std::vector< boost::asio::ip::udp::endpoint > getLocalIpAddresses();

   std::shared_ptr<boost::asio::ip::udp::socket > getUDPSocket() { return this->udpSock; }
   boost::asio::ip::udp::endpoint& getUDPEndPoint() { return this->udpEp; }

   std::shared_ptr< boost::asio::ip::tcp::socket > getTCPSocket() { return this->tcpSock; }
   boost::asio::ip::tcp::endpoint& getTCPEndPoint() { return this->tcpEp; }

protected:
   NetMessengerClient( const std::string& host, const std::string& port );
   virtual void onCreate();

   std::string host = "";
   std::string port = "";
   std::unique_ptr< boost::asio::io_context > ioService; ///< Boost's abstraction layer to the OS
   std::shared_ptr < boost::asio::ip::tcp::socket > tcpSock;
   boost::asio::ip::tcp::endpoint tcpEp;
   bool tcpSockIsConnected = false;
   std::shared_ptr<boost::asio::ip::udp::socket> udpSock;
   boost::asio::ip::udp::endpoint udpEp;
   constexpr static unsigned int BUFF_SIZE = 16384;
   std::shared_ptr<char[]> recvBuff;
};



} //namespace Aftr

#endif //AFTR_CONFIG_USE_BOOST
