/*
 * 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:
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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.
 */

/**
 * @unrestricted
 */
export default class SoftContextMenu {
  /**
   * @param {!Array.<!InspectorFrontendHostAPI.ContextMenuDescriptor>} items
   * @param {function(string)} itemSelectedCallback
   * @param {!SoftContextMenu=} parentMenu
   */
  constructor(items, itemSelectedCallback, parentMenu) {
    this._items = items;
    this._itemSelectedCallback = itemSelectedCallback;
    this._parentMenu = parentMenu;
    /** @type {?Element} */
    this._highlightedMenuItemElement = null;
  }

  /**
   * @param {!Document} document
   * @param {!AnchorBox} anchorBox
   */
  show(document, anchorBox) {
    if (!this._items.length) {
      return;
    }

    this._document = document;

    this._glassPane = new UI.GlassPane();
    this._glassPane.setPointerEventsBehavior(
        this._parentMenu ? UI.GlassPane.PointerEventsBehavior.PierceGlassPane :
                           UI.GlassPane.PointerEventsBehavior.BlockedByGlassPane);
    this._glassPane.registerRequiredCSS('ui/softContextMenu.css');
    this._glassPane.setContentAnchorBox(anchorBox);
    this._glassPane.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
    this._glassPane.setMarginBehavior(UI.GlassPane.MarginBehavior.NoMargin);
    this._glassPane.setAnchorBehavior(
        this._parentMenu ? UI.GlassPane.AnchorBehavior.PreferRight : UI.GlassPane.AnchorBehavior.PreferBottom);

    this._contextMenuElement = this._glassPane.contentElement.createChild('div', 'soft-context-menu');
    this._contextMenuElement.tabIndex = -1;
    UI.ARIAUtils.markAsMenu(this._contextMenuElement);
    this._contextMenuElement.addEventListener('mouseup', e => e.consume(), false);
    this._contextMenuElement.addEventListener('keydown', this._menuKeyDown.bind(this), false);

    for (let i = 0; i < this._items.length; ++i) {
      this._contextMenuElement.appendChild(this._createMenuItem(this._items[i]));
    }

    this._glassPane.show(document);
    this._focusRestorer = new UI.ElementFocusRestorer(this._contextMenuElement);

    if (!this._parentMenu) {
      this._hideOnUserGesture = event => {
        // If a user clicks on any submenu, prevent the menu system from closing.
        let subMenu = this._subMenu;
        while (subMenu) {
          if (subMenu._contextMenuElement === event.path[0]) {
            return;
          }
          subMenu = subMenu._subMenu;
        }

        this.discard();
        event.consume(true);
      };
      this._document.body.addEventListener('mousedown', this._hideOnUserGesture, false);
      this._document.defaultView.addEventListener('resize', this._hideOnUserGesture, false);
    }
  }

  discard() {
    if (this._subMenu) {
      this._subMenu.discard();
    }
    if (this._focusRestorer) {
      this._focusRestorer.restore();
    }
    if (this._glassPane) {
      this._glassPane.hide();
      delete this._glassPane;
      if (this._hideOnUserGesture) {
        this._document.body.removeEventListener('mousedown', this._hideOnUserGesture, false);
        this._document.defaultView.removeEventListener('resize', this._hideOnUserGesture, false);
        delete this._hideOnUserGesture;
      }
    }
    if (this._parentMenu) {
      delete this._parentMenu._subMenu;
    }
  }

