/*
 * Copyright (C) 2007 Apple Inc.  All rights reserved.
 * Copyright (C) 2014 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:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
 */

/**
 * @unrestricted
 */
Elements.PropertiesWidget = class extends UI.ThrottledWidget {
  constructor() {
    super(true /* isWebComponent */);
    this.registerRequiredCSS('elements/propertiesWidget.css');

    SDK.targetManager.addModelListener(SDK.DOMModel, SDK.DOMModel.Events.AttrModified, this._onNodeChange, this);
    SDK.targetManager.addModelListener(SDK.DOMModel, SDK.DOMModel.Events.AttrRemoved, this._onNodeChange, this);
    SDK.targetManager.addModelListener(
        SDK.DOMModel, SDK.DOMModel.Events.CharacterDataModified, this._onNodeChange, this);
    SDK.targetManager.addModelListener(
        SDK.DOMModel, SDK.DOMModel.Events.ChildNodeCountUpdated, this._onNodeChange, this);
    UI.context.addFlavorChangeListener(SDK.DOMNode, this._setNode, this);
    this._node = UI.context.flavor(SDK.DOMNode);
    this.update();
  }

  /**
   * @param {!Common.Event} event
   */
  _setNode(event) {
    this._node = /** @type {?SDK.DOMNode} */ (event.data);
    this.update();
  }

  /**
   * @override
   * @protected
   * @return {!Promise.<?>}
   */
  doUpdate() {
    if (this._lastRequestedNode) {
      this._lastRequestedNode.domModel().runtimeModel().releaseObjectGroup(Elements.PropertiesWidget._objectGroupName);
      delete this._lastRequestedNode;
    }

    if (!this._node) {
      this.contentElement.removeChildren();
      this.sections = [];
      return Promise.resolve();
    }

    this._lastRequestedNode = this._node;
    return this._node.resolveToObject(Elements.PropertiesWidget._objectGroupName).then(nodeResolved.bind(this));

    /**
     * @param {?SDK.RemoteObject} object
     * @this {Elements.PropertiesWidget}
     */
    function nodeResolved(object) {
      if (!object)
        return;

      /**
       * @suppressReceiverCheck
       * @this {*}
       */
      function protoList() {
        let proto = this;
        const result = {__proto__: null};
        let counter = 1;
        while (proto) {
          result[counter++] = proto;
          proto = proto.__proto__;
        }
        return result;
      }
      const promise = object.callFunctionPromise(protoList).then(nodePrototypesReady.bind(this));
      object.release();
      return promise;
    }

    /**
     * @param {!{object: ?SDK.RemoteObject, wasThrown: (boolean|undefined)}} result
     * @this {Elements.PropertiesWidget}
     */
    function nodePrototypesReady(result) {
      if (!result.object || result.wasThrown)
        return;

      const promise = result.object.getOwnPropertiesPromise(false /* generatePreview */).then(fillSection.bind(this));
      result.object.release();
      return promise;
    }

    /**
     * @param {!{properties: ?Array.<!SDK.RemoteObjectProperty>, internalProperties: ?Array.<!SDK.RemoteObjectProperty>}} result
     * @this {Elements.PropertiesWidget}
     */
    function fillSection(result) {
      if (!result || !result.properties)
        return;

      const properties = result.properties;
      const expanded = [];
      const sections = this.sections || [];
      for (let i = 0; i < sections.length; ++i)
        expanded.push(sections[i].expanded);

      this.contentElement.removeChildren();
      this.sections = [];

      // Get array of property user-friendly names.
      for (let i = 0; i < properties.length; ++i) {
        if (!parseInt(properties[i].name, 10))
          continue;
        const property = properties[i].value;
        let title = property.description;
        title = title.replace(/Prototype$/, '');
        const section = new ObjectUI.ObjectPropertiesSection(property, title);
        section.element.classList.add('properties-widget-section');
        this.sections.push(section);
        this.contentElement.appendChild(section.element);
        if (expanded[this.sections.length - 1])
          section.expand();
        section.addEventListener(UI.TreeOutline.Events.ElementExpanded, this._propertyExpanded, this);
      }
    }
  }

  /**
   * @param {!Common.Event} event
   */
  _propertyExpanded(event) {
    Host.userMetrics.actionTaken(Host.UserMetrics.Action.DOMPropertiesExpanded);
    for (const section of this.sections)
      section.removeEventListener(UI.TreeOutline.Events.ElementExpanded, this._propertyExpanded, this);
  }

  /**
   * @param {!Common.Event} event
   */
  _onNodeChange(event) {
    if (!this._node)
      return;
    const data = event.data;
    const node = /** @type {!SDK.DOMNode} */ (data instanceof SDK.DOMNode ? data : data.node);
    if (this._node !== node)
      return;
    this.update();
  }
};

Elements.PropertiesWidget._objectGroupName = 'properties-sidebar-pane';
