/*
 * Copyright (C) 2011 Google Inc. All rights reserved.
 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
 * Copyright (C) 2014 University of Washington.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER OR 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.
 */

InspectorBackend.globalSequenceId = 1;

InspectorBackend.Connection = class InspectorBackendConnection
{
    constructor()
    {
        this._pendingResponses = new Map;
        this._deferredCallbacks = [];
        this._target = null;
    }

    // Public

    get target()
    {
        return this._target;
    }

    set target(target)
    {
        console.assert(!this._target);
        this._target = target;
    }

    dispatch(message)
    {
        let messageObject = typeof message === "string" ? JSON.parse(message) : message;

        if ("id" in messageObject)
            this._dispatchResponse(messageObject);
        else
            this._dispatchEvent(messageObject);
    }

    runAfterPendingDispatches(callback)
    {
        console.assert(typeof callback === "function");

        if (!this._pendingResponses.size)
            callback.call(this);
        else
            this._deferredCallbacks.push(callback);
    }

    // Protected

    sendMessageToBackend(message)
    {
        throw new Error("Should be implemented by a InspectorBackend.Connection subclass");
    }

    // Private

    _dispatchResponse(messageObject)
    {
        console.assert(this._pendingResponses.size >= 0);

        if (messageObject.error && messageObject.error.code !== -32000)
            console.error("Request with id = " + messageObject["id"] + " failed. " + JSON.stringify(messageObject.error));

        let sequenceId = messageObject["id"];
        console.assert(this._pendingResponses.has(sequenceId), sequenceId, this._target ? this._target.identifier : "(unknown)", this._pendingResponses);

        let responseData = this._pendingResponses.take(sequenceId) || {};
        let {request, command, callback, promise} = responseData;

        let processingStartTimestamp = performance.now();
        for (let tracer of InspectorBackend.activeTracers)
            tracer.logWillHandleResponse(this, messageObject);

        InspectorBackend.currentDispatchState.request = request;
        InspectorBackend.currentDispatchState.response = messageObject;

        if (typeof callback === "function")
            this._dispatchResponseToCallback(command, request, messageObject, callback);
        else if (typeof promise === "object")
            this._dispatchResponseToPromise(command, messageObject, promise);
        else
            console.error("Received a command response without a corresponding callback or promise.", messageObject, command);

        InspectorBackend.currentDispatchState.request = null;
        InspectorBackend.currentDispatchState.response = null;

        let processingTime = (performance.now() - processingStartTimestamp).toFixed(3);
        let roundTripTime = (processingStartTimestamp - responseData.sendRequestTimestamp).toFixed(3);

        for (let tracer of InspectorBackend.activeTracers)
            tracer.logDidHandleResponse(this, messageObject, {rtt: roundTripTime, dispatch: processingTime});

        if (this._deferredCallbacks.length && !this._pendingResponses.size)
            this._flushPendingScripts();
    }

    _dispatchResponseToCallback(command, requestObject, responseObject, callback)
    {
        let callbackArguments = [];
        callbackArguments.push(responseObject["error"] ? responseObject["error"].message : null);

        if (responseObject["result"]) {
            for (let parameterName of command._replySignature)
                callbackArguments.push(responseObject["result"][parameterName]);
        }

        try {
            callback.apply(null, callbackArguments);
        } catch (e) {
            WI.reportInternalError(e, {"cause": `An uncaught exception was thrown while dispatching response callback for command ${command._qualifiedName}.`});
        }
    }

    _dispatchResponseToPromise(command, messageObject, promise)
    {
        let {resolve, reject} = promise;
        if (messageObject["error"])
            reject(new Error(messageObject["error"].message));
        else
            resolve(messageObject["result"]);
    }

    _dispatchEvent(messageObject)
    {
        let qualifiedName = messageObject.method;
        let [domainName, eventName] = qualifiedName.split(".");

        // COMPATIBILITY (iOS 12.2 and iOS 13): because the multiplexing target isn't created until
        // `Target.exists` returns, any `Target.targetCreated` won't have a dispatcher for the
        // message, so create a multiplexing target here to force this._target._agents.Target.
        if (!this._target && this === InspectorBackend.backendConnection && WI.sharedApp.debuggableType === WI.DebuggableType.WebPage && qualifiedName === "Target.targetCreated")
            WI.targetManager.createMultiplexingBackendTarget();

        let agent = this._target._agents[domainName];
        if (!agent) {
            console.error(`Protocol Error: Attempted to dispatch method '${qualifiedName}' for non-existing domain '${domainName}'`, messageObject);
            return;
        }

        let dispatcher = agent._dispatcher;
        if (!dispatcher) {
            console.error(`Protocol Error: Missing dispatcher for domain '${domainName}', for event '${qualifiedName}'`, messageObject);
            return;
        }

        let event = agent._events[eventName];
        if (!event) {
            console.error(`Protocol Error: Attempted to dispatch an unspecified method '${qualifiedName}'`, messageObject);
            return;
        }

        let handler = dispatcher[eventName];
        if (!handler) {
            console.error(`Protocol Error: Attempted to dispatch an unimplemented method '${qualifiedName}'`, messageObject);
            return;
        }

        let processingStartTimestamp = performance.now();
        for (let tracer of InspectorBackend.activeTracers)
            tracer.logWillHandleEvent(this, messageObject);

        InspectorBackend.currentDispatchState.event = messageObject;

        try {
            let params = messageObject.params || {};
            handler.apply(dispatcher, event._parameterNames.map((name) => params[name]));
        } catch (e) {
            for (let tracer of InspectorBackend.activeTracers)
                tracer.logFrontendException(this, messageObject, e);

            WI.reportInternalError(e, {"cause": `An uncaught exception was thrown while handling event: ${qualifiedName}`});
        }

        InspectorBackend.currentDispatchState.event = null;

        let processingDuration = (performance.now() - processingStartTimestamp).toFixed(3);
        for (let tracer of InspectorBackend.activeTracers)
            tracer.logDidHandleEvent(this, messageObject, {dispatch: processingDuration});
    }

    _sendCommandToBackendWithCallback(command, parameters, callback)
    {
        let sequenceId = InspectorBackend.globalSequenceId++;

        let messageObject = {
            "id": sequenceId,
            "method": command._qualifiedName,
        };

        if (!isEmptyObject(parameters))
            messageObject["params"] = parameters;

        let responseData = {command, request: messageObject, callback};

        if (InspectorBackend.activeTracer)
            responseData.sendRequestTimestamp = performance.now();

        this._pendingResponses.set(sequenceId, responseData);
        this._sendMessageToBackend(messageObject);
    }

    _sendCommandToBackendExpectingPromise(command, parameters)
    {
        let sequenceId = InspectorBackend.globalSequenceId++;

        let messageObject = {
            "id": sequenceId,
            "method": command._qualifiedName,
        };

        if (!isEmptyObject(parameters))
            messageObject["params"] = parameters;

        let responseData = {command, request: messageObject};

        if (InspectorBackend.activeTracer)
            responseData.sendRequestTimestamp = performance.now();

        let responsePromise = new Promise(function(resolve, reject) {
            responseData.promise = {resolve, reject};
        });

        this._pendingResponses.set(sequenceId, responseData);
        this._sendMessageToBackend(messageObject);

        return responsePromise;
    }

    _sendMessageToBackend(messageObject)
    {
        for (let tracer of InspectorBackend.activeTracers)
            tracer.logFrontendRequest(this, messageObject);

        this.sendMessageToBackend(JSON.stringify(messageObject));
    }

    _flushPendingScripts()
    {
        console.assert(this._pendingResponses.size === 0);

        let scriptsToRun = this._deferredCallbacks;
        this._deferredCallbacks = [];
        for (let script of scriptsToRun)
            script.call(this);
    }
};

