/*
 * Copyright (C) 2022 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "FormDataConsumer.h"

#include "BlobLoader.h"
#include "FormData.h"
#include <wtf/WorkQueue.h>

namespace WebCore {

FormDataConsumer::FormDataConsumer(const FormData& formData, ScriptExecutionContext& context, Callback&& callback)
    : m_formData(formData.copy())
    , m_context(&context)
    , m_callback(WTFMove(callback))
    , m_fileQueue(WorkQueue::create("FormDataConsumer file queue"))
{
    read();
}

FormDataConsumer::~FormDataConsumer()
{
}

void FormDataConsumer::read()
{
    if (isCancelled())
        return;

    ASSERT(m_callback);
    ASSERT(!m_blobLoader);

    if (m_currentElementIndex >= m_formData->elements().size()) {
        m_callback(Span<const uint8_t> { });
        return;
    }

    switchOn(m_formData->elements()[m_currentElementIndex++].data, [this](const Vector<uint8_t>& content) {
        consumeData(content);
    }, [this](const FormDataElement::EncodedFileData& fileData) {
        consumeFile(fileData.filename);
    }, [this](const FormDataElement::EncodedBlobData& blobData) {
        consumeBlob(blobData.url);
    });
}

void FormDataConsumer::consumeData(const Vector<uint8_t>& content)
{
    consume(content.span());
}

void FormDataConsumer::consumeFile(const String& filename)
{
    m_fileQueue->dispatch([weakThis = WeakPtr { *this }, identifier = m_context->identifier(), path = filename.isolatedCopy()]() mutable {
        ScriptExecutionContext::postTaskTo(identifier, [weakThis = WTFMove(weakThis), content = FileSystem::readEntireFile(path)](auto&) {
            if (!weakThis)
                return;

            if (!content) {
                weakThis->didFail(Exception { InvalidStateError, "Unable to read form data file"_s });
                return;
            }

            weakThis->consume(*content);
        });
    });
}

void FormDataConsumer::consumeBlob(const URL& blobURL)
{
    m_blobLoader = makeUnique<BlobLoader>([weakThis = WeakPtr { *this }](BlobLoader&) mutable {
        if (!weakThis)
            return;

        auto loader = std::exchange(weakThis->m_blobLoader, { });
        if (!loader)
            return;

        if (auto optionalErrorCode = loader->errorCode()) {
            weakThis->didFail(Exception { InvalidStateError, "Failed to read form data blob"_s });
            return;
        }

        if (auto data = loader->arrayBufferResult())
            weakThis->consume(Span<const uint8_t> { static_cast<const uint8_t*>(data->data()), data->byteLength() });
    });

    m_blobLoader->start(blobURL, m_context.get(), FileReaderLoader::ReadAsArrayBuffer);

    if (!m_blobLoader || !m_blobLoader->isLoading())
        didFail(Exception { InvalidStateError, "Unable to read form data blob"_s });
}

void FormDataConsumer::consume(Span<const uint8_t> content)
{
    if (!m_callback)
        return;

    m_callback(WTFMove(content));
    if (!m_callback)
        return;

    read();
}

void FormDataConsumer::didFail(auto&& exception)
{
    auto callback = std::exchange(m_callback, nullptr);
    cancel();
    if (callback)
        callback(WTFMove(exception));
}

void FormDataConsumer::cancel()
{
    m_callback = nullptr;
    if (auto loader = std::exchange(m_blobLoader, { }))
        loader->cancel();
    m_context = nullptr;
}

} // namespace WebCore
