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


#include <WiFiClient.h>
#include <WiFiServer.h>

#include <eCxx/Platform/NodeMCU/TCPClientServer.h>


namespace eCxx {


//
// 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
//
TCPClient::TCPClient()
: _wifiClient( new WiFiClient() )
{}


TCPClient::TCPClient(const TCPClient& tcpClient)
: _wifiClient( new WiFiClient(*tcpClient._wifiClient) )
{}


TCPClient::TCPClient(TCPClient&& tcpClient)
: _wifiClient( new WiFiClient(*tcpClient._wifiClient) )
{}


TCPClient::TCPClient(const WiFiClient& wifiClient)
: _wifiClient( new WiFiClient(wifiClient) )
{}


TCPClient::~TCPClient()
{ delete _wifiClient; }


TCPClient& TCPClient::operator=(const TCPClient& tcpClient)
{
    *_wifiClient = *tcpClient._wifiClient;
    return *this;
}


TCPClient& TCPClient::operator=(TCPClient&& tcpClient)
{
    *_wifiClient = *tcpClient._wifiClient;
    return *this;
}


bool TCPClient::begin(NodeMCU::IPAddress ip, uint16_t port)
{ return _wifiClient->connect(ip, port); }


bool TCPClient::begin(const char* host, uint16_t port)
{ return _wifiClient->connect(host, port); }


bool TCPClient::begin(const NodeMCU::WString& host, uint16_t port)
{ return _wifiClient->connect(host, port); }


void TCPClient::end()
{ _wifiClient->stop(); }


void TCPClient::setKeepAlive(uint16_t idleSec, uint8_t intvSec, uint8_t probCnt)
{ _wifiClient->keepAlive(idleSec, intvSec, probCnt); }


TCPState TCPClient::state() const
{ return static_cast<TCPState>( _wifiClient->status() ); }


bool TCPClient::connected() const
{ return _wifiClient->connected(); }


const NodeMCU::IPAddress TCPClient::remoteIP() const
{ return _wifiClient->remoteIP(); }


uint16_t TCPClient::remotePort() const
{ return _wifiClient->remotePort(); }


const NodeMCU::IPAddress TCPClient::localIP() const
{ return _wifiClient->localIP(); }


uint16_t TCPClient::localPort() const
{ return _wifiClient->localPort(); }


bool TCPClient::canRead() const
{ return _wifiClient->available() > 0; }


size_t TCPClient::availableForRead() const
{ return _wifiClient->available(); }


bool TCPClient::read(uint8_t& value)
{
    const int32_t c = _wifiClient->read();
    value = c;

    return c >= 0;
}


size_t TCPClient::read(uint8_t* buf, size_t size)
{ return _wifiClient->read(buf, size); }


bool TCPClient::peek(uint8_t& value) const
{
    const int32_t c = _wifiClient->peek();
    value = c;

    return c >= 0;
}


size_t TCPClient::peek(uint8_t* buf, size_t size) const
{ return _wifiClient->peekBytes(buf, size); }


bool TCPClient::canWrite() const
{ return _wifiClient->availableForWrite() > 0; }


size_t TCPClient::availableForWrite() const
{ return _wifiClient->availableForWrite(); }


bool TCPClient::write(uint8_t value)
{ return _wifiClient->write(value) == 1; }


size_t TCPClient::write(const uint8_t* buf, size_t size)
{ return _wifiClient->write(buf, size); }


size_t TCPClient::write(PGMCharPointer buf, size_t size)
{ return _wifiClient->write_P(buf.p, size); }


void TCPClient::flush()
{ _wifiClient->flush(); }


//
// 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
//
TCPServer::TCPServer(uint16_t port)
: _wifiServer( new WiFiServer(port) )
{}


TCPServer::~TCPServer()
{ delete _wifiServer; }


void TCPServer::begin(bool enableGlobalServerNoDelay)
{
    _wifiServer->begin();
    _wifiServer->setNoDelay(enableGlobalServerNoDelay);
}


void TCPServer::end()
{ _wifiServer->close(); }


TCPState TCPServer::state() const
{ return static_cast<TCPState>( _wifiServer->status() ); }


TCPClient TCPServer::handleClient(bool enableClientNoDelay)
{
    WiFiClient wifiClient = _wifiServer->available();
    wifiClient.setNoDelay(enableClientNoDelay);

    TCPClient tcpClient(wifiClient);
    return tcpClient;
}


} // namespace eCxx
