/*
 * Copyright (C) 2011 Google 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:
 *
 *     * 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.
 */

/** @typedef {string} */
Protocol.Error = Symbol('Protocol.Error');

/**
 * @unrestricted
 */
Protocol.InspectorBackend = class {
  constructor() {
    this._agentPrototypes = {};
    this._dispatcherPrototypes = {};
    this._initialized = false;
  }

  /**
   * @param {string} error
   * @param {!Object} messageObject
   */
  static reportProtocolError(error, messageObject) {
    console.error(error + ': ' + JSON.stringify(messageObject));
  }

  /**
   * @return {boolean}
   */
  isInitialized() {
    return this._initialized;
  }

  /**
   * @param {string} domain
   */
  _addAgentGetterMethodToProtocolTargetPrototype(domain) {
    let upperCaseLength = 0;
    while (upperCaseLength < domain.length && domain[upperCaseLength].toLowerCase() !== domain[upperCaseLength])
      ++upperCaseLength;

    const methodName = domain.substr(0, upperCaseLength).toLowerCase() + domain.slice(upperCaseLength) + 'Agent';

    /**
     * @this {Protocol.TargetBase}
     */
    function agentGetter() {
      return this._agents[domain];
    }

    Protocol.TargetBase.prototype[methodName] = agentGetter;

    /**
     * @this {Protocol.TargetBase}
     */
    function registerDispatcher(dispatcher) {
      this.registerDispatcher(domain, dispatcher);
    }

    Protocol.TargetBase.prototype['register' + domain + 'Dispatcher'] = registerDispatcher;
  }

  /**
   * @param {string} domain
   * @return {!Protocol.InspectorBackend._AgentPrototype}
   */
  _agentPrototype(domain) {
    if (!this._agentPrototypes[domain]) {
      this._agentPrototypes[domain] = new Protocol.InspectorBackend._AgentPrototype(domain);
      this._addAgentGetterMethodToProtocolTargetPrototype(domain);
    }

    return this._agentPrototypes[domain];
  }

  /**
   * @param {string} domain
   * @return {!Protocol.InspectorBackend._DispatcherPrototype}
   */
  _dispatcherPrototype(domain) {
    if (!this._dispatcherPrototypes[domain])
      this._dispatcherPrototypes[domain] = new Protocol.InspectorBackend._DispatcherPrototype();
    return this._dispatcherPrototypes[domain];
  }

  /**
   * @param {string} method
   * @param {!Array.<!Object>} signature
   * @param {!Array.<string>} replyArgs
   * @param {boolean} hasErrorData
   */
  registerCommand(method, signature, replyArgs, hasErrorData) {
    const domainAndMethod = method.split('.');
    this._agentPrototype(domainAndMethod[0]).registerCommand(domainAndMethod[1], signature, replyArgs, hasErrorData);
    this._initialized = true;
  }

  /**
   * @param {string} type
   * @param {!Object} values
   */
  registerEnum(type, values) {
    const domainAndName = type.split('.');
    const domain = domainAndName[0];
    if (!Protocol[domain])
      Protocol[domain] = {};

    Protocol[domain][domainAndName[1]] = values;
    this._initialized = true;
  }

  /**
   * @param {string} eventName
   * @param {!Object} params
   */
  registerEvent(eventName, params) {
    const domain = eventName.split('.')[0];
    this._dispatcherPrototype(domain).registerEvent(eventName, params);
    this._initialized = true;
  }

  /**
   * @param {function(T)} clientCallback
   * @param {string} errorPrefix
   * @param {function(new:T,S)=} constructor
   * @param {T=} defaultValue
   * @return {function(?string, S)}
   * @template T,S
   */
  wrapClientCallback(clientCallback, errorPrefix, constructor, defaultValue) {
    /**
     * @param {?string} error
     * @param {S} value
     * @template S
     */
    function callbackWrapper(error, value) {
      if (error) {
        console.error(errorPrefix + error);
        clientCallback(defaultValue);
        return;
      }
      if (constructor)
        clientCallback(new constructor(value));
      else
        clientCallback(value);
    }
    return callbackWrapper;
  }
};

