/*
 * 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;
        this._provisionalMessages = [];
    }

    // Public

    get target()
    {
        return this._target;
    }

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

    addProvisionalMessage(message)
    {
        console.assert(this.target && this.target.isProvisional);
        this._provisionalMessages.push(message);
    }

    dispatchProvisionalMessages()
    {
        console.assert(this.target && !this.target.isProvisional);
        for (let message of this._provisionalMessages)
            this.dispatch(message);
        this._provisionalMessages = [];
    }

    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
{
    sendMessageToBackend(message)
    {
        let workerId = this.target.identifier;
        this.target.parentTarget.WorkerAgent.sendMessageToWorker(workerId, message).catch((error) => {
            // Ignore errors if a worker went away quickly.
            if (this.target.isDestroyed)
                return;
            WI.reportInternalError(error);
        });
    }
};

InspectorBackend.TargetConnection = class InspectorBackendTargetConnection extends InspectorBackend.Connection
{
    sendMessageToBackend(message)
    {
        let targetId = this.target.identifier;
        this.target.parentTarget.TargetAgent.sendMessageToTarget(targetId, message).catch((error) => {
            // Ignore errors if the target was destroyed after the command was dispatched.
            if (this.target.isDestroyed)
                return;
            WI.reportInternalError(error);
        });
    }
};

InspectorBackend.backendConnection = new InspectorBackend.BackendConnection;
