/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_PLATFORM_NODEMCU_TCP_SERVER_H
#define ECXX_PLATFORM_NODEMCU_TCP_SERVER_H


#include <eCxx/CTL/Types.h>

#include <IPAddress.h>
#include <WString.h>


//
// Forward declaration of WiFi client and server classes
//
class WiFiClient;
class WiFiServer;


namespace eCxx {


//
// TCP state
// NOTE : Synchronize with "src/eCxx/Platform/NodeMCU/libNodeMCU/libraries/ESP8266WiFi/src/include/wl_definitions.h"
//
enum class TCPState : uint8_t {
    Closed      =  0,
    Listen      =  1,
    SynSent     =  2,
    SynRcvd     =  3,
    Established =  4,
    FinWait1    =  5,
    FinWait2    =  6,
    CloseWait   =  7,
    Closing     =  8,
    LastAck     =  9,
    TimeWait    = 10
};


//
// A simple and thin wrapper class for NodeMCU's WiFiClient class so that the public API
// will appear more consistent with other eCxx library APIs
//
class TCPClient {
    public:
        static constexpr uint16_t DefaultKeepAlive_IdleSec = 5 * 3600;
        static constexpr uint8_t  DefaultKeepAlive_IntvSec = 60;
        static constexpr uint8_t  DefaultKeepAlive_ProbCnt = 10;


    public:
        TCPClient();
        TCPClient(const TCPClient& tcpClient);
        TCPClient(TCPClient&& tcpClient);
        ~TCPClient();

        TCPClient& operator=(const TCPClient& tcpClient);
        TCPClient& operator=(TCPClient&& tcpClient);

        bool begin(NodeMCU::IPAddress ip, uint16_t port);
        bool begin(const char* host, uint16_t port);
        bool begin(const NodeMCU::WString& host, uint16_t port);
        void end();

        void setKeepAlive(uint16_t idleSec = DefaultKeepAlive_IdleSec, uint8_t intvSec = DefaultKeepAlive_IntvSec, uint8_t probCnt = DefaultKeepAlive_ProbCnt);

        TCPState state() const;
        bool connected() const;

        const NodeMCU::IPAddress remoteIP() const;
        uint16_t remotePort() const;

        const NodeMCU::IPAddress localIP() const;
        uint16_t localPort() const;

        bool canRead() const;
        size_t availableForRead() const;
        bool read(uint8_t& value);
        size_t read(uint8_t* buf, size_t size);
        bool peek(uint8_t& value) const;
        size_t peek(uint8_t* buf, size_t size) const;

        bool canWrite() const;
        size_t availableForWrite() const;
        bool write(uint8_t value);
        size_t write(const uint8_t* buf, size_t size);
        size_t write(PGMCharPointer buf, size_t size);
        void flush();

    private:
        TCPClient(const WiFiClient& wifiClient);

    private:
        WiFiClient* _wifiClient;

        friend class TCPServer;
};


//
// A simple and thin wrapper class for NodeMCU's WiFiServer class so that the public API
// will appear more consistent with other eCxx library APIs
//
class TCPServer {
    public:
        TCPServer() = delete;

        TCPServer(const TCPServer& ) = delete;
        TCPServer(      TCPServer&&) = delete;

        TCPServer& operator=(const TCPServer& ) = delete;
        TCPServer& operator=(      TCPServer&&) = delete;

    public:
        TCPServer(uint16_t port);
        ~TCPServer();

        void begin(bool enableGlobalServerNoDelay = false);
        void end();

        TCPState state() const;

        TCPClient handleClient(bool enableClientNoDelay = false);

    private:
        WiFiServer* _wifiServer;
};


} // namespace eCxx


#endif
