// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as Common from '../common/common.js';
import * as Root from '../root/root.js';
import * as SDK from '../sdk/sdk.js';
import * as UI from '../ui/ui.js';

// eslint-disable-next-line rulesdir/es_modules_import
import type * as Elements from './elements.js';

import * as i18n from '../i18n/i18n.js';
export const UIStrings = {
  /**
  *@description Command for showing the 'Elements' tool
  */
  showElements: 'Show Elements',
  /**
  *@description Title of the Elements Panel
  */
  elements: 'Elements',
  /**
  *@description Command for showing the 'Event Listeners' tool
  */
  showEventListeners: 'Show Event Listeners',
  /**
  *@description Title of the 'Event Listeners' tool in the sidebar of the elements tool
  */
  eventListeners: 'Event Listeners',
  /**
  *@description Command for showing the 'Properties' tool
  */
  showProperties: 'Show Properties',
  /**
  *@description Title of the 'Properties' tool in the sidebar of the elements tool
  */
  properties: 'Properties',
  /**
  *@description Command for showing the 'Stack Trace' tool
  */
  showStackTrace: 'Show Stack Trace',
  /**
  *@description Text for the execution stack trace
  */
  stackTrace: 'Stack Trace',
  /**
  *@description Command for showing the 'Layout' tool
  */
  showLayout: 'Show Layout',
  /**
  *@description Text in Timeline UIUtils of the Performance panel
  */
  layout: 'Layout',
  /**
  *@description Text to hide an element
  */
  hideElement: 'Hide element',
  /**
  *@description A context menu item in the Elements Tree Element of the Elements panel
  */
  editAsHtml: 'Edit as HTML',
  /**
  *@description A context menu item in the Elements Tree Element of the Elements panel
  */
  duplicateElement: 'Duplicate element',
  /**
  *@description Title of an Elements panel action to undo changes.
  */
  undo: 'Undo',
  /**
  *@description Title of an Elements panel action to redo changes.
  */
  redo: 'Redo',
  /**
  *@description Title of an action in the elements tool to capture area screenshot
  */
  captureAreaScreenshot: 'Capture area screenshot',
  /**
  *@description Title of an action in the elements tool to toggle element search
  */
  selectAnElementInThePageTo: 'Select an element in the page to inspect it',
  /**
  *@description Title of a setting under the Elements category in Settings
  */
  showUserAgentShadowDom: 'Show `user agent shadow DOM`',
  /**
  *@description Title of a setting under the Elements category in Settings
  */
  wordWrap: 'Word wrap',
  /**
  *@description Title of a setting under the Elements category that can be invoked through the Command Menu
  */
  enableDomWordWrap: 'Enable DOM word wrap',
  /**
  *@description Title of a setting under the Elements category that can be invoked through the Command Menu
  */
  disableDomWordWrap: 'Disable DOM word wrap',
  /**
  *@description Title of a setting under the Elements category that can be invoked through the Command Menu
  */
  showHtmlComments: 'Show HTML comments',
  /**
  *@description Title of a setting under the Elements category that can be invoked through the Command Menu
  */
  hideHtmlComments: 'Hide HTML comments',
  /**
  *@description Title of a setting under the Elements category in Settings
  */
  revealDomNodeOnHover: 'Reveal DOM node on hover',
  /**
  *@description Title of a setting under the Elements category in Settings
  */
  showDetailedInspectTooltip: 'Show detailed inspect tooltip',
};
const str_ = i18n.i18n.registerUIStrings('elements/elements-meta.ts', UIStrings);
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);
let loadedElementsModule: (typeof Elements|undefined);

async function loadElementsModule(): Promise<typeof Elements> {
  if (!loadedElementsModule) {
    // Side-effect import resources in module.json
    await Root.Runtime.Runtime.instance().loadModulePromise('elements');
    loadedElementsModule = await import('./elements.js');
  }
  return loadedElementsModule;
}
function maybeRetrieveContextTypes<T = unknown>(getClassCallBack: (elementsModule: typeof Elements) => T[]): T[] {
  if (loadedElementsModule === undefined) {
    return [];
  }
  return getClassCallBack(loadedElementsModule);
}

