/*
 * Copyright (C) 2007 Apple Inc.  All rights reserved.
 * Copyright (C) 2009 Joseph Pecoraro
 *
 * 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.
 */
import {ComputedStyle, ComputedStyleModel, Events} from './ComputedStyleModel.js';  // eslint-disable-line no-unused-vars
import {PlatformFontsWidget} from './PlatformFontsWidget.js';
import {StylePropertiesSection, StylesSidebarPane, StylesSidebarPropertyRenderer} from './StylesSidebarPane.js';

/**
 * @unrestricted
 */
export class ComputedStyleWidget extends UI.ThrottledWidget {
  constructor() {
    super(true);
    this.registerRequiredCSS('elements/computedStyleSidebarPane.css');
    this._alwaysShowComputedProperties = {'display': true, 'height': true, 'width': true};

    this._computedStyleModel = new ComputedStyleModel();
    this._computedStyleModel.addEventListener(Events.ComputedStyleChanged, this.update, this);

    this._showInheritedComputedStylePropertiesSetting =
        Common.settings.createSetting('showInheritedComputedStyleProperties', false);
    this._showInheritedComputedStylePropertiesSetting.addChangeListener(
        this._showInheritedComputedStyleChanged.bind(this));

    const hbox = this.contentElement.createChild('div', 'hbox styles-sidebar-pane-toolbar');
    const filterContainerElement = hbox.createChild('div', 'styles-sidebar-pane-filter-box');
    const filterInput = StylesSidebarPane.createPropertyFilterElement(ls`Filter`, hbox, filterCallback.bind(this));
    UI.ARIAUtils.setAccessibleName(filterInput, Common.UIString('Filter Computed Styles'));
    filterContainerElement.appendChild(filterInput);
    this.setDefaultFocusedElement(filterInput);

    const toolbar = new UI.Toolbar('styles-pane-toolbar', hbox);
    toolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(
        this._showInheritedComputedStylePropertiesSetting, undefined, Common.UIString('Show all')));

    this._noMatchesElement = this.contentElement.createChild('div', 'gray-info-message');
    this._noMatchesElement.textContent = ls`No matching property`;

    this._propertiesOutline = new UI.TreeOutlineInShadow();
    this._propertiesOutline.hideOverflow();
    this._propertiesOutline.setShowSelectionOnKeyboardFocus(true);
    this._propertiesOutline.setFocusable(true);
    this._propertiesOutline.registerRequiredCSS('elements/computedStyleWidgetTree.css');
    this._propertiesOutline.element.classList.add('monospace', 'computed-properties');
    this.contentElement.appendChild(this._propertiesOutline.element);

    this._linkifier = new Components.Linkifier(_maxLinkLength);

    /**
     * @param {?RegExp} regex
     * @this {ComputedStyleWidget}
     */
    function filterCallback(regex) {
      this._filterRegex = regex;
      this._updateFilter(regex);
    }

