import { append, addDisposableListener, $ as $$1, addStandardDisposableListener, EventType } from "../../../browser/dom.mjs";
import { StandardKeyboardEvent } from "../../../browser/keyboardEvent.mjs";
import { ActionBar } from "../../../browser/ui/actionbar/actionbar.mjs";
import { IconLabel } from "../../../browser/ui/iconLabel/iconLabel.mjs";
import { KeybindingLabel } from "../../../browser/ui/keybindingLabel/keybindingLabel.mjs";
import { Action } from "../../../common/actions.mjs";
import { range } from "../../../common/arrays.mjs";
import { getCodiconAriaLabel } from "../../../common/codicons.mjs";
import { compareAnything } from "../../../common/comparers.mjs";
import { memoize } from "../../../common/decorators.mjs";
import { Emitter, Event } from "../../../common/event.mjs";
import { matchesFuzzyIconAware, parseLabelWithIcons } from "../../../common/iconLabels.mjs";
import { dispose } from "../../../common/lifecycle.mjs";
import { isMacintosh, OS } from "../../../common/platform.mjs";
import { withNullAsUndefined } from "../../../common/types.mjs";
import { getIconClass } from "./quickInputUtils.mjs";
import "./media/quickInput.css.mjs";
import { localize } from "../../../../nls.mjs";
var __decorate = globalThis && globalThis.__decorate || function(decorators, target, key, desc) {
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
    r = Reflect.decorate(decorators, target, key, desc);
  else
    for (var i = decorators.length - 1; i >= 0; i--)
      if (d = decorators[i])
        r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
  return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
const $ = $$1;
class ListElement {
  constructor(init) {
    this.hidden = false;
    this._onChecked = new Emitter();
    this.onChecked = this._onChecked.event;
    Object.assign(this, init);
  }
  get checked() {
    return !!this._checked;
  }
  set checked(value) {
    if (value !== this._checked) {
      this._checked = value;
      this._onChecked.fire(value);
    }
  }
  dispose() {
    this._onChecked.dispose();
  }
}
class ListElementRenderer {
  get templateId() {
    return ListElementRenderer.ID;
  }
  renderTemplate(container) {
    const data = /* @__PURE__ */ Object.create(null);
    data.toDisposeElement = [];
    data.toDisposeTemplate = [];
    data.entry = append(container, $(".quick-input-list-entry"));
    const label = append(data.entry, $("label.quick-input-list-label"));
    data.toDisposeTemplate.push(addStandardDisposableListener(label, EventType.CLICK, (e) => {
      if (!data.checkbox.offsetParent) {
        e.preventDefault();
      }
    }));
    data.checkbox = append(label, $("input.quick-input-list-checkbox"));
    data.checkbox.type = "checkbox";
    data.toDisposeTemplate.push(addStandardDisposableListener(data.checkbox, EventType.CHANGE, (e) => {
      data.element.checked = data.checkbox.checked;
    }));
    const rows = append(label, $(".quick-input-list-rows"));
    const row1 = append(rows, $(".quick-input-list-row"));
    const row2 = append(rows, $(".quick-input-list-row"));
    data.label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportIcons: true });
    const keybindingContainer = append(row1, $(".quick-input-list-entry-keybinding"));
    data.keybinding = new KeybindingLabel(keybindingContainer, OS);
    const detailContainer = append(row2, $(".quick-input-list-label-meta"));
    data.detail = new IconLabel(detailContainer, { supportHighlights: true, supportIcons: true });
    data.separator = append(data.entry, $(".quick-input-list-separator"));
    data.actionBar = new ActionBar(data.entry);
    data.actionBar.domNode.classList.add("quick-input-list-entry-action-bar");
    data.toDisposeTemplate.push(data.actionBar);
    return data;
  }
  renderElement(element, index, data) {
    data.toDisposeElement = dispose(data.toDisposeElement);
    data.element = element;
    data.checkbox.checked = element.checked;
    data.toDisposeElement.push(element.onChecked((checked) => data.checkbox.checked = checked));
    const { labelHighlights, descriptionHighlights, detailHighlights } = element;
    const options = /* @__PURE__ */ Object.create(null);
    options.matches = labelHighlights || [];
    options.descriptionTitle = element.saneDescription;
    options.descriptionMatches = descriptionHighlights || [];
    options.extraClasses = element.item.iconClasses;
    options.italic = element.item.italic;
    options.strikethrough = element.item.strikethrough;
    data.label.setLabel(element.saneLabel, element.saneDescription, options);
    data.keybinding.set(element.item.keybinding);
    if (element.saneDetail) {
      data.detail.setLabel(element.saneDetail, void 0, {
        matches: detailHighlights,
        title: element.saneDetail
      });
    }
    if (element.separator && element.separator.label) {
      data.separator.textContent = element.separator.label;
      data.separator.style.display = "";
    } else {
      data.separator.style.display = "none";
    }
    data.entry.classList.toggle("quick-input-list-separator-border", !!element.separator);
    data.actionBar.clear();
    const buttons = element.item.buttons;
    if (buttons && buttons.length) {
      data.actionBar.push(buttons.map((button, index2) => {
        let cssClasses = button.iconClass || (button.iconPath ? getIconClass(button.iconPath) : void 0);
        if (button.alwaysVisible) {
          cssClasses = cssClasses ? `${cssClasses} always-visible` : "always-visible";
        }
        const action = new Action(`id-${index2}`, "", cssClasses, true, () => __awaiter(this, void 0, void 0, function* () {
          element.fireButtonTriggered({
            button,
            item: element.item
          });
        }));
        action.tooltip = button.tooltip || "";
        return action;
      }), { icon: true, label: false });
      data.entry.classList.add("has-actions");
    } else {
      data.entry.classList.remove("has-actions");
    }
  }
  disposeElement(element, index, data) {
    data.toDisposeElement = dispose(data.toDisposeElement);
  }
  disposeTemplate(data) {
    data.toDisposeElement = dispose(data.toDisposeElement);
    data.toDisposeTemplate = dispose(data.toDisposeTemplate);
  }
}
ListElementRenderer.ID = "listelement";
class ListElementDelegate {
  getHeight(element) {
    return element.saneDetail ? 44 : 22;
  }
  getTemplateId(element) {
    return ListElementRenderer.ID;
  }
}
var QuickInputListFocus;
(function(QuickInputListFocus2) {
  QuickInputListFocus2[QuickInputListFocus2["First"] = 1] = "First";
  QuickInputListFocus2[QuickInputListFocus2["Second"] = 2] = "Second";
  QuickInputListFocus2[QuickInputListFocus2["Last"] = 3] = "Last";
  QuickInputListFocus2[QuickInputListFocus2["Next"] = 4] = "Next";
  QuickInputListFocus2[QuickInputListFocus2["Previous"] = 5] = "Previous";
  QuickInputListFocus2[QuickInputListFocus2["NextPage"] = 6] = "NextPage";
  QuickInputListFocus2[QuickInputListFocus2["PreviousPage"] = 7] = "PreviousPage";
})(QuickInputListFocus || (QuickInputListFocus = {}));
class QuickInputList {
  constructor(parent, id, options) {
    this.parent = parent;
    this.inputElements = [];
    this.elements = [];
    this.elementsToIndexes = /* @__PURE__ */ new Map();
    this.matchOnDescription = false;
    this.matchOnDetail = false;
    this.matchOnLabel = true;
    this.matchOnMeta = true;
    this.sortByLabel = true;
    this._onChangedAllVisibleChecked = new Emitter();
    this.onChangedAllVisibleChecked = this._onChangedAllVisibleChecked.event;
    this._onChangedCheckedCount = new Emitter();
    this.onChangedCheckedCount = this._onChangedCheckedCount.event;
    this._onChangedVisibleCount = new Emitter();
    this.onChangedVisibleCount = this._onChangedVisibleCount.event;
    this._onChangedCheckedElements = new Emitter();
    this.onChangedCheckedElements = this._onChangedCheckedElements.event;
    this._onButtonTriggered = new Emitter();
    this.onButtonTriggered = this._onButtonTriggered.event;
    this._onKeyDown = new Emitter();
    this.onKeyDown = this._onKeyDown.event;
    this._onLeave = new Emitter();
    this.onLeave = this._onLeave.event;
    this._fireCheckedEvents = true;
    this.elementDisposables = [];
    this.disposables = [];
    this.id = id;
    this.container = append(this.parent, $(".quick-input-list"));
    const delegate = new ListElementDelegate();
    const accessibilityProvider = new QuickInputAccessibilityProvider();
    this.list = options.createList("QuickInput", this.container, delegate, [new ListElementRenderer()], {
      identityProvider: { getId: (element) => element.saneLabel },
      setRowLineHeight: false,
      multipleSelectionSupport: false,
      horizontalScrolling: false,
      accessibilityProvider
    });
    this.list.getHTMLElement().id = id;
    this.disposables.push(this.list);
    this.disposables.push(this.list.onKeyDown((e) => {
      const event = new StandardKeyboardEvent(e);
      switch (event.keyCode) {
        case 10:
          this.toggleCheckbox();
          break;
        case 31:
          if (isMacintosh ? e.metaKey : e.ctrlKey) {
            this.list.setFocus(range(this.list.length));
          }
          break;
        case 16: {
          const focus1 = this.list.getFocus();
          if (focus1.length === 1 && focus1[0] === 0) {
            this._onLeave.fire();
          }
          break;
        }
        case 18: {
          const focus2 = this.list.getFocus();
          if (focus2.length === 1 && focus2[0] === this.list.length - 1) {
            this._onLeave.fire();
          }
          break;
        }
      }
      this._onKeyDown.fire(event);
    }));
    this.disposables.push(this.list.onMouseDown((e) => {
      if (e.browserEvent.button !== 2) {
        e.browserEvent.preventDefault();
      }
    }));
    this.disposables.push(addDisposableListener(this.container, EventType.CLICK, (e) => {
      if (e.x || e.y) {
        this._onLeave.fire();
      }
    }));
    this.disposables.push(this.list.onMouseMiddleClick((e) => {
      this._onLeave.fire();
    }));
    this.disposables.push(this.list.onContextMenu((e) => {
      if (typeof e.index === "number") {
        e.browserEvent.preventDefault();
        this.list.setSelection([e.index]);
      }
    }));
    this.disposables.push(this._onChangedAllVisibleChecked, this._onChangedCheckedCount, this._onChangedVisibleCount, this._onChangedCheckedElements, this._onButtonTriggered, this._onLeave, this._onKeyDown);
  }
  get onDidChangeFocus() {
    return Event.map(this.list.onDidChangeFocus, (e) => e.elements.map((e2) => e2.item));
  }
  get onDidChangeSelection() {
    return Event.map(this.list.onDidChangeSelection, (e) => ({ items: e.elements.map((e2) => e2.item), event: e.browserEvent }));
  }
  get scrollTop() {
    return this.list.scrollTop;
  }
  set scrollTop(scrollTop) {
    this.list.scrollTop = scrollTop;
  }
  getAllVisibleChecked() {
    return this.allVisibleChecked(this.elements, false);
  }
  allVisibleChecked(elements, whenNoneVisible = true) {
    for (let i = 0, n = elements.length; i < n; i++) {
      const element = elements[i];
      if (!element.hidden) {
        if (!element.checked) {
          return false;
        } else {
          whenNoneVisible = true;
        }
      }
    }
    return whenNoneVisible;
  }
  getCheckedCount() {
    let count = 0;
    const elements = this.elements;
    for (let i = 0, n = elements.length; i < n; i++) {
      if (elements[i].checked) {
        count++;
      }
    }
    return count;
  }
  getVisibleCount() {
    let count = 0;
    const elements = this.elements;
    for (let i = 0, n = elements.length; i < n; i++) {
      if (!elements[i].hidden) {
        count++;
      }
    }
    return count;
  }
  setAllVisibleChecked(checked) {
    try {
      this._fireCheckedEvents = false;
      this.elements.forEach((element) => {
        if (!element.hidden) {
          element.checked = checked;
        }
      });
    } finally {
      this._fireCheckedEvents = true;
      this.fireCheckedEvents();
    }
  }
  setElements(inputElements) {
    this.elementDisposables = dispose(this.elementDisposables);
    const fireButtonTriggered = (event) => this.fireButtonTriggered(event);
    this.inputElements = inputElements;
    this.elements = inputElements.reduce((result, item, index) => {
      var _a, _b, _c;
      if (item.type !== "separator") {
        const previous = index && inputElements[index - 1];
        const saneLabel = item.label && item.label.replace(/\r?\n/g, " ");
        const saneMeta = item.meta && item.meta.replace(/\r?\n/g, " ");
        const saneDescription = item.description && item.description.replace(/\r?\n/g, " ");
        const saneDetail = item.detail && item.detail.replace(/\r?\n/g, " ");
        const saneAriaLabel = item.ariaLabel || [saneLabel, saneDescription, saneDetail].map((s) => getCodiconAriaLabel(s)).filter((s) => !!s).join(", ");
        const hasCheckbox = this.parent.classList.contains("show-checkboxes");
        result.push(new ListElement({
          hasCheckbox,
          index,
          item,
          saneLabel,
          saneMeta,
          saneAriaLabel,
          saneDescription,
          saneDetail,
          labelHighlights: (_a = item.highlights) === null || _a === void 0 ? void 0 : _a.label,
          descriptionHighlights: (_b = item.highlights) === null || _b === void 0 ? void 0 : _b.description,
          detailHighlights: (_c = item.highlights) === null || _c === void 0 ? void 0 : _c.detail,
          checked: false,
          separator: previous && previous.type === "separator" ? previous : void 0,
          fireButtonTriggered
        }));
      }
      return result;
    }, []);
    this.elementDisposables.push(...this.elements);
    this.elementDisposables.push(...this.elements.map((element) => element.onChecked(() => this.fireCheckedEvents())));
    this.elementsToIndexes = this.elements.reduce((map, element, index) => {
      map.set(element.item, index);
      return map;
    }, /* @__PURE__ */ new Map());
    this.list.splice(0, this.list.length);
    this.list.splice(0, this.list.length, this.elements);
    this._onChangedVisibleCount.fire(this.elements.length);
  }
  getFocusedElements() {
    return this.list.getFocusedElements().map((e) => e.item);
  }
  setFocusedElements(items) {
    this.list.setFocus(items.filter((item) => this.elementsToIndexes.has(item)).map((item) => this.elementsToIndexes.get(item)));
    if (items.length > 0) {
      const focused = this.list.getFocus()[0];
      if (typeof focused === "number") {
        this.list.reveal(focused);
      }
    }
  }
  getActiveDescendant() {
    return this.list.getHTMLElement().getAttribute("aria-activedescendant");
  }
  setSelectedElements(items) {
    this.list.setSelection(items.filter((item) => this.elementsToIndexes.has(item)).map((item) => this.elementsToIndexes.get(item)));
  }
  getCheckedElements() {
    return this.elements.filter((e) => e.checked).map((e) => e.item);
  }
  setCheckedElements(items) {
    try {
      this._fireCheckedEvents = false;
      const checked = /* @__PURE__ */ new Set();
      for (const item of items) {
        checked.add(item);
      }
      for (const element of this.elements) {
        element.checked = checked.has(element.item);
      }
    } finally {
      this._fireCheckedEvents = true;
      this.fireCheckedEvents();
    }
  }
  set enabled(value) {
    this.list.getHTMLElement().style.pointerEvents = value ? "" : "none";
  }
  focus(what) {
    if (!this.list.length) {
      return;
    }
    if (what === QuickInputListFocus.Next && this.list.getFocus()[0] === this.list.length - 1) {
      what = QuickInputListFocus.First;
    }
    if (what === QuickInputListFocus.Previous && this.list.getFocus()[0] === 0) {
      what = QuickInputListFocus.Last;
    }
    if (what === QuickInputListFocus.Second && this.list.length < 2) {
      what = QuickInputListFocus.First;
    }
    switch (what) {
      case QuickInputListFocus.First:
        this.list.focusFirst();
        break;
      case QuickInputListFocus.Second:
        this.list.focusNth(1);
        break;
      case QuickInputListFocus.Last:
        this.list.focusLast();
        break;
      case QuickInputListFocus.Next:
        this.list.focusNext();
        break;
      case QuickInputListFocus.Previous:
        this.list.focusPrevious();
        break;
      case QuickInputListFocus.NextPage:
        this.list.focusNextPage();
        break;
      case QuickInputListFocus.PreviousPage:
        this.list.focusPreviousPage();
        break;
    }
    const focused = this.list.getFocus()[0];
    if (typeof focused === "number") {
      this.list.reveal(focused);
    }
  }
  clearFocus() {
    this.list.setFocus([]);
  }
  domFocus() {
    this.list.domFocus();
  }
  layout(maxHeight) {
    this.list.getHTMLElement().style.maxHeight = maxHeight ? `calc(${Math.floor(maxHeight / 44) * 44}px)` : "";
    this.list.layout();
  }
  filter(query) {
    if (!(this.sortByLabel || this.matchOnLabel || this.matchOnDescription || this.matchOnDetail)) {
      this.list.layout();
      return false;
    }
    query = query.trim();
    if (!query || !(this.matchOnLabel || this.matchOnDescription || this.matchOnDetail)) {
      this.elements.forEach((element) => {
        element.labelHighlights = void 0;
        element.descriptionHighlights = void 0;
        element.detailHighlights = void 0;
        element.hidden = false;
        const previous = element.index && this.inputElements[element.index - 1];
        element.separator = previous && previous.type === "separator" ? previous : void 0;
      });
    } else {
      let currentSeparator;
      this.elements.forEach((element) => {
        const labelHighlights = this.matchOnLabel ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneLabel))) : void 0;
        const descriptionHighlights = this.matchOnDescription ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDescription || ""))) : void 0;
        const detailHighlights = this.matchOnDetail ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneDetail || ""))) : void 0;
        const metaHighlights = this.matchOnMeta ? withNullAsUndefined(matchesFuzzyIconAware(query, parseLabelWithIcons(element.saneMeta || ""))) : void 0;
        if (labelHighlights || descriptionHighlights || detailHighlights || metaHighlights) {
          element.labelHighlights = labelHighlights;
          element.descriptionHighlights = descriptionHighlights;
          element.detailHighlights = detailHighlights;
          element.hidden = false;
        } else {
          element.labelHighlights = void 0;
          element.descriptionHighlights = void 0;
          element.detailHighlights = void 0;
          element.hidden = !element.item.alwaysShow;
        }
        element.separator = void 0;
        if (!this.sortByLabel) {
          const previous = element.index && this.inputElements[element.index - 1];
          currentSeparator = previous && previous.type === "separator" ? previous : currentSeparator;
          if (currentSeparator && !element.hidden) {
            element.separator = currentSeparator;
            currentSeparator = void 0;
          }
        }
      });
    }
    const shownElements = this.elements.filter((element) => !element.hidden);
    if (this.sortByLabel && query) {
      const normalizedSearchValue = query.toLowerCase();
      shownElements.sort((a, b) => {
        return compareEntries(a, b, normalizedSearchValue);
      });
    }
    this.elementsToIndexes = shownElements.reduce((map, element, index) => {
      map.set(element.item, index);
      return map;
    }, /* @__PURE__ */ new Map());
    this.list.splice(0, this.list.length, shownElements);
    this.list.setFocus([]);
    this.list.layout();
    this._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());
    this._onChangedVisibleCount.fire(shownElements.length);
    return true;
  }
  toggleCheckbox() {
    try {
      this._fireCheckedEvents = false;
      const elements = this.list.getFocusedElements();
      const allChecked = this.allVisibleChecked(elements);
      for (const element of elements) {
        element.checked = !allChecked;
      }
    } finally {
      this._fireCheckedEvents = true;
      this.fireCheckedEvents();
    }
  }
  display(display) {
    this.container.style.display = display ? "" : "none";
  }
  isDisplayed() {
    return this.container.style.display !== "none";
  }
  dispose() {
    this.elementDisposables = dispose(this.elementDisposables);
    this.disposables = dispose(this.disposables);
  }
  fireCheckedEvents() {
    if (this._fireCheckedEvents) {
      this._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());
      this._onChangedCheckedCount.fire(this.getCheckedCount());
      this._onChangedCheckedElements.fire(this.getCheckedElements());
    }
  }
  fireButtonTriggered(event) {
    this._onButtonTriggered.fire(event);
  }
  style(styles) {
    this.list.style(styles);
  }
}
__decorate([
  memoize
], QuickInputList.prototype, "onDidChangeFocus", null);
__decorate([
  memoize
], QuickInputList.prototype, "onDidChangeSelection", null);
function compareEntries(elementA, elementB, lookFor) {
  const labelHighlightsA = elementA.labelHighlights || [];
  const labelHighlightsB = elementB.labelHighlights || [];
  if (labelHighlightsA.length && !labelHighlightsB.length) {
    return -1;
  }
  if (!labelHighlightsA.length && labelHighlightsB.length) {
    return 1;
  }
  if (labelHighlightsA.length === 0 && labelHighlightsB.length === 0) {
    return 0;
  }
  return compareAnything(elementA.saneLabel, elementB.saneLabel, lookFor);
}
class QuickInputAccessibilityProvider {
  getWidgetAriaLabel() {
    return localize("quickInput", "Quick Input");
  }
  getAriaLabel(element) {
    return element.saneAriaLabel;
  }
  getWidgetRole() {
    return "listbox";
  }
  getRole(element) {
    return element.hasCheckbox ? "checkbox" : "option";
  }
  isChecked(element) {
    if (!element.hasCheckbox) {
      return void 0;
    }
    return {
      value: element.checked,
      onDidChange: element.onChecked
    };
  }
}
export {
  QuickInputList,
  QuickInputListFocus
};
