/*
 * Copyright (C) 2021 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 "WebAutomationSessionProxy.h"

#include "ArgumentCoders.h"
#include "CoordinateSystem.h"
#include "Decoder.h"
#include "HandleMessage.h"
#include "WebAutomationSessionProxyMessages.h"
#include "WebCoreArgumentCoders.h"
#include <WebCore/Cookie.h>
#include <WebCore/FrameIdentifier.h>
#include <WebCore/IntPoint.h>
#include <WebCore/IntRect.h>
#include <WebCore/PageIdentifier.h>
#include <optional>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>

namespace Messages {

namespace WebAutomationSessionProxy {

void ResolveChildFrameWithOrdinal::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<std::optional<WebCore::FrameIdentifier>> frameID;
    decoder >> frameID;
    if (!frameID) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*frameID));
}

void ResolveChildFrameWithOrdinal::cancelReply(CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<std::optional<WebCore::FrameIdentifier>>::create());
}

void ResolveChildFrameWithOrdinal::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const std::optional<WebCore::FrameIdentifier>& frameID)
{
    encoder.get() << errorType;
    encoder.get() << frameID;
    connection.sendSyncReply(WTFMove(encoder));
}

void ResolveChildFrameWithNodeHandle::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<std::optional<WebCore::FrameIdentifier>> frameID;
    decoder >> frameID;
    if (!frameID) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*frameID));
}

void ResolveChildFrameWithNodeHandle::cancelReply(CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<std::optional<WebCore::FrameIdentifier>>::create());
}

void ResolveChildFrameWithNodeHandle::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const std::optional<WebCore::FrameIdentifier>& frameID)
{
    encoder.get() << errorType;
    encoder.get() << frameID;
    connection.sendSyncReply(WTFMove(encoder));
}

void ResolveChildFrameWithName::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<std::optional<WebCore::FrameIdentifier>> frameID;
    decoder >> frameID;
    if (!frameID) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*frameID));
}

void ResolveChildFrameWithName::cancelReply(CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<std::optional<WebCore::FrameIdentifier>>::create());
}

void ResolveChildFrameWithName::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const std::optional<WebCore::FrameIdentifier>& frameID)
{
    encoder.get() << errorType;
    encoder.get() << frameID;
    connection.sendSyncReply(WTFMove(encoder));
}

void ResolveParentFrame::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<std::optional<WebCore::FrameIdentifier>> frameID;
    decoder >> frameID;
    if (!frameID) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*frameID));
}

void ResolveParentFrame::cancelReply(CompletionHandler<void(std::optional<String>&&, std::optional<WebCore::FrameIdentifier>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<std::optional<WebCore::FrameIdentifier>>::create());
}

void ResolveParentFrame::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const std::optional<WebCore::FrameIdentifier>& frameID)
{
    encoder.get() << errorType;
    encoder.get() << frameID;
    connection.sendSyncReply(WTFMove(encoder));
}

void ComputeElementLayout::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, WebCore::IntRect&&, std::optional<WebCore::IntPoint>&&, bool&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<WebCore::IntRect> rect;
    decoder >> rect;
    if (!rect) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<std::optional<WebCore::IntPoint>> inViewCenterPoint;
    decoder >> inViewCenterPoint;
    if (!inViewCenterPoint) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<bool> isObscured;
    decoder >> isObscured;
    if (!isObscured) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*rect), WTFMove(*inViewCenterPoint), WTFMove(*isObscured));
}

void ComputeElementLayout::cancelReply(CompletionHandler<void(std::optional<String>&&, WebCore::IntRect&&, std::optional<WebCore::IntPoint>&&, bool&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<WebCore::IntRect>::create(), IPC::AsyncReplyError<std::optional<WebCore::IntPoint>>::create(), IPC::AsyncReplyError<bool>::create());
}

void ComputeElementLayout::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const WebCore::IntRect& rect, const std::optional<WebCore::IntPoint>& inViewCenterPoint, bool isObscured)
{
    encoder.get() << errorType;
    encoder.get() << rect;
    encoder.get() << inViewCenterPoint;
    encoder.get() << isObscured;
    connection.sendSyncReply(WTFMove(encoder));
}

void SelectOptionElement::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType));
}

void SelectOptionElement::cancelReply(CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create());
}

void SelectOptionElement::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType)
{
    encoder.get() << errorType;
    connection.sendSyncReply(WTFMove(encoder));
}

void SetFilesForInputFileUpload::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType));
}

void SetFilesForInputFileUpload::cancelReply(CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create());
}

void SetFilesForInputFileUpload::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType)
{
    encoder.get() << errorType;
    connection.sendSyncReply(WTFMove(encoder));
}

void SnapshotRectForScreenshot::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, WebCore::IntRect&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<WebCore::IntRect> rect;
    decoder >> rect;
    if (!rect) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*rect));
}

void SnapshotRectForScreenshot::cancelReply(CompletionHandler<void(std::optional<String>&&, WebCore::IntRect&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<WebCore::IntRect>::create());
}

void SnapshotRectForScreenshot::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const WebCore::IntRect& rect)
{
    encoder.get() << errorType;
    encoder.get() << rect;
    connection.sendSyncReply(WTFMove(encoder));
}

void GetCookiesForFrame::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&, Vector<WebCore::Cookie>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    std::optional<Vector<WebCore::Cookie>> cookies;
    decoder >> cookies;
    if (!cookies) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType), WTFMove(*cookies));
}

void GetCookiesForFrame::cancelReply(CompletionHandler<void(std::optional<String>&&, Vector<WebCore::Cookie>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create(), IPC::AsyncReplyError<Vector<WebCore::Cookie>>::create());
}

void GetCookiesForFrame::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType, const Vector<WebCore::Cookie>& cookies)
{
    encoder.get() << errorType;
    encoder.get() << cookies;
    connection.sendSyncReply(WTFMove(encoder));
}

void DeleteCookie::callReply(IPC::Decoder& decoder, CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    std::optional<std::optional<String>> errorType;
    decoder >> errorType;
    if (!errorType) {
        ASSERT_NOT_REACHED();
        cancelReply(WTFMove(completionHandler));
        return;
    }
    completionHandler(WTFMove(*errorType));
}

void DeleteCookie::cancelReply(CompletionHandler<void(std::optional<String>&&)>&& completionHandler)
{
    completionHandler(IPC::AsyncReplyError<std::optional<String>>::create());
}

void DeleteCookie::send(UniqueRef<IPC::Encoder>&& encoder, IPC::Connection& connection, const std::optional<String>& errorType)
{
    encoder.get() << errorType;
    connection.sendSyncReply(WTFMove(encoder));
}

} // namespace WebAutomationSessionProxy

} // namespace Messages

namespace WebKit {

void WebAutomationSessionProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
{
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::EvaluateJavaScriptFunction::name())
        return IPC::handleMessage<Messages::WebAutomationSessionProxy::EvaluateJavaScriptFunction>(connection, decoder, this, &WebAutomationSessionProxy::evaluateJavaScriptFunction);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::ResolveChildFrameWithOrdinal::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::ResolveChildFrameWithOrdinal>(connection, decoder, this, &WebAutomationSessionProxy::resolveChildFrameWithOrdinal);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::ResolveChildFrameWithNodeHandle::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::ResolveChildFrameWithNodeHandle>(connection, decoder, this, &WebAutomationSessionProxy::resolveChildFrameWithNodeHandle);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::ResolveChildFrameWithName::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::ResolveChildFrameWithName>(connection, decoder, this, &WebAutomationSessionProxy::resolveChildFrameWithName);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::ResolveParentFrame::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::ResolveParentFrame>(connection, decoder, this, &WebAutomationSessionProxy::resolveParentFrame);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::ComputeElementLayout::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::ComputeElementLayout>(connection, decoder, this, &WebAutomationSessionProxy::computeElementLayout);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::SelectOptionElement::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::SelectOptionElement>(connection, decoder, this, &WebAutomationSessionProxy::selectOptionElement);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::SetFilesForInputFileUpload::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::SetFilesForInputFileUpload>(connection, decoder, this, &WebAutomationSessionProxy::setFilesForInputFileUpload);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::TakeScreenshot::name())
        return IPC::handleMessage<Messages::WebAutomationSessionProxy::TakeScreenshot>(connection, decoder, this, &WebAutomationSessionProxy::takeScreenshot);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::SnapshotRectForScreenshot::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::SnapshotRectForScreenshot>(connection, decoder, this, &WebAutomationSessionProxy::snapshotRectForScreenshot);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::GetCookiesForFrame::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::GetCookiesForFrame>(connection, decoder, this, &WebAutomationSessionProxy::getCookiesForFrame);
    if (decoder.messageName() == Messages::WebAutomationSessionProxy::DeleteCookie::name())
        return IPC::handleMessageAsync<Messages::WebAutomationSessionProxy::DeleteCookie>(connection, decoder, this, &WebAutomationSessionProxy::deleteCookie);
    UNUSED_PARAM(connection);
    UNUSED_PARAM(decoder);
#if ENABLE(IPC_TESTING_API)
    if (connection.ignoreInvalidMessageForTesting())
        return;
#endif // ENABLE(IPC_TESTING_API)
    ASSERT_NOT_REACHED_WITH_MESSAGE("Unhandled message %s to %" PRIu64, IPC::description(decoder.messageName()), decoder.destinationID());
}

} // namespace WebKit