Protocol.InspectorBackend._ConnectionClosedErrorCode = -32000;
Protocol.InspectorBackend.DevToolsStubErrorCode = -32015;


Protocol.inspectorBackend = new Protocol.InspectorBackend();

/**
 * @interface
 */
Protocol.InspectorBackend.Connection = function() {};

Protocol.InspectorBackend.Connection.prototype = {
  /**
   * @param {string} message
   */
  sendMessage(message) {},

  /**
   * @return {!Promise}
   */
  disconnect() {},
};

/**
 * @typedef {!{
 *   onMessage: function((!Object|string)),
 *   onDisconnect: function(string)
 * }}
 */
Protocol.InspectorBackend.Connection.Params;

/**
 * @typedef {function(!Protocol.InspectorBackend.Connection.Params):!Protocol.InspectorBackend.Connection}
 */
Protocol.InspectorBackend.Connection.Factory;

/**
 * @unrestricted
 */
Protocol.TargetBase = class extends Common.Object {
  /**
   *  @param {!Protocol.InspectorBackend.Connection.Factory} connectionFactory
   */
  constructor(connectionFactory) {
    super();
    this._connection =
        connectionFactory({onMessage: this._onMessage.bind(this), onDisconnect: this._onDisconnect.bind(this)});
    this._lastMessageId = 1;
    this._pendingResponsesCount = 0;
    this._agents = {};
    this._dispatchers = {};
    this._callbacks = {};
    this._initialize(Protocol.inspectorBackend._agentPrototypes, Protocol.inspectorBackend._dispatcherPrototypes);
    this._domainToLogger = new Map();
    if (!Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches) {
      Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches =
          this._deprecatedRunAfterPendingDispatches.bind(this);
    }
    if (!Protocol.InspectorBackend.sendRawMessageForTesting)
      Protocol.InspectorBackend.sendRawMessageForTesting = this._sendRawMessageForTesting.bind(this);
  }

  /**
   * @param {!Object.<string, !Protocol.InspectorBackend._AgentPrototype>} agentPrototypes
   * @param {!Object.<string, !Protocol.InspectorBackend._DispatcherPrototype>} dispatcherPrototypes
   */
  _initialize(agentPrototypes, dispatcherPrototypes) {
    for (const domain in agentPrototypes) {
      this._agents[domain] = Object.create(agentPrototypes[domain]);
      this._agents[domain].setTarget(this);
    }

    for (const domain in dispatcherPrototypes) {
      this._dispatchers[domain] = Object.create(dispatcherPrototypes[domain]);
      this._dispatchers[domain].initialize();
    }
  }

  /**
   * @return {number}
   */
  _nextMessageId() {
    return this._lastMessageId++;
  }

  /**
   * @param {string} domain
   * @return {!Protocol.InspectorBackend._AgentPrototype}
   */
  _agent(domain) {
    return this._agents[domain];
  }

  /**
   * @param {string} domain
   * @param {string} method
   * @param {?Object} params
   * @param {?function(*)} callback
   */
  _wrapCallbackAndSendMessageObject(domain, method, params, callback) {
    if (!this._connection) {
      if (callback)
        this._dispatchConnectionErrorResponse(domain, method, callback);
      return;
    }

    const messageObject = {};
    const messageId = this._nextMessageId();
    messageObject.id = messageId;
    messageObject.method = method;
    if (params)
      messageObject.params = params;

    const wrappedCallback = this._wrap(callback, domain, method);
    const message = JSON.stringify(messageObject);

    if (Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages)
      this._dumpProtocolMessage('frontend: ' + message, '[FE] ' + domain);
    if (this.hasEventListeners(Protocol.TargetBase.Events.MessageSent)) {
      this.dispatchEventToListeners(
          Protocol.TargetBase.Events.MessageSent,
          {domain, method, params: JSON.parse(JSON.stringify(params)), id: messageId});
    }

    this._connection.sendMessage(message);
    ++this._pendingResponsesCount;
    this._callbacks[messageId] = wrappedCallback;
  }

  /**
   * @param {?function(*)} callback
   * @param {string} method
   * @param {string} domain
   * @return {function(*)}
   */
  _wrap(callback, domain, method) {
    if (!callback)
      callback = function() {};

    callback.methodName = method;
    callback.domain = domain;
    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
      callback.sendRequestTime = Date.now();

    return callback;
  }

  /**
   * @param {string} method
   * @param {?Object} params
   * @param {?function(...*)} callback
   */
  _sendRawMessageForTesting(method, params, callback) {
    const domain = method.split('.')[0];
    this._wrapCallbackAndSendMessageObject(domain, method, params, callback);
  }

  /**
   * @param {!Object|string} message
   */
  _onMessage(message) {
    if (Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages) {
      this._dumpProtocolMessage(
          'backend: ' + ((typeof message === 'string') ? message : JSON.stringify(message)), 'Backend');
    }
    if (this.hasEventListeners(Protocol.TargetBase.Events.MessageReceived)) {
      this.dispatchEventToListeners(Protocol.TargetBase.Events.MessageReceived, {
        message: JSON.parse((typeof message === 'string') ? message : JSON.stringify(message)),
      });
    }


    const messageObject = /** @type {!Object} */ ((typeof message === 'string') ? JSON.parse(message) : message);

    if ('id' in messageObject) {  // just a response for some request
      const callback = this._callbacks[messageObject.id];
      if (!callback) {
        Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
        return;
      }

      const timingLabel = 'time-stats: ' + callback.methodName;
      if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
        Protocol.InspectorBackend._timeLogger.time(timingLabel);

      this._agent(callback.domain).dispatchResponse(messageObject, callback.methodName, callback);
      --this._pendingResponsesCount;
      delete this._callbacks[messageObject.id];

      if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
        Protocol.InspectorBackend._timeLogger.timeEnd(timingLabel);

      if (this._scripts && !this._pendingResponsesCount)
        this._deprecatedRunAfterPendingDispatches();
    } else {
      if (!('method' in messageObject)) {
        Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
        return;
      }

      const method = messageObject.method.split('.');
      const domainName = method[0];
      if (!(domainName in this._dispatchers)) {
        Protocol.InspectorBackend.reportProtocolError(
            `Protocol Error: the message ${messageObject.method} is for non-existing domain '${domainName}'`,
            messageObject);
        return;
      }

      this._dispatchers[domainName].dispatch(method[1], messageObject);
    }
  }

  /**
   * @param {string} domain
   * @param {!Object} dispatcher
   */
  registerDispatcher(domain, dispatcher) {
    if (!this._dispatchers[domain])
      return;

    this._dispatchers[domain].addDomainDispatcher(dispatcher);
  }

  /**
   * @param {function()=} script
   */
  _deprecatedRunAfterPendingDispatches(script) {
    if (!this._scripts)
      this._scripts = [];

    if (script)
      this._scripts.push(script);

    // Execute all promises.
    setTimeout(function() {
      if (!this._pendingResponsesCount)
        this._executeAfterPendingDispatches();
      else
        this._deprecatedRunAfterPendingDispatches();
    }.bind(this), 0);
  }

  _executeAfterPendingDispatches() {
    if (!this._pendingResponsesCount) {
      const scripts = this._scripts;
      this._scripts = [];
      for (let id = 0; id < scripts.length; ++id)
        scripts[id].call(this);
    }
  }

  /**
   * @param {string} message
   * @param {string} context
   */
  _dumpProtocolMessage(message, context) {
    if (!this._domainToLogger.get(context))
      this._domainToLogger.set(context, console.context ? console.context(context) : console);
    const logger = this._domainToLogger.get(context);
    logger.log(message);
  }

  /**
   * @param {string} reason
   */
  _onDisconnect(reason) {
    this._connection = null;
    this._runPendingCallbacks();
    this.dispose();
  }

  /**
   * @protected
   */
  dispose() {
  }

  /**
   * @return {boolean}
   */
  isDisposed() {
    return !this._connection;
  }

  _runPendingCallbacks() {
    const keys = Object.keys(this._callbacks).map(function(num) {
      return parseInt(num, 10);
    });
    for (let i = 0; i < keys.length; ++i) {
      const callback = this._callbacks[keys[i]];
      this._dispatchConnectionErrorResponse(callback.domain, callback.methodName, callback);
    }
    this._callbacks = {};
  }

  /**
   * @param {string} domain
   * @param {string} methodName
   * @param {function(*)} callback
   */
  _dispatchConnectionErrorResponse(domain, methodName, callback) {
    const error = {
      message: 'Connection is closed, can\'t dispatch pending ' + methodName,
      code: Protocol.InspectorBackend._ConnectionClosedErrorCode,
      data: null
    };
    const messageObject = {error: error};
    setTimeout(
        Protocol.InspectorBackend._AgentPrototype.prototype.dispatchResponse.bind(
            this._agent(domain), messageObject, methodName, callback),
        0);
  }
};

