#pragma once
#include "DOMFormData.h"
#include "FetchBodyConsumer.h"
#include "FormData.h"
#include "JSDOMPromiseDeferred.h"
#include "ReadableStream.h"
#include "URLSearchParams.h"
#include <wtf/Variant.h>
namespace WebCore {
class FetchBodyOwner;
class FetchBodySource;
class ScriptExecutionContext;
class FetchBody {
public:
void arrayBuffer(FetchBodyOwner&, Ref<DeferredPromise>&&);
void blob(FetchBodyOwner&, Ref<DeferredPromise>&&, const String&);
void json(FetchBodyOwner&, Ref<DeferredPromise>&&);
void text(FetchBodyOwner&, Ref<DeferredPromise>&&);
void formData(FetchBodyOwner&, Ref<DeferredPromise>&& promise) { promise.get().reject(NotSupportedError); }
#if ENABLE(STREAMS_API)
void consumeAsStream(FetchBodyOwner&, FetchBodySource&);
#endif
using Init = Variant<RefPtr<Blob>, RefPtr<ArrayBufferView>, RefPtr<ArrayBuffer>, RefPtr<DOMFormData>, RefPtr<URLSearchParams>, RefPtr<ReadableStream>, String>;
static FetchBody extract(ScriptExecutionContext&, Init&&, String&);
FetchBody() = default;
WEBCORE_EXPORT static std::optional<FetchBody> fromFormData(FormData&);
void loadingFailed();
void loadingSucceeded();
RefPtr<FormData> bodyAsFormData(ScriptExecutionContext&) const;
using TakenData = Variant<std::nullptr_t, Ref<FormData>, Ref<SharedBuffer>>;
TakenData take();
void setAsFormData(Ref<FormData>&& data) { m_data = WTFMove(data); }
FetchBodyConsumer& consumer() { return m_consumer; }
void consumeOnceLoadingFinished(FetchBodyConsumer::Type, Ref<DeferredPromise>&&, const String&);
void cleanConsumer() { m_consumer.clean(); }
FetchBody clone();
bool hasReadableStream() const { return !!m_readableStream; }
const ReadableStream* readableStream() const { return m_readableStream.get(); }
ReadableStream* readableStream() { return m_readableStream.get(); }
void setReadableStream(Ref<ReadableStream>&& stream)
{
ASSERT(!m_readableStream);
m_readableStream = WTFMove(stream);
}
bool isBlob() const { return WTF::holds_alternative<Ref<const Blob>>(m_data); }
bool isFormData() const { return WTF::holds_alternative<Ref<FormData>>(m_data); }
private:
explicit FetchBody(Ref<const Blob>&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(Ref<const ArrayBuffer>&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(Ref<const ArrayBufferView>&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(Ref<FormData>&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(String&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(Ref<const URLSearchParams>&& data) : m_data(WTFMove(data)) { }
explicit FetchBody(const FetchBodyConsumer& consumer) : m_consumer(consumer) { }
explicit FetchBody(Ref<ReadableStream>&& stream) : m_readableStream(WTFMove(stream)) { }
void consume(FetchBodyOwner&, Ref<DeferredPromise>&&);
void consumeArrayBuffer(Ref<DeferredPromise>&&);
void consumeArrayBufferView(Ref<DeferredPromise>&&);
void consumeText(Ref<DeferredPromise>&&, const String&);
void consumeBlob(FetchBodyOwner&, Ref<DeferredPromise>&&);
bool isArrayBuffer() const { return WTF::holds_alternative<Ref<const ArrayBuffer>>(m_data); }
bool isArrayBufferView() const { return WTF::holds_alternative<Ref<const ArrayBufferView>>(m_data); }
bool isURLSearchParams() const { return WTF::holds_alternative<Ref<const URLSearchParams>>(m_data); }
bool isText() const { return WTF::holds_alternative<String>(m_data); }
const Blob& blobBody() const { return WTF::get<Ref<const Blob>>(m_data).get(); }
FormData& formDataBody() { return WTF::get<Ref<FormData>>(m_data).get(); }
const FormData& formDataBody() const { return WTF::get<Ref<FormData>>(m_data).get(); }
const ArrayBuffer& arrayBufferBody() const { return WTF::get<Ref<const ArrayBuffer>>(m_data).get(); }
const ArrayBufferView& arrayBufferViewBody() const { return WTF::get<Ref<const ArrayBufferView>>(m_data).get(); }
String& textBody() { return WTF::get<String>(m_data); }
const String& textBody() const { return WTF::get<String>(m_data); }
const URLSearchParams& urlSearchParamsBody() const { return WTF::get<Ref<const URLSearchParams>>(m_data).get(); }
using Data = Variant<std::nullptr_t, Ref<const Blob>, Ref<FormData>, Ref<const ArrayBuffer>, Ref<const ArrayBufferView>, Ref<const URLSearchParams>, String>;
Data m_data { nullptr };
FetchBodyConsumer m_consumer { FetchBodyConsumer::Type::None };
RefPtr<ReadableStream> m_readableStream;
};
}