  _createMenuItem(item) {
    if (item.type === 'separator') {
      return this._createSeparator();
    }

    if (item.type === 'subMenu') {
      return this._createSubMenu(item);
    }

    const menuItemElement = createElementWithClass('div', 'soft-context-menu-item');
    menuItemElement.tabIndex = -1;
    UI.ARIAUtils.markAsMenuItem(menuItemElement);
    const checkMarkElement = UI.Icon.create('smallicon-checkmark', 'checkmark');
    menuItemElement.appendChild(checkMarkElement);
    if (!item.checked) {
      checkMarkElement.style.opacity = '0';
    }

    if (item.element) {
      const wrapper = menuItemElement.createChild('div', 'soft-context-menu-custom-item');
      wrapper.appendChild(item.element);
      menuItemElement._customElement = item.element;
      return menuItemElement;
    }

    if (!item.enabled) {
      menuItemElement.classList.add('soft-context-menu-disabled');
    }
    menuItemElement.createTextChild(item.label);
    menuItemElement.createChild('span', 'soft-context-menu-shortcut').textContent = item.shortcut;

    menuItemElement.addEventListener('mousedown', this._menuItemMouseDown.bind(this), false);
    menuItemElement.addEventListener('mouseup', this._menuItemMouseUp.bind(this), false);

    // Manually manage hover highlight since :hover does not work in case of click-and-hold menu invocation.
    menuItemElement.addEventListener('mouseover', this._menuItemMouseOver.bind(this), false);
    menuItemElement.addEventListener('mouseleave', this._menuItemMouseLeave.bind(this), false);

    menuItemElement._actionId = item.id;

    let accessibleName = item.label;

    if (item.type === 'checkbox') {
      const checkedState = item.checked ? ls`checked` : ls`unchecked`;
      if (item.shortcut) {
        accessibleName = ls`${item.label}, ${item.shortcut}, ${checkedState}`;
      } else {
        accessibleName = ls`${item.label}, ${checkedState}`;
      }
    } else if (item.shortcut) {
      accessibleName = ls`${item.label}, ${item.shortcut}`;
    }
    UI.ARIAUtils.setAccessibleName(menuItemElement, accessibleName);

    return menuItemElement;
  }

  _createSubMenu(item) {
    const menuItemElement = createElementWithClass('div', 'soft-context-menu-item');
    menuItemElement._subItems = item.subItems;
    menuItemElement.tabIndex = -1;
    UI.ARIAUtils.markAsMenuItemSubMenu(menuItemElement);

    // Occupy the same space on the left in all items.
    const checkMarkElement = UI.Icon.create('smallicon-checkmark', 'soft-context-menu-item-checkmark');
    checkMarkElement.classList.add('checkmark');
    menuItemElement.appendChild(checkMarkElement);
    checkMarkElement.style.opacity = '0';

    menuItemElement.createTextChild(item.label);

    if (Host.isMac() && !UI.themeSupport.hasTheme()) {
      const subMenuArrowElement = menuItemElement.createChild('span', 'soft-context-menu-item-submenu-arrow');
      subMenuArrowElement.textContent = '\u25B6';  // BLACK RIGHT-POINTING TRIANGLE
    } else {
      const subMenuArrowElement = UI.Icon.create('smallicon-triangle-right', 'soft-context-menu-item-submenu-arrow');
      menuItemElement.appendChild(subMenuArrowElement);
    }

    menuItemElement.addEventListener('mousedown', this._menuItemMouseDown.bind(this), false);
    menuItemElement.addEventListener('mouseup', this._menuItemMouseUp.bind(this), false);

    // Manually manage hover highlight since :hover does not work in case of click-and-hold menu invocation.
    menuItemElement.addEventListener('mouseover', this._menuItemMouseOver.bind(this), false);
    menuItemElement.addEventListener('mouseleave', this._menuItemMouseLeave.bind(this), false);

    return menuItemElement;
  }

  _createSeparator() {
    const separatorElement = createElementWithClass('div', 'soft-context-menu-separator');
    separatorElement._isSeparator = true;
    separatorElement.createChild('div', 'separator-line');
    return separatorElement;
  }

  _menuItemMouseDown(event) {
    // Do not let separator's mouse down hit menu's handler - we need to receive mouse up!
    event.consume(true);
  }

  _menuItemMouseUp(event) {
    this._triggerAction(event.target, event);
    event.consume();
  }

  /**
   * @return {!SoftContextMenu}
   */
  _root() {
    let root = this;
    while (root._parentMenu) {
      root = root._parentMenu;
    }
    return root;
  }

  _triggerAction(menuItemElement, event) {
    if (!menuItemElement._subItems) {
      this._root().discard();
      event.consume(true);
      if (typeof menuItemElement._actionId !== 'undefined') {
        this._itemSelectedCallback(menuItemElement._actionId);
        delete menuItemElement._actionId;
      }
      return;
    }

    this._showSubMenu(menuItemElement);
    event.consume();
  }

  _showSubMenu(menuItemElement) {
    if (menuItemElement._subMenuTimer) {
      clearTimeout(menuItemElement._subMenuTimer);
      delete menuItemElement._subMenuTimer;
    }
    if (this._subMenu) {
      return;
    }

    this._subMenu = new SoftContextMenu(menuItemElement._subItems, this._itemSelectedCallback, this);
    const anchorBox = menuItemElement.boxInWindow();
    // Adjust for padding.
    anchorBox.y -= 5;
    anchorBox.x += 3;
    anchorBox.width -= 6;
    anchorBox.height += 10;
    this._subMenu.show(this._document, anchorBox);
  }