Protocol.TargetBase.Events = {
  MessageSent: Symbol('MessageSent'),
  MessageReceived: Symbol('MessageReceived')
};

/**
 * @unrestricted
 */
Protocol.InspectorBackend._AgentPrototype = class {
  /**
   * @param {string} domain
   */
  constructor(domain) {
    this._replyArgs = {};
    this._hasErrorData = {};
    this._domain = domain;
  }

  /**
   * @param {!Protocol.TargetBase} target
   */
  setTarget(target) {
    this._target = target;
  }

  /**
   * @param {string} methodName
   * @param {!Array.<!Object>} signature
   * @param {!Array.<string>} replyArgs
   * @param {boolean} hasErrorData
   */
  registerCommand(methodName, signature, replyArgs, hasErrorData) {
    const domainAndMethod = this._domain + '.' + methodName;

    /**
     * @param {...*} vararg
     * @this {Protocol.InspectorBackend._AgentPrototype}
     * @return {!Promise.<*>}
     */
    function sendMessagePromise(vararg) {
      const params = Array.prototype.slice.call(arguments);
      return Protocol.InspectorBackend._AgentPrototype.prototype._sendMessageToBackendPromise.call(
          this, domainAndMethod, signature, params);
    }

    this[methodName] = sendMessagePromise;

    /**
     * @param {!Object} request
     * @return {!Promise}
     * @this {Protocol.InspectorBackend._AgentPrototype}
     */
    function invoke(request) {
      return this._invoke(domainAndMethod, request);
    }

    this['invoke_' + methodName] = invoke;

    this._replyArgs[domainAndMethod] = replyArgs;
    if (hasErrorData)
      this._hasErrorData[domainAndMethod] = true;
  }

  /**
   * @param {string} method
   * @param {!Array.<!Object>} signature
   * @param {!Array.<*>} args
   * @param {function(string)} errorCallback
   * @return {?Object}
   */
  _prepareParameters(method, signature, args, errorCallback) {
    const params = {};
    let hasParams = false;

    for (const param of signature) {
      const paramName = param['name'];
      const typeName = param['type'];
      const optionalFlag = param['optional'];

      if (!args.length && !optionalFlag) {
        errorCallback(
            `Protocol Error: Invalid number of arguments for method '${method}' call. ` +
            `It must have the following arguments ${JSON.stringify(signature)}'.`);
        return null;
      }

      const value = args.shift();
      if (optionalFlag && typeof value === 'undefined')
        continue;

      if (typeof value !== typeName) {
        errorCallback(
            `Protocol Error: Invalid type of argument '${paramName}' for method '${method}' call. ` +
            `It must be '${typeName}' but it is '${typeof value}'.`);
        return null;
      }

      params[paramName] = value;
      hasParams = true;
    }

    if (args.length) {
      errorCallback(`Protocol Error: Extra ${args.length} arguments in a call to method '${method}'.`);
      return null;
    }

    return hasParams ? params : null;
  }

  /**
   * @param {string} method
   * @param {!Array<!Object>} signature
   * @param {!Array<*>} args
   * @return {!Promise<?>}
   */
  _sendMessageToBackendPromise(method, signature, args) {
    let errorMessage;
    /**
     * @param {string} message
     */
    function onError(message) {
      console.error(message);
      errorMessage = message;
    }
    const params = this._prepareParameters(method, signature, args, onError);
    if (errorMessage)
      return Promise.resolve(null);

    return new Promise(resolve => {
      this._target._wrapCallbackAndSendMessageObject(this._domain, method, params, (error, result) => {
        if (error) {
          resolve(null);
          return;
        }
        const args = this._replyArgs[method];
        resolve(result && args.length ? result[args[0]] : undefined);
      });
    });
  }

  /**
   * @param {string} method
   * @param {?Object} request
   * @return {!Promise<!Object>}
   */
  _invoke(method, request) {
    return new Promise(fulfill => {
      this._target._wrapCallbackAndSendMessageObject(this._domain, method, request, (error, result) => {
        if (!result)
          result = {};
        if (error)
          result[Protocol.Error] = error.message;
        fulfill(result);
      });
    });
  }

  /**
   * @param {!Object} messageObject
   * @param {string} methodName
   * @param {function(?Protocol.Error, ?Object)} callback
   */
  dispatchResponse(messageObject, methodName, callback) {
    if (messageObject.error && messageObject.error.code !== Protocol.InspectorBackend._ConnectionClosedErrorCode &&
        messageObject.error.code !== Protocol.InspectorBackend.DevToolsStubErrorCode &&
        !Protocol.InspectorBackend.Options.suppressRequestErrors) {
      const id =
          Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages ? ' with id = ' + messageObject.id : '';
      console.error('Request ' + methodName + id + ' failed. ' + JSON.stringify(messageObject.error));
    }
    callback(messageObject.error, messageObject.result);
  }
};

