/*
 * Copyright (C) 2019 Sony Interactive Entertainment Inc.
 *
 * 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 "RemoteInspectorProtocolHandler.h"

#if ENABLE(REMOTE_INSPECTOR)

#include "APILoaderClient.h"
#include "APINavigation.h"
#include "APIUserContentWorld.h"
#include "WebPageGroup.h"
#include "WebPageProxy.h"
#include "WebScriptMessageHandler.h"
#include "WebUserContentControllerProxy.h"
#include <WebCore/JSDOMExceptionHandling.h>
#include <WebCore/SerializedScriptValue.h>
#include <wtf/URL.h>
#include <wtf/text/StringBuilder.h>

namespace WebKit {

using namespace WebCore;

class ScriptMessageClient final : public WebScriptMessageHandler::Client {
    WTF_MAKE_FAST_ALLOCATED;
public:
    ScriptMessageClient(RemoteInspectorProtocolHandler& inspectorProtocolHandler)
        : m_inspectorProtocolHandler(inspectorProtocolHandler) { }

    ~ScriptMessageClient() { }

    void didPostMessage(WebPageProxy& page, FrameInfoData&&, WebCore::SerializedScriptValue& serializedScriptValue) override
    {
        auto tokens = serializedScriptValue.toString().split(":");
        if (tokens.size() != 3)
            return;

        URL requestURL { { }, page.pageLoadState().url() };
        m_inspectorProtocolHandler.inspect(requestURL.hostAndPort(), tokens[0].toUIntStrict(), tokens[1].toUIntStrict(), tokens[2]);
    }

private:
    RemoteInspectorProtocolHandler& m_inspectorProtocolHandler;
};

class LoaderClient final : public API::LoaderClient {
    WTF_MAKE_FAST_ALLOCATED;
public:
    LoaderClient(Function<void()>&& loadedCallback)
        : m_loadedCallback { WTFMove(loadedCallback) } { }

    void didFinishLoadForFrame(WebKit::WebPageProxy&, WebKit::WebFrameProxy&, API::Navigation*, API::Object*) final
    {
        m_loadedCallback();
    }

private:
    Function<void()> m_loadedCallback;
};

void RemoteInspectorProtocolHandler::inspect(const String& hostAndPort, ConnectionID connectionID, TargetID targetID, const String& type)
{
    if (m_inspectorClient)
        m_inspectorClient->inspect(connectionID, targetID, type);
}

void RemoteInspectorProtocolHandler::runScript(const String& script)
{
    m_page.runJavaScriptInMainFrame(script, false,
        [](API::SerializedScriptValue*, bool hadException, const WebCore::ExceptionDetails& exceptionDetails, CallbackBase::Error) {
            if (hadException)
                LOG_ERROR("Exception running script \"%s\"", exceptionDetails.message.utf8().data());
    });
}

void RemoteInspectorProtocolHandler::targetListChanged(RemoteInspectorClient& client)
{
    StringBuilder html;
    if (client.targets().isEmpty())
        html.append("<p>No targets found</p>"_s);
    else {
        html.append("<table>");
        for (auto& connectionID : client.targets().keys()) {
            for (auto& target : client.targets().get(connectionID)) {
                html.append(makeString(
                    "<tbody><tr>"
                    "<td class=\"data\"><div class=\"targetname\">", target.name, "</div><div class=\"targeturl\">", target.url, "</div></td>"
                    "<td class=\"input\"><input type=\"button\" value=\"Inspect\" onclick=\"window.webkit.messageHandlers.inspector.postMessage(\\'", connectionID, ":", target.id, ":", target.type, "\\');\"></td>"
                    "</tr></tbody>"
                ));
            }
        }
        html.append("</table>");
    }
    m_targetListsHtml = html.toString();
    if (m_pageLoaded)
        updateTargetList();
}

void RemoteInspectorProtocolHandler::updateTargetList()
{
    if (!m_targetListsHtml.isEmpty()) {
        runScript(makeString("updateTargets(`", m_targetListsHtml, "`);"));
        m_targetListsHtml = { };
    }
}

void RemoteInspectorProtocolHandler::platformStartTask(WebPageProxy& pageProxy, WebURLSchemeTask& task)
{
    auto& requestURL = task.request().url();

    // Destroy the client before creating a new connection so it can connect to the same port
    m_inspectorClient = nullptr;
    m_inspectorClient = makeUnique<RemoteInspectorClient>(requestURL, *this);

    // Setup target postMessage listener
    auto handler = WebScriptMessageHandler::create(makeUnique<ScriptMessageClient>(*this), "inspector", API::UserContentWorld::normalWorld());
    pageProxy.pageGroup().userContentController().addUserScriptMessageHandler(handler.get());

    // Setup loader client to get notified of page load
    m_page.setLoaderClient(makeUnique<LoaderClient>([this] {
        m_pageLoaded = true;
        updateTargetList();
    }));
    m_pageLoaded = false;

    StringBuilder htmlBuilder;
    htmlBuilder.append(
        "<html><head><title>Remote Inspector</title>"
        "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"
        "<style>"
        "  h1 { color: #babdb6; text-shadow: 0 1px 0 white; margin-bottom: 0; }"
        "  html { font-family: -webkit-system-font; font-size: 11pt; color: #2e3436; padding: 20px 20px 0 20px; background-color: #f6f6f4; "
        "         background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #eeeeec), color-stop(1, #f6f6f4));"
        "         background-size: 100% 5em; background-repeat: no-repeat; }"
        "  table { width: 100%; border-collapse: collapse; table-layout: fixed; }"
        "  table, td { border: 1px solid #d3d7cf; border-left: none; border-right: none; }"
        "  p { margin-bottom: 30px; }"
        "  td { padding: 15px; }"
        "  td.data { width: 200px; }"
        "  .targetname { font-weight: bold; overflow: hidden; white-space:nowrap; text-overflow: ellipsis; }"
        "  .targeturl { color: #babdb6; background: #eee; word-wrap: break-word; overflow-wrap: break-word; }"
        "  td.input { width: 64px; }"
        "  input { width: 100%; padding: 8px; }"
        "</style>"
        "</head><body><h1>Inspectable targets</h1>"
        "<div id=\"targetlist\"><p>No targets found</p></div></body>"
        "<script>"
        "function updateTargets(str) {"
            "let targetDiv = document.getElementById('targetlist');"
            "targetDiv.innerHTML = str;"
        "}"
        "</script>");
    htmlBuilder.append("</html>");

    auto html = htmlBuilder.toString().utf8();
    auto data = SharedBuffer::create(html.data(), html.length());
    ResourceResponse response(requestURL, "text/html"_s, html.length(), "UTF-8"_s);
    task.didReceiveResponse(response);
    task.didReceiveData(WTFMove(data));
    task.didComplete(ResourceError());
}

} // namespace WebKit

#endif // ENABLE(REMOTE_INSPECTOR)
