/*
 * 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_STREAM_SLOT_FS_H
#define ECXX_PLATFORM_NODEMCU_WEB_SERVER_STREAM_SLOT_FS_H


#include "../SlotFS.h"

#include "WebServer.h"


namespace eCxx {


//
// Stream data (file) from SlotFS to web server
//      # In case the file is not found or cannot be read, it will return eCxx::NumericLimits<uint32_t>::max()
//      # Otherwise, it will return the number of bytes written
//
template <typename WebServerImplT>
inline uint32_t streamFileToWebServerFromSlotFS(BasicWebServer<WebServerImplT>& webServer, SlotFS& slotFS, const char* userID, const WString& contentType, HTTPRequestMethod requestMethod = HTTPRequestMethod::Get, uint32_t* actualFileSizeRet = nullptr)
{
    // Find the slot number
    const uint16_t slotNumber = slotFS.findFirstSlotNumberByUserID(userID);
    if(slotNumber == SlotFS::InvalidSlotNumber) return eCxx::NumericLimits<uint32_t>::max();

    // Open the slot for reading
    SlotFS::SlotHandle handle = slotFS.slotReadOpen(slotNumber);
    if(!handle) return eCxx::NumericLimits<uint32_t>::max();

    // Get the available byte size
    const uint32_t slotByteSize = slotFS.slotReadRemainingBytesAvailable(handle);

    // Return the actual file size as needed
    if(actualFileSizeRet) *actualFileSizeRet = slotByteSize;

    // Copy the user ID as the path name
    const WString path = userID;

    // Set content length
    webServer.setContentLength(slotByteSize);

    // Send the gzip content encoding as needed
    if( path.endsWith( WString( eCxx::PGM_PTR( WebServer::MimeTable[WebServer::MIME::gz  ].endsWith ) ) ) &&
        contentType != WString( eCxx::PGM_PTR( WebServer::MimeTable[WebServer::MIME::gz  ].mimeType ) )   &&
        contentType != WString( eCxx::PGM_PTR( WebServer::MimeTable[WebServer::MIME::none].mimeType ) )
    ) {
        webServer.sendHeader( PGM_STR("Content-Encoding"), PGM_STR("gzip") );
    }

    // Send the content type
    webServer.send(200, contentType, emptyString);

    // Stream the content for HTTP GET request only
    uint32_t contentLength = 0;

    if(requestMethod == HTTPRequestMethod::Get && slotByteSize) {
        // Read buffer
        uint8_t readBuff[256];
        // Loop until all the bytes are sent
        for(;;) {
            // Read bytes and check for error
            const uint16_t readSize = slotFS.slotReadGet( handle, readBuff, sizeof(readBuff) );
            if(!readSize) break;
            // Send the bytes
            webServer.sendContent( reinterpret_cast<const char*>(readBuff), readSize );
            // Accumulate the sent size
            contentLength += readSize;
            // Yield
            Application::yield();
        }
    }

    // Close the slot
    slotFS.slotClose(handle);

    // Return the sent size
    return contentLength;
}


} // namespace eCxx


#endif
