/*
 * 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_WEB_SERVER_TPP
#define ECXX_PLATFORM_NODEMCU_WEB_SERVER_TPP


#include <ESP8266WebServer.h>

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


namespace eCxx {


//
// HTTP upload structure
//
inline HTTPUpload::HTTPUpload(
    HTTPUploadStatus        status_,
    const NodeMCU::WString& name_,
    const NodeMCU::WString& type_,
    const NodeMCU::WString& fileName_,
    size_t                  totalSize_,
    size_t                  currentSize_,
    size_t                  contentLength_,
    const uint8_t* const    buffer_
)
: status       (status_       )
, name         (name_         )
, type         (type_         )
, fileName     (fileName_     )
, totalSize    (totalSize_    )
, currentSize  (currentSize_  )
, contentLength(contentLength_)
, buffer       (buffer_       )
{}


//
// A simple and thin wrapper class for NodeMCU's ESP8266WebServer class so that the public API
// will appear more consistent with other eCxx library APIs
//
template <typename WebServerImplT>
BasicWebServer<WebServerImplT>::BasicWebServer(uint16_t port)
: _webServer( new WebServerImplT(port) )
{}


template <typename WebServerImplT>
BasicWebServer<WebServerImplT>::~BasicWebServer()
{ delete _webServer; }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::begin()
{ _webServer->begin(); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::end()
{ _webServer->close(); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::enableCrossOriginRequest(bool enabled)
{ _webServer->enableCORS(enabled); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::handleClient()
{ _webServer->handleClient(); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::onNotFound(HandlerFunction hfn)
{ _webServer->onNotFound(hfn); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::on(const URI& uri, HandlerFunction hfn)
{ _webServer->on(uri, hfn); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::on(const URI& uri, HTTPRequestMethod method, HandlerFunction hfn)
{ _webServer->on(uri, static_cast<::HTTPMethod>(method), hfn); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::on(const URI& uri, HTTPRequestMethod method, HandlerFunction hfn, HandlerFunction hfnUpload)
{ _webServer->on(uri, static_cast<::HTTPMethod>(method), hfn, hfnUpload); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::serveStaticFileFromInternalFlash(const char* uri, const char* path, const char* cacheHeader)
{ _webServer->serveStatic(uri, LittleFS, path, cacheHeader); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::uri() const
{ return _webServer->uri(); }


template <typename WebServerImplT>
HTTPRequestMethod BasicWebServer<WebServerImplT>::method() const
{ return static_cast<HTTPRequestMethod>( _webServer->method() ); }


template <typename WebServerImplT>
const HTTPUpload BasicWebServer<WebServerImplT>::httpUpload()
{
    ::HTTPUpload tmp = _webServer->upload();

    return HTTPUpload(
        static_cast<HTTPUploadStatus>(tmp.status),
        tmp.name,
        tmp.type,
        tmp.filename,
        tmp.totalSize,
        tmp.currentSize,
        tmp.contentLength,
        tmp.buf
    );
}


template <typename WebServerImplT>
uint8_t BasicWebServer<WebServerImplT>::headerCount() const
{ return _webServer->headers(); }


template <typename WebServerImplT>
bool BasicWebServer<WebServerImplT>::hasHeaderName(const WString& name) const
{ return _webServer->hasHeader(name); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::headerName(uint8_t i) const
{ return _webServer->headerName(i); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::headerValue(uint8_t i) const
{ return _webServer->header(i); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::headerValue(const WString& name) const
{ return _webServer->header(name); }


template <typename WebServerImplT>
uint8_t BasicWebServer<WebServerImplT>::argCount() const
{ return _webServer->args(); }


template <typename WebServerImplT>
bool BasicWebServer<WebServerImplT>::hasArgName(const WString& name) const
{ return _webServer->hasArg(name); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::argName(uint8_t i) const
{ return _webServer->argName(i); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::argValue(uint8_t i) const
{ return _webServer->arg(i); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::argValue(const WString& name) const
{ return _webServer->arg(name); }


template <typename WebServerImplT>
const WString& BasicWebServer<WebServerImplT>::pathArgValue(uint8_t i) const
{ return _webServer->pathArg(i); }


template <typename WebServerImplT>
bool BasicWebServer<WebServerImplT>::authenticate(const char* username, const char* password)
{ return _webServer->authenticate(username, password); }


template <typename WebServerImplT>
bool BasicWebServer<WebServerImplT>::authenticateDigest(const char* username, const char* hash)
{ return _webServer->authenticateDigest(username, hash); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::requestAuthentication(HTTPAuthMethod mode, const char* realm, const char* onFailMessage)
{ _webServer->requestAuthentication( static_cast<::HTTPAuthMethod>(mode), realm, onFailMessage ); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code)
{ _webServer->send(code); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code, const char* contentType, const char* content)
{ _webServer->send( code, contentType, content ? WString(content) : (::emptyString) ); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code, const WString& contentType, WString& content)
{ _webServer->send(code, contentType, content); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code, const WString& contentType, const WString& content)
{ _webServer->send(code, contentType, content); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code, PGMCharPointer contentType, PGMCharPointer content)
{ _webServer->send_P(code, contentType.p, content.p); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::send(int16_t code, PGMCharPointer contentType, PGMCharPointer content, size_t contentLength)
{ _webServer->send_P(code, contentType.p, content.p, contentLength); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::setContentLength(const size_t contentLength)
{ _webServer->setContentLength(contentLength); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendHeader(const WString& name, const WString& value, bool first)
{ _webServer->sendHeader(name, value, first); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendContent(const WString& content)
{ _webServer->sendContent(content); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendContent(const char* content)
{ _webServer->sendContent(content); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendContent(const char* content, size_t size)
{ _webServer->sendContent(content, size); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendContent(PGMCharPointer content)
{ _webServer->sendContent_P(content.p); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::sendContent(PGMCharPointer content, size_t size)
{ _webServer->sendContent_P(content.p, size); }


template <typename WebServerImplT>
bool BasicWebServer<WebServerImplT>::beginChunkedResponseMode(int16_t code, PGMCharPointer contentType)
{ return _webServer->chunkedResponseModeStart_P(code, contentType.p); }


template <typename WebServerImplT>
void BasicWebServer<WebServerImplT>::endChunkedResponseMode()
{ _webServer->chunkedResponseFinalize(); }


template <typename WebServerImplT>
size_t BasicWebServer<WebServerImplT>::streamFile(NodeMCU::FileSystem::File& file, const WString& contentType, HTTPRequestMethod requestMethod)
{ return _webServer->streamFile( file, contentType, static_cast<::HTTPMethod>(requestMethod) ); }


template <typename WebServerImplT>
size_t BasicWebServer<WebServerImplT>::streamFileFromInternalFlash(const char* path, const WString& contentType, HTTPRequestMethod requestMethod)
{
    NodeMCU::FileSystem::File file = Application::nvOpenFileForReading(path);

    const size_t result = streamFile(file, contentType, requestMethod);

    file.close();

    return result;
}


template <typename WebServerImplT>
const WString BasicWebServer<WebServerImplT>::urlDecode(const WString& text)
{ return WebServerImplT::urlDecode(text); }


template <typename WebServerImplT>
const WString BasicWebServer<WebServerImplT>::responseCodeToString(int16_t code)
{ return WebServerImplT::responseCodeToString(code); }


} // namespace eCxx


#endif