/**
 * @unrestricted
 */
Protocol.InspectorBackend._DispatcherPrototype = class {
  constructor() {
    this._eventArgs = {};
  }

  /**
   * @param {string} eventName
   * @param {!Object} params
   */
  registerEvent(eventName, params) {
    this._eventArgs[eventName] = params;
  }

  initialize() {
    this._dispatchers = [];
  }

  /**
   * @param {!Object} dispatcher
   */
  addDomainDispatcher(dispatcher) {
    this._dispatchers.push(dispatcher);
  }

  /**
   * @param {string} functionName
   * @param {!Object} messageObject
   */
  dispatch(functionName, messageObject) {
    if (!this._dispatchers.length)
      return;

    if (!this._eventArgs[messageObject.method]) {
      Protocol.InspectorBackend.reportProtocolError(
          `Protocol Error: Attempted to dispatch an unspecified method '${messageObject.method}'`, messageObject);
      return;
    }

    const params = [];
    if (messageObject.params) {
      const paramNames = this._eventArgs[messageObject.method];
      for (let i = 0; i < paramNames.length; ++i)
        params.push(messageObject.params[paramNames[i]]);
    }

    const timingLabel = 'time-stats: ' + messageObject.method;
    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
      Protocol.InspectorBackend._timeLogger.time(timingLabel);

    for (let index = 0; index < this._dispatchers.length; ++index) {
      const dispatcher = this._dispatchers[index];
      if (functionName in dispatcher)
        dispatcher[functionName].apply(dispatcher, params);
    }

    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
      Protocol.InspectorBackend._timeLogger.timeEnd(timingLabel);
  }
};

Protocol.InspectorBackend.Options = {
  dumpInspectorTimeStats: false,
  dumpInspectorProtocolMessages: false,
  suppressRequestErrors: false
};

Protocol.InspectorBackend._timeLogger = console.context ? console.context('Protocol timing') : console;