    const fontsWidget = new PlatformFontsWidget(this._computedStyleModel);
    fontsWidget.show(this.contentElement);
  }

  /**
   * @override
   */
  onResize() {
    const isNarrow = this.contentElement.offsetWidth < 260;
    this._propertiesOutline.contentElement.classList.toggle('computed-narrow', isNarrow);
  }

  _showInheritedComputedStyleChanged() {
    this.update();
  }

  /**
   * @override
   * @return {!Promise.<?>}
   */
  doUpdate() {
    const promises = [this._computedStyleModel.fetchComputedStyle(), this._fetchMatchedCascade()];
    return Promise.all(promises).spread(this._innerRebuildUpdate.bind(this));
  }

  /**
   * @return {!Promise.<?SDK.CSSMatchedStyles>}
   */
  _fetchMatchedCascade() {
    const node = this._computedStyleModel.node();
    if (!node || !this._computedStyleModel.cssModel()) {
      return Promise.resolve(/** @type {?SDK.CSSMatchedStyles} */ (null));
    }

    return this._computedStyleModel.cssModel().cachedMatchedCascadeForNode(node).then(validateStyles.bind(this));

    /**
     * @param {?SDK.CSSMatchedStyles} matchedStyles
     * @return {?SDK.CSSMatchedStyles}
     * @this {ComputedStyleWidget}
     */
    function validateStyles(matchedStyles) {
      return matchedStyles && matchedStyles.node() === this._computedStyleModel.node() ? matchedStyles : null;
    }
  }

  /**
   * @param {string} text
   * @return {!Node}
   */
  _processColor(text) {
    const color = Common.Color.parse(text);
    if (!color) {
      return createTextNode(text);
    }
    const swatch = InlineEditor.ColorSwatch.create();
    swatch.setColor(color);
    swatch.setFormat(Common.Color.detectColorFormat(color));
    return swatch;
  }

  /**
   * @param {?ComputedStyle} nodeStyle
   * @param {?SDK.CSSMatchedStyles} matchedStyles
   */
  _innerRebuildUpdate(nodeStyle, matchedStyles) {
    /** @type {!Set<string>} */
    const expandedProperties = new Set();
    for (const treeElement of this._propertiesOutline.rootElement().children()) {
      if (!treeElement.expanded) {
        continue;
      }
      const propertyName = treeElement[_propertySymbol].name;
      expandedProperties.add(propertyName);
    }
    const hadFocus = this._propertiesOutline.element.hasFocus();
    this._propertiesOutline.removeChildren();
    this._linkifier.reset();
    const cssModel = this._computedStyleModel.cssModel();
    if (!nodeStyle || !matchedStyles || !cssModel) {
      this._noMatchesElement.classList.remove('hidden');
      return;
    }

    const uniqueProperties = nodeStyle.computedStyle.keysArray();
    uniqueProperties.sort(propertySorter);

    const propertyTraces = this._computePropertyTraces(matchedStyles);
    const inhertiedProperties = this._computeInheritedProperties(matchedStyles);
    const showInherited = this._showInheritedComputedStylePropertiesSetting.get();
    for (let i = 0; i < uniqueProperties.length; ++i) {
      const propertyName = uniqueProperties[i];
      const propertyValue = nodeStyle.computedStyle.get(propertyName);
      const canonicalName = SDK.cssMetadata().canonicalPropertyName(propertyName);
      const inherited = !inhertiedProperties.has(canonicalName);
      if (!showInherited && inherited && !(propertyName in this._alwaysShowComputedProperties)) {
        continue;
      }
      if (!showInherited && propertyName.startsWith('--')) {
        continue;
      }
      if (propertyName !== canonicalName && propertyValue === nodeStyle.computedStyle.get(canonicalName)) {
        continue;
      }

      const propertyElement = createElement('div');
      propertyElement.classList.add('computed-style-property');
      propertyElement.classList.toggle('computed-style-property-inherited', inherited);
      const renderer =
          new StylesSidebarPropertyRenderer(null, nodeStyle.node, propertyName, /** @type {string} */ (propertyValue));
      renderer.setColorHandler(this._processColor.bind(this));
      const propertyNameElement = renderer.renderName();
      propertyNameElement.classList.add('property-name');
      propertyElement.appendChild(propertyNameElement);

      const colon = createElementWithClass('span', 'delimeter');
      colon.textContent = ': ';
      propertyNameElement.appendChild(colon);

      const propertyValueElement = propertyElement.createChild('span', 'property-value');

      const propertyValueText = renderer.renderValue();
      propertyValueText.classList.add('property-value-text');
      propertyValueElement.appendChild(propertyValueText);

      const semicolon = createElementWithClass('span', 'delimeter');
      semicolon.textContent = ';';
      propertyValueElement.appendChild(semicolon);

      const treeElement = new UI.TreeElement();
      treeElement.title = propertyElement;
      treeElement[_propertySymbol] = {name: propertyName, value: propertyValue};
      const isOdd = this._propertiesOutline.rootElement().children().length % 2 === 0;
      treeElement.listItemElement.classList.toggle('odd-row', isOdd);
      this._propertiesOutline.appendChild(treeElement);
      if (!this._propertiesOutline.selectedTreeElement) {
        treeElement.select(!hadFocus);
      }

      const trace = propertyTraces.get(propertyName);
      if (trace) {
        const activeProperty = this._renderPropertyTrace(cssModel, matchedStyles, nodeStyle.node, treeElement, trace);
        treeElement.listItemElement.addEventListener('mousedown', e => e.consume(), false);
        treeElement.listItemElement.addEventListener('dblclick', e => e.consume(), false);
        treeElement.listItemElement.addEventListener('click', handleClick.bind(null, treeElement), false);
        treeElement.listItemElement.addEventListener(
            'contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, activeProperty));
        const gotoSourceElement = UI.Icon.create('mediumicon-arrow-in-circle', 'goto-source-icon');
        gotoSourceElement.addEventListener('click', this._navigateToSource.bind(this, activeProperty));
        propertyValueElement.appendChild(gotoSourceElement);
        if (expandedProperties.has(propertyName)) {
          treeElement.expand();
        }
      }
    }

    this._updateFilter(this._filterRegex);

    /**
     * @param {string} a
     * @param {string} b
     * @return {number}
     */
    function propertySorter(a, b) {
      if (a.startsWith('--') ^ b.startsWith('--')) {
        return a.startsWith('--') ? 1 : -1;
      }
      if (a.startsWith('-webkit') ^ b.startsWith('-webkit')) {
        return a.startsWith('-webkit') ? 1 : -1;
      }
      const canonical1 = SDK.cssMetadata().canonicalPropertyName(a);
      const canonical2 = SDK.cssMetadata().canonicalPropertyName(b);
      return canonical1.compareTo(canonical2);
    }

    /**
     * @param {!UI.TreeElement} treeElement
     * @param {!Event} event
     */
    function handleClick(treeElement, event) {
      if (!treeElement.expanded) {
        treeElement.expand();
      } else {
        treeElement.collapse();
      }
      event.consume();
    }
  }

  /**
   * @param {!SDK.CSSProperty} cssProperty
   * @param {!Event} event
   */
  _navigateToSource(cssProperty, event) {
    Common.Revealer.reveal(cssProperty);
    event.consume(true);
  }

  /**
   * @param {!SDK.CSSModel} cssModel
   * @param {!SDK.CSSMatchedStyles} matchedStyles
   * @param {!SDK.DOMNode} node
   * @param {!UI.TreeElement} rootTreeElement
   * @param {!Array<!SDK.CSSProperty>} tracedProperties
   * @return {!SDK.CSSProperty}
   */
  _renderPropertyTrace(cssModel, matchedStyles, node, rootTreeElement, tracedProperties) {
    let activeProperty = null;
    for (const property of tracedProperties) {
      const trace = createElement('div');
      trace.classList.add('property-trace');
      if (matchedStyles.propertyState(property) === SDK.CSSMatchedStyles.PropertyState.Overloaded) {
        trace.classList.add('property-trace-inactive');
      } else {
        activeProperty = property;
      }

      const renderer =
          new StylesSidebarPropertyRenderer(null, node, property.name, /** @type {string} */ (property.value));
      renderer.setColorHandler(this._processColor.bind(this));
      const valueElement = renderer.renderValue();
      valueElement.classList.add('property-trace-value');
      valueElement.addEventListener('click', this._navigateToSource.bind(this, property), false);
      const gotoSourceElement = UI.Icon.create('mediumicon-arrow-in-circle', 'goto-source-icon');
      gotoSourceElement.addEventListener('click', this._navigateToSource.bind(this, property));
      valueElement.insertBefore(gotoSourceElement, valueElement.firstChild);

      trace.appendChild(valueElement);

      const rule = property.ownerStyle.parentRule;
      const selectorElement = trace.createChild('span', 'property-trace-selector');
      selectorElement.textContent = rule ? rule.selectorText() : 'element.style';
      selectorElement.title = selectorElement.textContent;

      if (rule) {
        const linkSpan = trace.createChild('span', 'trace-link');
        linkSpan.appendChild(StylePropertiesSection.createRuleOriginNode(matchedStyles, this._linkifier, rule));
      }

      const traceTreeElement = new UI.TreeElement();
      traceTreeElement.title = trace;

      traceTreeElement.listItemElement.addEventListener(
          'contextmenu', this._handleContextMenuEvent.bind(this, matchedStyles, property));
      rootTreeElement.appendChild(traceTreeElement);
    }
    return /** @type {!SDK.CSSProperty} */ (activeProperty);
  }

  /**
   * @param {!SDK.CSSMatchedStyles} matchedStyles
   * @param {!SDK.CSSProperty} property
   * @param {!Event} event
   */
  _handleContextMenuEvent(matchedStyles, property, event) {
    const contextMenu = new UI.ContextMenu(event);
    const rule = property.ownerStyle.parentRule;

    if (rule) {
      const header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null;
      if (header && !header.isAnonymousInlineStyleSheet()) {
        contextMenu.defaultSection().appendItem(ls`Navigate to selector source`, () => {
          StylePropertiesSection.tryNavigateToRuleLocation(matchedStyles, rule);
        });
      }
    }

    contextMenu.defaultSection().appendItem(ls`Navigate to style`, () => Common.Revealer.reveal(property));
    contextMenu.show();
  }

  /**
   * @param {!SDK.CSSMatchedStyles} matchedStyles
   * @return {!Map<string, !Array<!SDK.CSSProperty>>}
   */
  _computePropertyTraces(matchedStyles) {
    const result = new Map();
    for (const style of matchedStyles.nodeStyles()) {
      const allProperties = style.allProperties();
      for (const property of allProperties) {
        if (!property.activeInStyle() || !matchedStyles.propertyState(property)) {
          continue;
        }
        if (!result.has(property.name)) {
          result.set(property.name, []);
        }
        result.get(property.name).push(property);
      }
    }
    return result;
  }

  /**
   * @param {!SDK.CSSMatchedStyles} matchedStyles
   * @return {!Set<string>}
   */
  _computeInheritedProperties(matchedStyles) {
    const result = new Set();
    for (const style of matchedStyles.nodeStyles()) {
      for (const property of style.allProperties()) {
        if (!matchedStyles.propertyState(property)) {
          continue;
        }
        result.add(SDK.cssMetadata().canonicalPropertyName(property.name));
      }
    }
    return result;
  }

  /**
   * @param {?RegExp} regex
   */
  _updateFilter(regex) {
    const children = this._propertiesOutline.rootElement().children();
    let hasMatch = false;
    for (const child of children) {
      const property = child[_propertySymbol];
      const matched = !regex || regex.test(property.name) || regex.test(property.value);
      child.hidden = !matched;
      hasMatch |= matched;
    }
    this._noMatchesElement.classList.toggle('hidden', !!hasMatch);
  }
}

const _maxLinkLength = 30;
const _propertySymbol = Symbol('property');
ComputedStyleWidget._propertySymbol = _propertySymbol;