UI.ViewManager.registerViewExtension({
  location: UI.ViewManager.ViewLocationValues.PANEL,
  id: 'elements',
  commandPrompt: i18nLazyString(UIStrings.showElements),
  title: i18nLazyString(UIStrings.elements),
  order: 10,
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
  hasToolbar: false,
  async loadView() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsPanel.instance();
  },
});

UI.ViewManager.registerViewExtension({
  location: UI.ViewManager.ViewLocationValues.ELEMENTS_SIDEBAR,
  id: 'elements.eventListeners',
  commandPrompt: i18nLazyString(UIStrings.showEventListeners),
  title: i18nLazyString(UIStrings.eventListeners),
  order: 5,
  hasToolbar: true,
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
  async loadView() {
    const Elements = await loadElementsModule();
    return Elements.EventListenersWidget.EventListenersWidget.instance();
  },
});

UI.ViewManager.registerViewExtension({
  location: UI.ViewManager.ViewLocationValues.ELEMENTS_SIDEBAR,
  id: 'elements.domProperties',
  commandPrompt: i18nLazyString(UIStrings.showProperties),
  title: i18nLazyString(UIStrings.properties),
  order: 7,
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
  async loadView() {
    const Elements = await loadElementsModule();
    return Elements.PropertiesWidget.PropertiesWidget.instance();
  },
});

UI.ViewManager.registerViewExtension({
  experiment: Root.Runtime.ExperimentName.CAPTURE_NODE_CREATION_STACKS,
  location: UI.ViewManager.ViewLocationValues.ELEMENTS_SIDEBAR,
  id: 'elements.domCreation',
  commandPrompt: i18nLazyString(UIStrings.showStackTrace),
  title: i18nLazyString(UIStrings.stackTrace),
  order: 10,
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
  async loadView() {
    const Elements = await loadElementsModule();
    return Elements.NodeStackTraceWidget.NodeStackTraceWidget.instance();
  },
});

UI.ViewManager.registerViewExtension({
  location: UI.ViewManager.ViewLocationValues.ELEMENTS_SIDEBAR,
  id: 'elements.layout',
  commandPrompt: i18nLazyString(UIStrings.showLayout),
  title: i18nLazyString(UIStrings.layout),
  order: 4,
  persistence: UI.ViewManager.ViewPersistence.PERMANENT,
  async loadView() {
    const Elements = await loadElementsModule();
    return Elements.LayoutSidebarPane.LayoutSidebarPane.instance();
  },
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.hide-element',
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  title: i18nLazyString(UIStrings.hideElement),
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsActionDelegate.instance();
  },
  contextTypes() {
    return maybeRetrieveContextTypes(Elements => [Elements.ElementsPanel.ElementsPanel]);
  },
  bindings: [
    {
      shortcut: 'H',
    },
  ],
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.edit-as-html',
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  title: i18nLazyString(UIStrings.editAsHtml),
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsActionDelegate.instance();
  },
  contextTypes() {
    return maybeRetrieveContextTypes(Elements => [Elements.ElementsPanel.ElementsPanel]);
  },
  bindings: [
    {
      shortcut: 'F2',
    },
  ],
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.duplicate-element',
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  title: i18nLazyString(UIStrings.duplicateElement),
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsActionDelegate.instance();
  },
  contextTypes() {
    return maybeRetrieveContextTypes(Elements => [Elements.ElementsPanel.ElementsPanel]);
  },
  bindings: [
    {
      shortcut: 'Shift+Alt+Down',
    },
  ],
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.undo',
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  title: i18nLazyString(UIStrings.undo),
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsActionDelegate.instance();
  },
  contextTypes() {
    return maybeRetrieveContextTypes(Elements => [Elements.ElementsPanel.ElementsPanel]);
  },
  bindings: [
    {
      shortcut: 'Ctrl+Z',
      platform: UI.ActionRegistration.Platforms.WindowsLinux,
    },
    {
      shortcut: 'Meta+Z',
      platform: UI.ActionRegistration.Platforms.Mac,
    },
  ],
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.redo',
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  title: i18nLazyString(UIStrings.redo),
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsActionDelegate.instance();
  },
  contextTypes() {
    return maybeRetrieveContextTypes(Elements => [Elements.ElementsPanel.ElementsPanel]);
  },
  bindings: [
    {
      shortcut: 'Ctrl+Y',
      platform: UI.ActionRegistration.Platforms.WindowsLinux,
    },
    {
      shortcut: 'Meta+Shift+Z',
      platform: UI.ActionRegistration.Platforms.Mac,
    },
  ],
});

