/*
 * 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>
#include <eCxx/Platform/NodeMCU/TCPConsole.h>


namespace eCxx {


TCPConsole::TCPConsole(uint16_t portConsole, uint16_t portDummyWeb)
: _tcpDummyWebServer( portDummyWeb ? new WiFiServer(portDummyWeb) : nullptr )
, _tcpConsoleServer (                new WiFiServer(portConsole )           )
, _tcpConsoleClient (                new WiFiClient                         )
{}


TCPConsole::~TCPConsole()
{
    end();

                           delete _tcpConsoleClient;
                           delete _tcpConsoleServer;
    if(_tcpDummyWebServer) delete _tcpDummyWebServer;
}


void TCPConsole::begin()
{
    if(_tcpDummyWebServer) _tcpDummyWebServer->begin();
                           _tcpConsoleServer ->begin();
}


void TCPConsole::end()
{
                           _tcpConsoleServer ->close();
    if(_tcpDummyWebServer) _tcpDummyWebServer->close();
}


void TCPConsole::handle()
{
    // Accept connection for the TCP console server
    if( !_tcpConsoleClient->connected() ) {
        *_tcpConsoleClient = _tcpConsoleServer->available();
        if( _tcpConsoleClient->connected() ) {
            _tcpConsoleClient->keepAlive(
                TCPClient::DefaultKeepAlive_IdleSec,
                TCPClient::DefaultKeepAlive_IntvSec,
                TCPClient::DefaultKeepAlive_ProbCnt
            );
        }
    }

    // We are done here if the dummy web server is not enabled
    if(!_tcpDummyWebServer) return;

    // Simply answer OK and close the connection for the dummy web server
    static const char PROGMEM res[] =
        "HTTP/1.1 200 OK\r\n"
        "Content-Length: 0\r\n"
        "Content-Type: text/plain\r\n"
        "Connection: close\r\n\r\n";

    WiFiClient&& dummyWeb = _tcpDummyWebServer->available();
    if( !dummyWeb.connected() ) return;

    dummyWeb.write_P( res, sizeof(res) - 1 );
    dummyWeb.stop();
}


bool TCPConsole::canRead() const
{ return _tcpConsoleClient->connected() ? (_tcpConsoleClient->available() > 0) : false; }


bool TCPConsole::read(uint8_t& value)
{
    if( !_tcpConsoleClient->connected() ) return false;

    const int32_t ch = _tcpConsoleClient->read();
    if(ch < 0) return false;

    value = ch;
    return true;
}


bool TCPConsole::peek(uint8_t& value) const
{
    if( !_tcpConsoleClient->connected() ) return false;

    const int32_t ch = _tcpConsoleClient->peek();
    if(ch < 0) return false;

    value = ch;
    return true;
}


bool TCPConsole::canWrite() const
{ return _tcpConsoleClient->connected() ? (_tcpConsoleClient->availableForWrite() > 0) : false; }


bool TCPConsole::write(uint8_t value)
{ return _tcpConsoleClient->connected() ? (_tcpConsoleClient->write(value) == 1) : false; }


void TCPConsole::flush()
{ if( _tcpConsoleClient->connected() ) _tcpConsoleClient->flush(); }


} // namespace eCxx
