/*
 * Copyright (C) 2012 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.
 */

// @ts-nocheck
// TODO(crbug.com/1011811): Enable TypeScript compiler checks

// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/naming-convention */

export function defineCommonExtensionSymbols(apiPrivate: any): void {
  if (!apiPrivate.panels) {
    apiPrivate.panels = {};
  }
  apiPrivate.panels.SearchAction = {
    CancelSearch: 'cancelSearch',
    PerformSearch: 'performSearch',
    NextSearchResult: 'nextSearchResult',
    PreviousSearchResult: 'previousSearchResult',
  };

  /** @enum {string} */
  apiPrivate.Events = {
    ButtonClicked: 'button-clicked-',
    PanelObjectSelected: 'panel-objectSelected-',
    NetworkRequestFinished: 'network-request-finished',
    OpenResource: 'open-resource',
    PanelSearch: 'panel-search-',
    RecordingStarted: 'trace-recording-started-',
    RecordingStopped: 'trace-recording-stopped-',
    ResourceAdded: 'resource-added',
    ResourceContentCommitted: 'resource-content-committed',
    ViewShown: 'view-shown-',
    ViewHidden: 'view-hidden-',
  };

  /** @enum {string} */
  apiPrivate.Commands = {
    AddRequestHeaders: 'addRequestHeaders',
    AddTraceProvider: 'addTraceProvider',
    ApplyStyleSheet: 'applyStyleSheet',
    CompleteTraceSession: 'completeTraceSession',
    CreatePanel: 'createPanel',
    CreateSidebarPane: 'createSidebarPane',
    CreateToolbarButton: 'createToolbarButton',
    EvaluateOnInspectedPage: 'evaluateOnInspectedPage',
    ForwardKeyboardEvent: '_forwardKeyboardEvent',
    GetHAR: 'getHAR',
    GetPageResources: 'getPageResources',
    GetRequestContent: 'getRequestContent',
    GetResourceContent: 'getResourceContent',
    InspectedURLChanged: 'inspectedURLChanged',
    OpenResource: 'openResource',
    Reload: 'Reload',
    Subscribe: 'subscribe',
    SetOpenResourceHandler: 'setOpenResourceHandler',
    SetResourceContent: 'setResourceContent',
    SetSidebarContent: 'setSidebarContent',
    SetSidebarHeight: 'setSidebarHeight',
    SetSidebarPage: 'setSidebarPage',
    ShowPanel: 'showPanel',
    Unsubscribe: 'unsubscribe',
    UpdateButton: 'updateButton',
    RegisterLanguageExtensionPlugin: 'registerLanguageExtensionPlugin',
  };

  /** @enum {string} */
  apiPrivate.LanguageExtensionPluginCommands = {
    AddRawModule: 'addRawModule',
    RemoveRawModule: 'removeRawModule',
    SourceLocationToRawLocation: 'sourceLocationToRawLocation',
    RawLocationToSourceLocation: 'rawLocationToSourceLocation',
    GetScopeInfo: 'getScopeInfo',
    ListVariablesInScope: 'listVariablesInScope',
    GetTypeInfo: 'getTypeInfo',
    GetFormatter: 'getFormatter',
    GetInspectableAddress: 'getInspectableAddress',
    GetFunctionInfo: 'getFunctionInfo',
    GetInlinedFunctionRanges: 'getInlinedFunctionRanges',
    GetInlinedCalleesRanges: 'getInlinedCalleesRanges',
    GetMappedLines: 'getMappedLines',
  };

  /** @enum {string} */
  apiPrivate.LanguageExtensionPluginEvents = {
    UnregisteredLanguageExtensionPlugin: 'unregisteredLanguageExtensionPlugin',
  };
}