UI.ActionRegistration.registerActionExtension({
  actionId: 'elements.capture-area-screenshot',
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.InspectElementModeController.ToggleSearchActionDelegate.instance();
  },
  condition: Root.Runtime.ConditionName.CAN_DOCK,
  title: i18nLazyString(UIStrings.captureAreaScreenshot),
  category: UI.ActionRegistration.ActionCategory.SCREENSHOT,
});

UI.ActionRegistration.registerActionExtension({
  category: UI.ActionRegistration.ActionCategory.ELEMENTS,
  actionId: 'elements.toggle-element-search',
  toggleable: true,
  async loadActionDelegate() {
    const Elements = await loadElementsModule();
    return Elements.InspectElementModeController.ToggleSearchActionDelegate.instance();
  },
  title: i18nLazyString(UIStrings.selectAnElementInThePageTo),
  iconClass: UI.ActionRegistration.IconClass.LARGEICON_NODE_SEARCH,
  bindings: [
    {
      shortcut: 'Ctrl+Shift+C',
      platform: UI.ActionRegistration.Platforms.WindowsLinux,
    },
    {
      shortcut: 'Meta+Shift+C',
      platform: UI.ActionRegistration.Platforms.Mac,
    },
  ],
});

Common.Settings.registerSettingExtension({
  category: Common.Settings.SettingCategory.ELEMENTS,
  order: 1,
  title: i18nLazyString('Show user agent shadow DOM'),
  settingName: 'showUAShadowDOM',
  settingType: Common.Settings.SettingType.BOOLEAN,
  defaultValue: false,
});

Common.Settings.registerSettingExtension({
  category: Common.Settings.SettingCategory.ELEMENTS,
  order: 2,
  title: i18nLazyString(UIStrings.wordWrap),
  settingName: 'domWordWrap',
  settingType: Common.Settings.SettingType.BOOLEAN,
  options: [
    {
      value: true,
      title: i18nLazyString(UIStrings.enableDomWordWrap),
    },
    {
      value: false,
      title: i18nLazyString(UIStrings.disableDomWordWrap),
    },
  ],
  defaultValue: true,
});

Common.Settings.registerSettingExtension({
  category: Common.Settings.SettingCategory.ELEMENTS,
  order: 3,
  title: i18nLazyString(UIStrings.showHtmlComments),
  settingName: 'showHTMLComments',
  settingType: Common.Settings.SettingType.BOOLEAN,
  defaultValue: true,
  options: [
    {
      value: true,
      title: i18nLazyString(UIStrings.showHtmlComments),
    },
    {
      value: false,
      title: i18nLazyString(UIStrings.hideHtmlComments),
    },
  ],
});

Common.Settings.registerSettingExtension({
  category: Common.Settings.SettingCategory.ELEMENTS,
  order: 4,
  title: i18nLazyString(UIStrings.revealDomNodeOnHover),
  settingName: 'highlightNodeOnHoverInOverlay',
  settingType: Common.Settings.SettingType.BOOLEAN,
  defaultValue: true,
});

Common.Settings.registerSettingExtension({
  category: Common.Settings.SettingCategory.ELEMENTS,
  order: 5,
  title: i18nLazyString(UIStrings.showDetailedInspectTooltip),
  settingName: 'showDetailedInspectTooltip',
  settingType: Common.Settings.SettingType.BOOLEAN,
  defaultValue: true,
});