InspectorBackend.BackendConnection = class InspectorBackendBackendConnection extends InspectorBackend.Connection
{
    sendMessageToBackend(message)
    {
        InspectorFrontendHost.sendMessageToBackend(message);
    }
};

InspectorBackend.WorkerConnection = class InspectorBackendWorkerConnection extends InspectorBackend.Connection
{
    constructor(parentTarget, workerId)
    {
        super();

        this._parentTarget = parentTarget;
        this._workerId = workerId;

        console.assert(this._parentTarget.hasCommand("Worker.sendMessageToWorker"));
    }

    sendMessageToBackend(message)
    {
        // Ignore errors if a worker went away quickly.
        this._parentTarget.WorkerAgent.sendMessageToWorker(this._workerId, message).catch(function(){});
    }
};

InspectorBackend.TargetConnection = class InspectorBackendTargetConnection extends InspectorBackend.Connection
{
    constructor(parentTarget, targetId)
    {
        super();

        this._parentTarget = parentTarget;
        this._targetId = targetId;

        console.assert(this._parentTarget.hasCommand("Target.sendMessageToTarget"));
    }

    sendMessageToBackend(message)
    {
        this._parentTarget.TargetAgent.sendMessageToTarget(this._targetId, message);
    }
};

InspectorBackend.backendConnection = new InspectorBackend.BackendConnection;