self.injectedExtensionAPI = function(
    extensionInfo: any, inspectedTabId: string, themeName: string, keysToForward: number[],
    testHook: (arg0: Object, arg1: Object) => any, injectedScriptId: number): void {
  const keysToForwardSet = new Set<number>(keysToForward);
  const chrome = window.chrome || {};

  const devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, 'devtools');
  if (devtools_descriptor) {
    return;
  }

  const apiPrivate = {};

  defineCommonExtensionSymbols(apiPrivate);

  const commands = apiPrivate.Commands;
  const languageExtensionPluginCommands = apiPrivate.LanguageExtensionPluginCommands;
  const languageExtensionPluginEvents = apiPrivate.LanguageExtensionPluginEvents;
  const events = apiPrivate.Events;
  let userAction = false;

  // Here and below, all constructors are private to API implementation.
  // For a public type Foo, if internal fields are present, these are on
  // a private FooImpl type, an instance of FooImpl is used in a closure
  // by Foo consutrctor to re-bind publicly exported members to an instance
  // of Foo.

  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/naming-convention
  function EventSinkImpl(type: any, customDispatch: any): void {
    this._type = type;
    this._listeners = [];
    this._customDispatch = customDispatch;
  }

  EventSinkImpl.prototype = {

    addListener: function(callback: any): void {
      if (typeof callback !== 'function') {
        throw 'addListener: callback is not a function';
      }
      if (this._listeners.length === 0) {
        extensionServer.sendRequest({command: commands.Subscribe, type: this._type});
      }
      this._listeners.push(callback);
      extensionServer.registerHandler('notify-' + this._type, this._dispatch.bind(this));
    },


    removeListener: function(callback: any): void {
      const listeners = this._listeners;

      for (let i = 0; i < listeners.length; ++i) {
        if (listeners[i] === callback) {
          listeners.splice(i, 1);
          break;
        }
      }
      if (this._listeners.length === 0) {
        extensionServer.sendRequest({command: commands.Unsubscribe, type: this._type});
      }
    },


    _fire: function _(_vararg: any): void {
      const listeners = this._listeners.slice();
      for (let i = 0; i < listeners.length; ++i) {
        listeners[i].apply(null, arguments);
      }
    },


    _dispatch: function(request: any): void {
      if (this._customDispatch) {
        this._customDispatch.call(this, request);
      } else {
        this._fire.apply(this, request.arguments);
      }
    },
  };

  /**
   * @constructor
   */

  function InspectorExtensionAPI(): void {
    this.inspectedWindow = new InspectedWindow();
    this.panels = new Panels();
    this.network = new Network();
    this.timeline = new Timeline();
    this.languageServices = new LanguageServicesAPI();
    defineDeprecatedProperty(this, 'webInspector', 'resources', 'network');
  }

  /**
   * @constructor
   */

  function Network(): void {
    function dispatchRequestEvent(this: EventSinkImpl, message: any): void {
      const request = message.arguments[1];
      request.__proto__ = new Request(message.arguments[0]);
      this._fire(request);
    }
    this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent);
    defineDeprecatedProperty(this, 'network', 'onFinished', 'onRequestFinished');
    this.onNavigated = new EventSink(events.InspectedURLChanged);
  }

  Network.prototype = {
    getHAR: function(callback: any): void {
      function callbackWrapper(result: any): void {
        const entries = (result && result.entries) || [];
        for (let i = 0; i < entries.length; ++i) {
          entries[i].__proto__ = new Request(entries[i]._requestId);
          delete entries[i]._requestId;
        }
        callback(result);
      }
      extensionServer.sendRequest({command: commands.GetHAR}, callback && callbackWrapper);
    },

    addRequestHeaders: function(headers: any): void {
      extensionServer.sendRequest(
          {command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname});
    },
  };

  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/naming-convention
  function RequestImpl(id: any): void {
    this._id = id;
  }

  RequestImpl.prototype = {
    getContent: function(callback: any): void {
      function callbackWrapper(response: any): void {
        callback(response.content, response.encoding);
      }
      extensionServer.sendRequest({command: commands.GetRequestContent, id: this._id}, callback && callbackWrapper);
    },
  };

  /**
   * @constructor
   */
  function Panels(): void {
    const panels = {
      elements: new ElementsPanel(),
      sources: new SourcesPanel(),
    };

    function panelGetter(name: any): any {
      return panels[name];
    }
    for (const panel in panels) {
      Object.defineProperty(this, panel, {get: panelGetter.bind(null, panel), enumerable: true});
    }
    this.applyStyleSheet = function(styleSheet: any): void {
      extensionServer.sendRequest({command: commands.ApplyStyleSheet, styleSheet: styleSheet});
    };
  }

  Panels.prototype = {
    create: function(title: any, icon: any, page: any, callback: any): void {
      const id = 'extension-panel-' + extensionServer.nextObjectId();
      const request = {command: commands.CreatePanel, id: id, title: title, icon: icon, page: page};
      extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
    },

    setOpenResourceHandler: function(callback: any): void {
      const hadHandler = extensionServer.hasHandler(events.OpenResource);

      function callbackWrapper(message: any): void {
        // Allow the panel to show itself when handling the event.
        userAction = true;
        try {
          callback.call(null, new Resource(message.resource), message.lineNumber);
        } finally {
          userAction = false;
        }
      }

      if (!callback) {
        extensionServer.unregisterHandler(events.OpenResource);
      } else {
        extensionServer.registerHandler(events.OpenResource, callbackWrapper);
      }

      // Only send command if we either removed an existing handler or added handler and had none before.
      if (hadHandler === !callback) {
        extensionServer.sendRequest({command: commands.SetOpenResourceHandler, 'handlerPresent': Boolean(callback)});
      }
    },

    openResource: function(url: any, lineNumber: any, callback: any): void {
      extensionServer.sendRequest({command: commands.OpenResource, 'url': url, 'lineNumber': lineNumber}, callback);
    },

    get SearchAction(): any {
      return apiPrivate.panels.SearchAction;
    },
  };

  /**
   * @constructor
   */
  function ExtensionViewImpl(id: any): void {
    this._id = id;

    function dispatchShowEvent(this: EventSinkImpl, message: any): void {
      const frameIndex = message.arguments[0];
      if (typeof frameIndex === 'number') {
        this._fire(window.parent.frames[frameIndex]);
      } else {
        this._fire();
      }
    }

    if (id) {
      this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent);
      this.onHidden = new EventSink(events.ViewHidden + id);
    }
  }

  /**
   * @constructor
   * @extends {ExtensionViewImpl}
   */
  function PanelWithSidebarImpl(hostPanelName: string): void {
    ExtensionViewImpl.call(this, null);
    this._hostPanelName = hostPanelName;
    this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
  }

  PanelWithSidebarImpl.prototype = {
    createSidebarPane: function(title: any, callback: any): void {
      const id = 'extension-sidebar-' + extensionServer.nextObjectId();
      const request = {command: commands.CreateSidebarPane, panel: this._hostPanelName, id: id, title: title};
      function callbackWrapper(): void {
        callback(new ExtensionSidebarPane(id));
      }
      extensionServer.sendRequest(request, callback && callbackWrapper);
    },

    __proto__: ExtensionViewImpl.prototype,
  };

  /**
   * @constructor
   */
  function LanguageServicesAPIImpl(): void {
    /** @type {!Map<*, !MessagePort>} */
    this._plugins = new Map();
  }

  LanguageServicesAPIImpl.prototype = {
    registerLanguageExtensionPlugin: async function(plugin: any, pluginName: string, supportedScriptTypes: {
      language: string,
      symbol_types: string[],
    }): Promise<void> {
      if (this._plugins.has(plugin)) {
        throw new Error(`Tried to register plugin '${pluginName}' twice`);
      }
      const channel = new MessageChannel();
      const port = channel.port1;
      this._plugins.set(plugin, port);
      port.onmessage = ({data: {requestId, method, parameters}}: MessageEvent<any>): void => {
        console.time(`${requestId}: ${method}`);
        dispatchMethodCall(method, parameters)
            .then(result => port.postMessage({requestId, result}))
            .catch(error => port.postMessage({requestId, error: {message: error.message}}))
            .finally(() => console.timeEnd(`${requestId}: ${method}`));
      };

      function dispatchMethodCall(method: string, parameters: any): Promise<any> {
        switch (method) {
          case languageExtensionPluginCommands.AddRawModule:
            return plugin.addRawModule(parameters.rawModuleId, parameters.symbolsURL, parameters.rawModule);
          case languageExtensionPluginCommands.RemoveRawModule:
            return plugin.removeRawModule(parameters.rawModuleId);
          case languageExtensionPluginCommands.SourceLocationToRawLocation:
            return plugin.sourceLocationToRawLocation(parameters.sourceLocation);
          case languageExtensionPluginCommands.RawLocationToSourceLocation:
            return plugin.rawLocationToSourceLocation(parameters.rawLocation);
          case languageExtensionPluginCommands.GetScopeInfo:
            return plugin.getScopeInfo(parameters.type);
          case languageExtensionPluginCommands.ListVariablesInScope:
            return plugin.listVariablesInScope(parameters.rawLocation);
          case languageExtensionPluginCommands.GetTypeInfo:
            return plugin.getTypeInfo(parameters.expression, parameters.context);
          case languageExtensionPluginCommands.GetFormatter:
            return plugin.getFormatter(parameters.expressionOrField, parameters.context);
          case languageExtensionPluginCommands.GetInspectableAddress:
            if ('getInspectableAddress' in plugin) {
              return plugin.getInspectableAddress(parameters.field);
            }
            return Promise.resolve({js: ''});
          case languageExtensionPluginCommands.GetFunctionInfo:
            return plugin.getFunctionInfo(parameters.rawLocation);
          case languageExtensionPluginCommands.GetInlinedFunctionRanges:
            return plugin.getInlinedFunctionRanges(parameters.rawLocation);
          case languageExtensionPluginCommands.GetInlinedCalleesRanges:
            return plugin.getInlinedCalleesRanges(parameters.rawLocation);
          case languageExtensionPluginCommands.GetMappedLines:
            if ('getMappedLines' in plugin) {
              return plugin.getMappedLines(parameters.rawModuleId, parameters.sourceFileURL);
            }
            return Promise.resolve(undefined);
        }
        throw new Error(`Unknown language plugin method ${method}`);
      }

      await new Promise(resolve => {
        extensionServer.sendRequest(
            {command: commands.RegisterLanguageExtensionPlugin, pluginName, port: channel.port2, supportedScriptTypes},
            () => resolve(), [channel.port2]);
      });
    },

    unregisterLanguageExtensionPlugin: async function(plugin: any): Promise<void> {
      const port = this._plugins.get(plugin);
      if (!port) {
        throw new Error('Tried to unregister a plugin that was not previously registered');
      }
      this._plugins.delete(plugin);
      port.postMessage({event: languageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin});
      port.close();
    },
  };

  function declareInterfaceClass(implConstructor: any): (...args: any[]) => void {
    return function(): void {
      const impl = {__proto__: implConstructor.prototype};
      implConstructor.apply(impl, arguments);
      populateInterfaceClass(this, impl);
    };
  }

  function defineDeprecatedProperty(object: any, className: any, oldName: any, newName: any): void {
    let warningGiven = false;
    function getter(): any {
      if (!warningGiven) {
        console.warn(className + '.' + oldName + ' is deprecated. Use ' + className + '.' + newName + ' instead');
        warningGiven = true;
      }
      return object[newName];
    }
    object.__defineGetter__(oldName, getter);
  }

  function extractCallbackArgument(args: any): any {
    const lastArgument = args[args.length - 1];
    return typeof lastArgument === 'function' ? lastArgument : undefined;
  }

  const LanguageServicesAPI = declareInterfaceClass(LanguageServicesAPIImpl);
  const Button = declareInterfaceClass(ButtonImpl);
  const EventSink = declareInterfaceClass(EventSinkImpl);
  const ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
  const ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
  /**
   * @constructor
   * @param {string} hostPanelName
   */
  const PanelWithSidebarClass = declareInterfaceClass(PanelWithSidebarImpl);
  const Request = declareInterfaceClass(RequestImpl);
  const Resource = declareInterfaceClass(ResourceImpl);
  const TraceSession = declareInterfaceClass(TraceSessionImpl);

  class ElementsPanel extends PanelWithSidebarClass {
    constructor() {
      super('elements');
    }
  }

  class SourcesPanel extends PanelWithSidebarClass {
    constructor() {
      super('sources');
    }
  }

  /**
   * @constructor
   * @extends {ExtensionViewImpl}
   */
  function ExtensionPanelImpl(id: any): void {
    ExtensionViewImpl.call(this, id);
    this.onSearch = new EventSink(events.PanelSearch + id);
  }

  ExtensionPanelImpl.prototype = {
    createStatusBarButton: function(iconPath: any, tooltipText: any, disabled: any): Object {
      const id = 'button-' + extensionServer.nextObjectId();
      const request = {
        command: commands.CreateToolbarButton,
        panel: this._id,
        id: id,
        icon: iconPath,
        tooltip: tooltipText,
        disabled: Boolean(disabled),
      };
      extensionServer.sendRequest(request);
      return new Button(id);
    },

    show: function(): void {
      if (!userAction) {
        return;
      }

      const request = {command: commands.ShowPanel, id: this._id};
      extensionServer.sendRequest(request);
    },

    __proto__: ExtensionViewImpl.prototype,
  };

  /**
   * @constructor
   * @extends {ExtensionViewImpl}
   */
  function ExtensionSidebarPaneImpl(id: any): void {
    ExtensionViewImpl.call(this, id);
  }

  ExtensionSidebarPaneImpl.prototype = {
    setHeight: function(height: any): void {
      extensionServer.sendRequest({command: commands.SetSidebarHeight, id: this._id, height: height});
    },

    setExpression: function(expression: any, rootTitle: any, evaluateOptions: any): void {
      const request = {
        command: commands.SetSidebarContent,
        id: this._id,
        expression: expression,
        rootTitle: rootTitle,
        evaluateOnPage: true,
      };
      if (typeof evaluateOptions === 'object') {
        request.evaluateOptions = evaluateOptions;
      }
      extensionServer.sendRequest(request, extractCallbackArgument(arguments));
    },

    setObject: function(jsonObject: any, rootTitle: any, callback: any): void {
      extensionServer.sendRequest(
          {command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle}, callback);
    },

    setPage: function(page: any): void {
      extensionServer.sendRequest({command: commands.SetSidebarPage, id: this._id, page: page});
    },

    __proto__: ExtensionViewImpl.prototype,
  };

  /**
   * @constructor
   */
  function ButtonImpl(id: any): void {
    this._id = id;
    this.onClicked = new EventSink(events.ButtonClicked + id);
  }

  ButtonImpl.prototype = {
    update: function(iconPath: any, tooltipText: any, disabled: any): void {
      const request = {
        command: commands.UpdateButton,
        id: this._id,
        icon: iconPath,
        tooltip: tooltipText,
        disabled: Boolean(disabled),
      };
      extensionServer.sendRequest(request);
    },
  };

  /**
   * @constructor
   */
  function Timeline(): void {
  }

  Timeline.prototype = {
    addTraceProvider: function(categoryName: string, categoryTooltip: string): TraceProvider {
      const id = 'extension-trace-provider-' + extensionServer.nextObjectId();
      extensionServer.sendRequest(
          {command: commands.AddTraceProvider, id: id, categoryName: categoryName, categoryTooltip: categoryTooltip});
      return new TraceProvider(id);
    },
  };

  /**
   * @constructor
   */
  function TraceSessionImpl(id: string): void {
    this._id = id;
  }

  TraceSessionImpl.prototype = {
    complete: function(url?: string, timeOffset?: number): void {
      const request =
          {command: commands.CompleteTraceSession, id: this._id, url: url || '', timeOffset: timeOffset || 0};
      extensionServer.sendRequest(request);
    },
  };

  /**
   * @constructor
   */
  function TraceProvider(id: string): void {
    function dispatchRecordingStarted(this: EventSinkImpl, message: any): void {
      const sessionId = message.arguments[0];
      this._fire(new TraceSession(sessionId));
    }

    this.onRecordingStarted = new EventSink(events.RecordingStarted + id, dispatchRecordingStarted);
    this.onRecordingStopped = new EventSink(events.RecordingStopped + id);
  }

  /**
   * @constructor
   */
  function InspectedWindow(): void {
    function dispatchResourceEvent(this: EventSinkImpl, message: any): void {
      this._fire(new Resource(message.arguments[0]));
    }

    function dispatchResourceContentEvent(this: EventSinkImpl, message: any): void {
      this._fire(new Resource(message.arguments[0]), message.arguments[1]);
    }

    this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent);
    this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent);
  }

  InspectedWindow.prototype = {
    reload: function(optionsOrUserAgent: any): void {
      let options: {
        userAgent: string,
      }|null = null;
      if (typeof optionsOrUserAgent === 'object') {
        options = optionsOrUserAgent;
      } else if (typeof optionsOrUserAgent === 'string') {
        options = {userAgent: optionsOrUserAgent};
        console.warn(
            'Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. ' +
            'Use inspectedWindow.reload({ userAgent: value}) instead.');
      }
      extensionServer.sendRequest({command: commands.Reload, options: options});
    },

    eval: function(expression: any, evaluateOptions: any): Object |
        null {
          const callback = extractCallbackArgument(arguments);
          function callbackWrapper(result: any): void {
            if (result.isError || result.isException) {
              callback(undefined, result);
            } else {
              callback(result.value);
            }
          }
          const request = {command: commands.EvaluateOnInspectedPage, expression: expression};
          if (typeof evaluateOptions === 'object') {
            request.evaluateOptions = evaluateOptions;
          }
          extensionServer.sendRequest(request, callback && callbackWrapper);
          return null;
        },

    getResources: function(callback: any): void {
      function wrapResource(resourceData: any): any {
        return new Resource(resourceData);
      }
      function callbackWrapper(resources: any): void {
        callback(resources.map(wrapResource));
      }
      extensionServer.sendRequest({command: commands.GetPageResources}, callback && callbackWrapper);
    },
  };

  /**
   * @constructor
   */
  function ResourceImpl(resourceData: any): void {
    this._url = resourceData.url;
    this._type = resourceData.type;
  }

  ResourceImpl.prototype = {
    get url(): string {
      return this._url;
    },

    get type(): string {
      return this._type;
    },

    getContent: function(callback: any): void {
      function callbackWrapper(response: any): void {
        callback(response.content, response.encoding);
      }

      extensionServer.sendRequest({command: commands.GetResourceContent, url: this._url}, callback && callbackWrapper);
    },

    setContent: function(content: any, commit: any, callback: any): void {
      extensionServer.sendRequest(
          {command: commands.SetResourceContent, url: this._url, content: content, commit: commit}, callback);
    },
  };

  function getTabId(): string {
    return inspectedTabId;
  }

  let keyboardEventRequestQueue: any[] = [];
  let forwardTimer: number|null = null;
  function forwardKeyboardEvent(event: any): void {
    // Check if the event should be forwarded.
    // This is a workaround for crbug.com/923338.
    const focused = document.activeElement;
    if (focused) {
      const isInput = focused.nodeName === 'INPUT' || focused.nodeName === 'TEXTAREA';
      if (isInput && !(event.ctrlKey || event.altKey || event.metaKey)) {
        return;
      }
    }

    let modifiers = 0;
    if (event.shiftKey) {
      modifiers |= 1;
    }
    if (event.ctrlKey) {
      modifiers |= 2;
    }
    if (event.altKey) {
      modifiers |= 4;
    }
    if (event.metaKey) {
      modifiers |= 8;
    }
    const num = (event.keyCode & 255) | (modifiers << 8);
    // We only care about global hotkeys, not about random text
    if (!keysToForwardSet.has(num)) {
      return;
    }
    event.preventDefault();
    const requestPayload = {
      eventType: event.type,
      ctrlKey: event.ctrlKey,
      altKey: event.altKey,
      metaKey: event.metaKey,
      shiftKey: event.shiftKey,
      keyIdentifier: event.keyIdentifier,
      key: event.key,
      code: event.code,
      location: event.location,
      keyCode: event.keyCode,
    };
    keyboardEventRequestQueue.push(requestPayload);
    if (!forwardTimer) {
      forwardTimer = setTimeout(forwardEventQueue, 0);
    }
  }

  function forwardEventQueue(): void {
    forwardTimer = null;
    const request = {command: commands.ForwardKeyboardEvent, entries: keyboardEventRequestQueue};
    extensionServer.sendRequest(request);
    keyboardEventRequestQueue = [];
  }

  document.addEventListener('keydown', forwardKeyboardEvent, false);

  /**
   * @constructor
   */
  function ExtensionServerClient(): void {
    this._callbacks = {};
    this._handlers = {};
    this._lastRequestId = 0;
    this._lastObjectId = 0;

    this.registerHandler('callback', this._onCallback.bind(this));

    const channel = new MessageChannel();
    this._port = channel.port1;
    this._port.addEventListener('message', this._onMessage.bind(this), false);
    this._port.start();

    window.parent.postMessage('registerExtension', '*', [channel.port2]);
  }

  ExtensionServerClient.prototype = {
    sendRequest: function(message: Object, callback?: (() => any), transfers?: any[]): void {
      if (typeof callback === 'function') {
        message.requestId = this._registerCallback(callback);
      }
      this._port.postMessage(message, transfers);
    },

    hasHandler: function(command: any): boolean {
      return Boolean(this._handlers[command]);
    },

    registerHandler: function(command: any, handler: any): void {
      this._handlers[command] = handler;
    },

    unregisterHandler: function(command: any): void {
      delete this._handlers[command];
    },

    nextObjectId: function(): string {
      return injectedScriptId.toString() + '_' + ++this._lastObjectId;
    },

    _registerCallback: function(callback: any): number {
      const id = ++this._lastRequestId;
      this._callbacks[id] = callback;
      return id;
    },

    _onCallback: function(request: any): void {
      if (request.requestId in this._callbacks) {
        const callback = this._callbacks[request.requestId];
        delete this._callbacks[request.requestId];
        callback(request.result);
      }
    },

    _onMessage: function(event: any): void {
      const request = event.data;
      const handler = this._handlers[request.command];
      if (handler) {
        handler.call(this, request);
      }
    },
  };

  function populateInterfaceClass(interfaze: any, implementation: any): void {
    for (const member in implementation) {
      if (member.charAt(0) === '_') {
        continue;
      }
      let descriptor: (PropertyDescriptor|undefined)|null = null;
      // Traverse prototype chain until we find the owner.
      for (let owner = implementation; owner && !descriptor; owner = owner.__proto__) {
        descriptor = Object.getOwnPropertyDescriptor(owner, member);
      }
      if (!descriptor) {
        continue;
      }
      if (typeof descriptor.value === 'function') {
        interfaze[member] = descriptor.value.bind(implementation);
      } else if (typeof descriptor.get === 'function') {
        interfaze.__defineGetter__(member, descriptor.get.bind(implementation));
      } else {
        Object.defineProperty(interfaze, member, descriptor);
      }
    }
  }

  const extensionServer = new ExtensionServerClient();
  const coreAPI = new InspectorExtensionAPI();

  Object.defineProperty(chrome, 'devtools', {value: {}, enumerable: true});

  // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
  chrome.devtools.inspectedWindow = {};
  Object.defineProperty(chrome.devtools.inspectedWindow, 'tabId', {get: getTabId});
  chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
  chrome.devtools.network = coreAPI.network;
  chrome.devtools.panels = coreAPI.panels;
  chrome.devtools.panels.themeName = themeName;
  chrome.devtools.languageServices = new LanguageServicesAPI();

  // default to expose experimental APIs for now.
  if (extensionInfo.exposeExperimentalAPIs !== false) {
    chrome.experimental = chrome.experimental || {};
    chrome.experimental.devtools = chrome.experimental.devtools || {};

    const properties = Object.getOwnPropertyNames(coreAPI);
    for (let i = 0; i < properties.length; ++i) {
      const descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
      if (descriptor) {
        Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
      }
    }
    chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
  }

  if (extensionInfo.exposeWebInspectorNamespace) {
    window.webInspector = coreAPI;
  }
  testHook(extensionServer, coreAPI);
};

self.buildExtensionAPIInjectedScript = function(
    extensionInfo: {
      startPage: string,
      name: string,
      exposeExperimentalAPIs: boolean,
    },
    inspectedTabId: string, themeName: string, keysToForward: number[],
    testHook: ((arg0: Object, arg1: Object) => any)|undefined): string {
  const argumentsJSON =
      [extensionInfo, inspectedTabId || null, themeName, keysToForward].map(_ => JSON.stringify(_)).join(',');
  if (!testHook) {
    testHook = (): void => {};
  }
  return '(function(injectedScriptId){ ' + defineCommonExtensionSymbols.toString() + ';' +
      '(' + self.injectedExtensionAPI.toString() + ')(' + argumentsJSON + ',' + testHook + ', injectedScriptId);' +
      '})';
};