Common.Settings.registerSettingExtension({
  settingName: 'showEventListenersForAncestors',
  settingType: Common.Settings.SettingType.BOOLEAN,
  defaultValue: true,
});

UI.ContextMenu.registerProvider({
  contextTypes() {
    return [
      SDK.RemoteObject.RemoteObject,
      SDK.DOMModel.DOMNode,
      SDK.DOMModel.DeferredDOMNode,
    ];
  },
  async loadProvider() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ContextMenuProvider.instance();
  },
  experiment: undefined,
});

UI.ViewManager.registerLocationResolver({
  name: UI.ViewManager.ViewLocationValues.ELEMENTS_SIDEBAR,
  category: UI.ViewManager.ViewLocationCategoryValues.ELEMENTS,
  async loadResolver() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.ElementsPanel.instance();
  },
});

Common.Revealer.registerRevealer({
  contextTypes() {
    return [
      SDK.DOMModel.DOMNode,
      SDK.DOMModel.DeferredDOMNode,
      SDK.RemoteObject.RemoteObject,
    ];
  },
  destination: Common.Revealer.RevealerDestination.ELEMENTS_PANEL,
  async loadRevealer() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.DOMNodeRevealer.instance();
  },
});

Common.Revealer.registerRevealer({
  contextTypes() {
    return [
      SDK.CSSProperty.CSSProperty,
    ];
  },
  destination: Common.Revealer.RevealerDestination.STYLES_SIDEBAR,
  async loadRevealer() {
    const Elements = await loadElementsModule();
    return Elements.ElementsPanel.CSSPropertyRevealer.instance();
  },
});

UI.Toolbar.registerToolbarItem({
  async loadItem() {
    const Elements = await loadElementsModule();
    return Elements.ElementStatePaneWidget.ButtonProvider.instance();
  },
  order: 1,
  location: UI.Toolbar.ToolbarItemLocation.STYLES_SIDEBARPANE_TOOLBAR,
  showLabel: undefined,
  condition: undefined,
  separator: undefined,
  actionId: undefined,
});

UI.Toolbar.registerToolbarItem({
  async loadItem() {
    const Elements = await loadElementsModule();
    return Elements.ClassesPaneWidget.ButtonProvider.instance();
  },
  order: 2,
  location: UI.Toolbar.ToolbarItemLocation.STYLES_SIDEBARPANE_TOOLBAR,
  showLabel: undefined,
  condition: undefined,
  separator: undefined,
  actionId: undefined,
});

UI.Toolbar.registerToolbarItem({
  async loadItem() {
    const Elements = await loadElementsModule();
    return Elements.StylesSidebarPane.ButtonProvider.instance();
  },
  order: 100,
  location: UI.Toolbar.ToolbarItemLocation.STYLES_SIDEBARPANE_TOOLBAR,
  showLabel: undefined,
  condition: undefined,
  separator: undefined,
  actionId: undefined,
});

UI.Toolbar.registerToolbarItem({
  actionId: 'elements.toggle-element-search',
  location: UI.Toolbar.ToolbarItemLocation.MAIN_TOOLBAR_LEFT,
  order: 0,
  showLabel: undefined,
  condition: undefined,
  separator: undefined,
  loadItem: undefined,
});

UI.UIUtils.registerRenderer({
  contextTypes() {
    return [SDK.DOMModel.DOMNode, SDK.DOMModel.DeferredDOMNode];
  },
  async loadRenderer() {
    const Elements = await loadElementsModule();
    return Elements.ElementsTreeOutline.Renderer.instance();
  },
});

Common.Linkifier.registerLinkifier({
  contextTypes() {
    return [
      SDK.DOMModel.DOMNode,
      SDK.DOMModel.DeferredDOMNode,
    ];
  },
  async loadLinkifier() {
    const Elements = await loadElementsModule();
    return Elements.DOMLinkifier.Linkifier.instance();
  },
});