  _menuItemMouseOver(event) {
    this._highlightMenuItem(event.target, true);
  }

  _menuItemMouseLeave(event) {
    if (!this._subMenu || !event.relatedTarget) {
      this._highlightMenuItem(null, true);
      return;
    }

    const relatedTarget = event.relatedTarget;
    if (relatedTarget === this._contextMenuElement) {
      this._highlightMenuItem(null, true);
    }
  }

  /**
   * @param {?Element} menuItemElement
   * @param {boolean} scheduleSubMenu
   */
  _highlightMenuItem(menuItemElement, scheduleSubMenu) {
    if (this._highlightedMenuItemElement === menuItemElement) {
      return;
    }

    if (this._subMenu) {
      this._subMenu.discard();
    }
    if (this._highlightedMenuItemElement) {
      this._highlightedMenuItemElement.classList.remove('force-white-icons');
      this._highlightedMenuItemElement.classList.remove('soft-context-menu-item-mouse-over');
      if (this._highlightedMenuItemElement._subItems && this._highlightedMenuItemElement._subMenuTimer) {
        clearTimeout(this._highlightedMenuItemElement._subMenuTimer);
        delete this._highlightedMenuItemElement._subMenuTimer;
      }
    }
    this._highlightedMenuItemElement = menuItemElement;
    if (this._highlightedMenuItemElement) {
      if (UI.themeSupport.hasTheme() || Host.isMac()) {
        this._highlightedMenuItemElement.classList.add('force-white-icons');
      }
      this._highlightedMenuItemElement.classList.add('soft-context-menu-item-mouse-over');
      if (this._highlightedMenuItemElement._customElement) {
        this._highlightedMenuItemElement._customElement.focus();
      } else {
        this._highlightedMenuItemElement.focus();
      }
      if (scheduleSubMenu && this._highlightedMenuItemElement._subItems &&
          !this._highlightedMenuItemElement._subMenuTimer) {
        this._highlightedMenuItemElement._subMenuTimer =
            setTimeout(this._showSubMenu.bind(this, this._highlightedMenuItemElement), 150);
      }
    }
  }

  _highlightPrevious() {
    let menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.previousSibling :
                                                             this._contextMenuElement.lastChild;
    while (menuItemElement &&
           (menuItemElement._isSeparator || menuItemElement.classList.contains('soft-context-menu-disabled'))) {
      menuItemElement = menuItemElement.previousSibling;
    }
    if (menuItemElement) {
      this._highlightMenuItem(menuItemElement, false);
    }
  }

  _highlightNext() {
    let menuItemElement = this._highlightedMenuItemElement ? this._highlightedMenuItemElement.nextSibling :
                                                             this._contextMenuElement.firstChild;
    while (menuItemElement &&
           (menuItemElement._isSeparator || menuItemElement.classList.contains('soft-context-menu-disabled'))) {
      menuItemElement = menuItemElement.nextSibling;
    }
    if (menuItemElement) {
      this._highlightMenuItem(menuItemElement, false);
    }
  }

  _menuKeyDown(event) {
    switch (event.key) {
      case 'ArrowUp':
        this._highlightPrevious();
        break;
      case 'ArrowDown':
        this._highlightNext();
        break;
      case 'ArrowLeft':
        if (this._parentMenu) {
          this._highlightMenuItem(null, false);
          this.discard();
        }
        break;
      case 'ArrowRight':
        if (!this._highlightedMenuItemElement) {
          break;
        }
        if (this._highlightedMenuItemElement._subItems) {
          this._showSubMenu(this._highlightedMenuItemElement);
          this._subMenu._highlightNext();
        }
        break;
      case 'Escape':
        this.discard();
        break;
      case 'Enter':
        if (!isEnterKey(event)) {
          return;
        }
      // Fall through
      case ' ':  // Space
        if (!this._highlightedMenuItemElement || this._highlightedMenuItemElement._customElement) {
          return;
        }
        this._triggerAction(this._highlightedMenuItemElement, event);
        if (this._highlightedMenuItemElement._subItems) {
          this._subMenu._highlightNext();
        }
        break;
    }
    event.consume(true);
  }
}

/* Legacy exported object*/
self.UI = self.UI || {};

/* Legacy exported object*/
UI = UI || {};

/** @constructor */
UI.SoftContextMenu = SoftContextMenu;
