(function() {
    /*
 * 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.
 */

/* eslint-disable indent */

function defineCommonExtensionSymbols(apiPrivate) {
  if (!apiPrivate.audits)
    apiPrivate.audits = {};
  apiPrivate.audits.Severity = {Info: 'info', Warning: 'warning', Severe: 'severe'};

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

  /** @enum {string} */
  apiPrivate.Events = {
    AuditStarted: 'audit-started-',
    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 = {
    AddAuditCategory: 'addAuditCategory',
    AddAuditResult: 'addAuditResult',
    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',
    StopAuditCategoryRun: 'stopAuditCategoryRun',
    Unsubscribe: 'unsubscribe',
    UpdateAuditProgress: 'updateAuditProgress',
    UpdateButton: 'updateButton'
  };
}

/**
 * @param {!ExtensionDescriptor} extensionInfo
 * @param {string} inspectedTabId
 * @param {string} themeName
 * @param {number} injectedScriptId
 * @param {function(!Object, !Object)} testHook
 * @suppressGlobalPropertiesCheck
 */
function injectedExtensionAPI(extensionInfo, inspectedTabId, themeName, testHook, injectedScriptId) {
  var apiPrivate = {};

  defineCommonExtensionSymbols(apiPrivate);

  var commands = apiPrivate.Commands;
  var events = apiPrivate.Events;
  var 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.

  /**
   * @constructor
   */
  function EventSinkImpl(type, customDispatch) {
    this._type = type;
    this._listeners = [];
    this._customDispatch = customDispatch;
  }

  EventSinkImpl.prototype = {
    addListener: function(callback) {
      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) {
      var listeners = this._listeners;

      for (var 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});
    },

    /**
     * @param {...} vararg
     */
    _fire: function(vararg) {
      var listeners = this._listeners.slice();
      for (var i = 0; i < listeners.length; ++i)
        listeners[i].apply(null, arguments);
    },

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

  /**
   * @constructor
   */
  function InspectorExtensionAPI() {
    this.audits = new Audits();
    this.inspectedWindow = new InspectedWindow();
    this.panels = new Panels();
    this.network = new Network();
    this.timeline = new Timeline();
    defineDeprecatedProperty(this, 'webInspector', 'resources', 'network');
  }

  /**
   * @constructor
   */
  function Network() {
    /**
     * @this {EventSinkImpl}
     */
    function dispatchRequestEvent(message) {
      var 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) {
      function callbackWrapper(result) {
        var entries = (result && result.entries) || [];
        for (var 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) {
      extensionServer.sendRequest(
          {command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname});
    }
  };

  /**
   * @constructor
   */
  function RequestImpl(id) {
    this._id = id;
  }

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

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

    function panelGetter(name) {
      return panels[name];
    }
    for (var panel in panels)
      this.__defineGetter__(panel, panelGetter.bind(null, panel));
    this.applyStyleSheet = function(styleSheet) {
      extensionServer.sendRequest({command: commands.ApplyStyleSheet, styleSheet: styleSheet});
    };
  }

  Panels.prototype = {
    create: function(title, icon, page, callback) {
      var id = 'extension-panel-' + extensionServer.nextObjectId();
      var 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) {
      var hadHandler = extensionServer.hasHandler(events.OpenResource);

      function callbackWrapper(message) {
        // 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': !!callback});
    },

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

    get SearchAction() {
      return apiPrivate.panels.SearchAction;
    }
  };

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

    /**
     * @this {EventSinkImpl}
     */
    function dispatchShowEvent(message) {
      var 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}
   * @param {string} hostPanelName
   */
  function PanelWithSidebarImpl(hostPanelName) {
    ExtensionViewImpl.call(this, null);
    this._hostPanelName = hostPanelName;
    this.onSelectionChanged = new EventSink(events.PanelObjectSelected + hostPanelName);
  }

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

    __proto__: ExtensionViewImpl.prototype
  };

  function declareInterfaceClass(implConstructor) {
    return function() {
      var impl = {__proto__: implConstructor.prototype};
      implConstructor.apply(impl, arguments);
      populateInterfaceClass(this, impl);
    };
  }

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

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

  var AuditCategory = declareInterfaceClass(AuditCategoryImpl);
  var AuditResult = declareInterfaceClass(AuditResultImpl);
  var Button = declareInterfaceClass(ButtonImpl);
  var EventSink = declareInterfaceClass(EventSinkImpl);
  var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
  var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
  var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl);
  var Request = declareInterfaceClass(RequestImpl);
  var Resource = declareInterfaceClass(ResourceImpl);
  var TraceSession = declareInterfaceClass(TraceSessionImpl);

  /**
   * @constructor
   * @extends {PanelWithSidebar}
   */
  function ElementsPanel() {
    PanelWithSidebar.call(this, 'elements');
  }

  ElementsPanel.prototype = {__proto__: PanelWithSidebar.prototype};

  /**
   * @constructor
   * @extends {PanelWithSidebar}
   */
  function SourcesPanel() {
    PanelWithSidebar.call(this, 'sources');
  }

  SourcesPanel.prototype = {__proto__: PanelWithSidebar.prototype};

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

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

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

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

    __proto__: ExtensionViewImpl.prototype
  };

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

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

    setExpression: function(expression, rootTitle, evaluateOptions) {
      var 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, rootTitle, callback) {
      extensionServer.sendRequest(
          {command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle}, callback);
    },

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

    __proto__: ExtensionViewImpl.prototype
  };

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

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

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

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

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

  TraceSessionImpl.prototype =
  {
    /**
     * @param {string=} url
     * @param {number=} timeOffset
     */
    complete: function(url, timeOffset) {
      var request = {command: commands.CompleteTraceSession, id: this._id, url: url || '', timeOffset: timeOffset || 0};
      extensionServer.sendRequest(request);
    }
  };

  /**
   * @constructor
   * @param {string} id
   */
  function TraceProvider(id) {
    /**
     * @this {EventSinkImpl}
     */
    function dispatchRecordingStarted(message) {
      var 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 Audits() {}

  Audits.prototype = {
    /**
     * @return {!AuditCategory}
     */
    addCategory: function(displayName, resultCount) {
      var id = 'extension-audit-category-' + extensionServer.nextObjectId();
      if (typeof resultCount !== 'undefined') {
        console.warn(
            'Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead.');
      }
      extensionServer.sendRequest(
          {command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount});
      return new AuditCategory(id);
    }
  };

  /**
   * @constructor
   */
  function AuditCategoryImpl(id) {
    /**
     * @this {EventSinkImpl}
     */
    function dispatchAuditEvent(request) {
      var auditResult = new AuditResult(request.arguments[0]);
      try {
        this._fire(auditResult);
      } catch (e) {
        console.error('Uncaught exception in extension audit event handler: ' + e);
        auditResult.done();
      }
    }
    this._id = id;
    this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent);
  }

  /**
   * @constructor
   */
  function AuditResultImpl(id) {
    this._id = id;

    this.createURL = this._nodeFactory.bind(this, 'url');
    this.createSnippet = this._nodeFactory.bind(this, 'snippet');
    this.createText = this._nodeFactory.bind(this, 'text');
    this.createObject = this._nodeFactory.bind(this, 'object');
    this.createNode = this._nodeFactory.bind(this, 'node');
  }

  AuditResultImpl.prototype = {
    addResult: function(displayName, description, severity, details) {
      // shorthand for specifying details directly in addResult().
      if (details && !(details instanceof AuditResultNode))
        details = new AuditResultNode(Array.isArray(details) ? details : [details]);

      var request = {
        command: commands.AddAuditResult,
        resultId: this._id,
        displayName: displayName,
        description: description,
        severity: severity,
        details: details
      };
      extensionServer.sendRequest(request);
    },

    /**
     * @return {!Object}
     */
    createResult: function() {
      return new AuditResultNode(Array.prototype.slice.call(arguments));
    },

    updateProgress: function(worked, totalWork) {
      extensionServer.sendRequest(
          {command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork});
    },

    done: function() {
      extensionServer.sendRequest({command: commands.StopAuditCategoryRun, resultId: this._id});
    },

    /**
     * @type {!Object.<string, string>}
     */
    get Severity() {
      return apiPrivate.audits.Severity;
    },

    /**
     * @return {!{type: string, arguments: !Array.<string|number>}}
     */
    createResourceLink: function(url, lineNumber) {
      return {type: 'resourceLink', arguments: [url, lineNumber && lineNumber - 1]};
    },

    /**
     * @return {!{type: string, arguments: !Array.<string|number>}}
     */
    _nodeFactory: function(type) {
      return {type: type, arguments: Array.prototype.slice.call(arguments, 1)};
    }
  };

  /**
   * @constructor
   */
  function AuditResultNode(contents) {
    this.contents = contents;
    this.children = [];
    this.expanded = false;
  }

  AuditResultNode.prototype = {
    /**
     * @return {!Object}
     */
    addChild: function() {
      var node = new AuditResultNode(Array.prototype.slice.call(arguments));
      this.children.push(node);
      return node;
    }
  };

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

    /**
     * @this {EventSinkImpl}
     */
    function dispatchResourceContentEvent(message) {
      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) {
      var options = 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});
    },

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

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

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

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

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

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

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

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

  function getTabId() {
    return inspectedTabId;
  }

  var keyboardEventRequestQueue = [];
  var forwardTimer = null;

  function forwardKeyboardEvent(event) {
    // We only care about global hotkeys, not about random text
    if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.key) && event.key !== 'Escape')
      return;
    var requestPayload = {
      eventType: event.type,
      ctrlKey: event.ctrlKey,
      altKey: event.altKey,
      metaKey: event.metaKey,
      key: event.key,
      key: event.key,
      code: event.code,
      location: event.location,
      keyCode: event.keyCode
    };
    keyboardEventRequestQueue.push(requestPayload);
    if (!forwardTimer)
      forwardTimer = setTimeout(forwardEventQueue, 0);
  }

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

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

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

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

    var 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 = {
    /**
     * @param {!Object} message
     * @param {function()=} callback
     */
    sendRequest: function(message, callback) {
      if (typeof callback === 'function')
        message.requestId = this._registerCallback(callback);
      this._port.postMessage(message);
    },

    /**
     * @return {boolean}
     */
    hasHandler: function(command) {
      return !!this._handlers[command];
    },

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

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

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

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

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

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

  function populateInterfaceClass(interfaze, implementation) {
    for (var member in implementation) {
      if (member.charAt(0) === '_')
        continue;
      var descriptor = null;
      // Traverse prototype chain until we find the owner.
      for (var 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);
    }
  }

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

  var chrome = window.chrome || {};
  // Override chrome.devtools as a workaround for a error-throwing getter being exposed
  // in extension pages loaded into a non-extension process (only happens for remote client
  // extensions)
  var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, 'devtools');
  if (!devtools_descriptor || devtools_descriptor.get)
    Object.defineProperty(chrome, 'devtools', {value: {}, enumerable: true});

  // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
  chrome.devtools.inspectedWindow = {};
  chrome.devtools.inspectedWindow.__defineGetter__('tabId', getTabId);
  chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
  chrome.devtools.network = coreAPI.network;
  chrome.devtools.panels = coreAPI.panels;
  chrome.devtools.panels.themeName = themeName;

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

    var properties = Object.getOwnPropertyNames(coreAPI);
    for (var i = 0; i < properties.length; ++i) {
      var 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);
}

/**
 * @param {!ExtensionDescriptor} extensionInfo
 * @param {string} inspectedTabId
 * @param {string} themeName
 * @param {function(!Object, !Object)|undefined} testHook
 * @return {string}
 */
function buildExtensionAPIInjectedScript(extensionInfo, inspectedTabId, themeName, testHook) {
  var argumentsJSON = [extensionInfo, inspectedTabId || null, themeName].map(_ => JSON.stringify(_)).join(',');
  if (!testHook)
    testHook = () => {};
  return '(function(injectedScriptId){ ' + defineCommonExtensionSymbols.toString() + ';' +
      '(' + injectedExtensionAPI.toString() + ')(' + argumentsJSON + ',' + testHook + ', injectedScriptId);' +
      '})';
}

        var tabId;
        var extensionInfo = {};
        var extensionServer;
        platformExtensionAPI(injectedExtensionAPI("remote-" + window.parent.frames.length));
    })();