import { addDisposableListener, EventType, trackFocus, getActiveElement, isAncestor, EventHelper, clearNode } from "../../dom.mjs";
import { StandardKeyboardEvent } from "../../keyboardEvent.mjs";
import { BaseActionViewItem, ActionViewItem } from "./actionViewItems.mjs";
import { ActionRunner } from "../../../common/actions.mjs";
import { Emitter } from "../../../common/event.mjs";
import { Disposable, dispose } from "../../../common/lifecycle.mjs";
import { isNumber, isFunction } from "../../../common/types.mjs";
import "./actionbar.css.mjs";
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());
  });
};
class ActionBar extends Disposable {
  constructor(container, options = {}) {
    var _a, _b, _c, _d, _e, _f;
    super();
    this.triggerKeyDown = false;
    this.focusable = true;
    this._onDidBlur = this._register(new Emitter());
    this.onDidBlur = this._onDidBlur.event;
    this._onDidCancel = this._register(new Emitter({ onFirstListenerAdd: () => this.cancelHasListener = true }));
    this.onDidCancel = this._onDidCancel.event;
    this.cancelHasListener = false;
    this._onDidRun = this._register(new Emitter());
    this.onDidRun = this._onDidRun.event;
    this._onBeforeRun = this._register(new Emitter());
    this.onBeforeRun = this._onBeforeRun.event;
    this.options = options;
    this._context = (_a = options.context) !== null && _a !== void 0 ? _a : null;
    this._orientation = (_b = this.options.orientation) !== null && _b !== void 0 ? _b : 0;
    this._triggerKeys = {
      keyDown: (_d = (_c = this.options.triggerKeys) === null || _c === void 0 ? void 0 : _c.keyDown) !== null && _d !== void 0 ? _d : false,
      keys: (_f = (_e = this.options.triggerKeys) === null || _e === void 0 ? void 0 : _e.keys) !== null && _f !== void 0 ? _f : [
        3,
        10
        /* Space */
      ]
    };
    if (this.options.actionRunner) {
      this._actionRunner = this.options.actionRunner;
    } else {
      this._actionRunner = new ActionRunner();
      this._register(this._actionRunner);
    }
    this._register(this._actionRunner.onDidRun((e) => this._onDidRun.fire(e)));
    this._register(this._actionRunner.onBeforeRun((e) => this._onBeforeRun.fire(e)));
    this._actionIds = [];
    this.viewItems = [];
    this.focusedItem = void 0;
    this.domNode = document.createElement("div");
    this.domNode.className = "monaco-action-bar";
    if (options.animated !== false) {
      this.domNode.classList.add("animated");
    }
    let previousKeys;
    let nextKeys;
    switch (this._orientation) {
      case 0:
        previousKeys = [
          15
          /* LeftArrow */
        ];
        nextKeys = [
          17
          /* RightArrow */
        ];
        break;
      case 1:
        previousKeys = [
          16
          /* UpArrow */
        ];
        nextKeys = [
          18
          /* DownArrow */
        ];
        this.domNode.className += " vertical";
        break;
    }
    this._register(addDisposableListener(this.domNode, EventType.KEY_DOWN, (e) => {
      const event = new StandardKeyboardEvent(e);
      let eventHandled = true;
      const focusedItem = typeof this.focusedItem === "number" ? this.viewItems[this.focusedItem] : void 0;
      if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {
        eventHandled = this.focusPrevious();
      } else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) {
        eventHandled = this.focusNext();
      } else if (event.equals(
        9
        /* Escape */
      ) && this.cancelHasListener) {
        this._onDidCancel.fire();
      } else if (event.equals(
        14
        /* Home */
      )) {
        eventHandled = this.focusFirst();
      } else if (event.equals(
        13
        /* End */
      )) {
        eventHandled = this.focusLast();
      } else if (event.equals(
        2
        /* Tab */
      ) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
        eventHandled = this.focusNext();
      } else if (this.isTriggerKeyEvent(event)) {
        if (this._triggerKeys.keyDown) {
          this.doTrigger(event);
        } else {
          this.triggerKeyDown = true;
        }
      } else {
        eventHandled = false;
      }
      if (eventHandled) {
        event.preventDefault();
        event.stopPropagation();
      }
    }));
    this._register(addDisposableListener(this.domNode, EventType.KEY_UP, (e) => {
      const event = new StandardKeyboardEvent(e);
      if (this.isTriggerKeyEvent(event)) {
        if (!this._triggerKeys.keyDown && this.triggerKeyDown) {
          this.triggerKeyDown = false;
          this.doTrigger(event);
        }
        event.preventDefault();
        event.stopPropagation();
      } else if (event.equals(
        2
        /* Tab */
      ) || event.equals(
        1024 | 2
        /* Tab */
      )) {
        this.updateFocusedItem();
      }
    }));
    this.focusTracker = this._register(trackFocus(this.domNode));
    this._register(this.focusTracker.onDidBlur(() => {
      if (getActiveElement() === this.domNode || !isAncestor(getActiveElement(), this.domNode)) {
        this._onDidBlur.fire();
        this.focusedItem = void 0;
        this.previouslyFocusedItem = void 0;
        this.triggerKeyDown = false;
      }
    }));
    this._register(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));
    this.actionsList = document.createElement("ul");
    this.actionsList.className = "actions-container";
    this.actionsList.setAttribute("role", "toolbar");
    if (this.options.ariaLabel) {
      this.actionsList.setAttribute("aria-label", this.options.ariaLabel);
    }
    this.domNode.appendChild(this.actionsList);
    container.appendChild(this.domNode);
  }
  refreshRole() {
    if (this.length() >= 2) {
      this.actionsList.setAttribute("role", "toolbar");
    } else {
      this.actionsList.setAttribute("role", "presentation");
    }
  }
  // Some action bars should not be focusable at times
  // When an action bar is not focusable make sure to make all the elements inside it not focusable
  // When an action bar is focusable again, make sure the first item can be focused
  setFocusable(focusable) {
    this.focusable = focusable;
    if (this.focusable) {
      const firstEnabled = this.viewItems.find((vi) => vi instanceof BaseActionViewItem && vi.isEnabled());
      if (firstEnabled instanceof BaseActionViewItem) {
        firstEnabled.setFocusable(true);
      }
    } else {
      this.viewItems.forEach((vi) => {
        if (vi instanceof BaseActionViewItem) {
          vi.setFocusable(false);
        }
      });
    }
  }
  isTriggerKeyEvent(event) {
    let ret = false;
    this._triggerKeys.keys.forEach((keyCode) => {
      ret = ret || event.equals(keyCode);
    });
    return ret;
  }
  updateFocusedItem() {
    for (let i = 0; i < this.actionsList.children.length; i++) {
      const elem = this.actionsList.children[i];
      if (isAncestor(getActiveElement(), elem)) {
        this.focusedItem = i;
        break;
      }
    }
  }
  get context() {
    return this._context;
  }
  set context(context) {
    this._context = context;
    this.viewItems.forEach((i) => i.setActionContext(context));
  }
  get actionRunner() {
    return this._actionRunner;
  }
  set actionRunner(actionRunner) {
    if (actionRunner) {
      this._actionRunner = actionRunner;
      this.viewItems.forEach((item) => item.actionRunner = actionRunner);
    }
  }
  getContainer() {
    return this.domNode;
  }
  push(arg, options = {}) {
    const actions = Array.isArray(arg) ? arg : [arg];
    let index = isNumber(options.index) ? options.index : null;
    actions.forEach((action) => {
      const actionViewItemElement = document.createElement("li");
      actionViewItemElement.className = "action-item";
      actionViewItemElement.setAttribute("role", "presentation");
      if (!this.options.allowContextMenu) {
        this._register(addDisposableListener(actionViewItemElement, EventType.CONTEXT_MENU, (e) => {
          EventHelper.stop(e, true);
        }));
      }
      let item;
      if (this.options.actionViewItemProvider) {
        item = this.options.actionViewItemProvider(action);
      }
      if (!item) {
        item = new ActionViewItem(this.context, action, options);
      }
      item.actionRunner = this._actionRunner;
      item.setActionContext(this.context);
      item.render(actionViewItemElement);
      if (this.focusable && item instanceof BaseActionViewItem && this.viewItems.length === 0) {
        item.setFocusable(true);
      }
      if (index === null || index < 0 || index >= this.actionsList.children.length) {
        this.actionsList.appendChild(actionViewItemElement);
        this.viewItems.push(item);
        this._actionIds.push(action.id);
      } else {
        this.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]);
        this.viewItems.splice(index, 0, item);
        this._actionIds.splice(index, 0, action.id);
        index++;
      }
    });
    if (typeof this.focusedItem === "number") {
      this.focus(this.focusedItem);
    }
    this.refreshRole();
  }
  clear() {
    dispose(this.viewItems);
    this.viewItems = [];
    this._actionIds = [];
    clearNode(this.actionsList);
    this.refreshRole();
  }
  length() {
    return this.viewItems.length;
  }
  focus(arg) {
    let selectFirst = false;
    let index = void 0;
    if (arg === void 0) {
      selectFirst = true;
    } else if (typeof arg === "number") {
      index = arg;
    } else if (typeof arg === "boolean") {
      selectFirst = arg;
    }
    if (selectFirst && typeof this.focusedItem === "undefined") {
      const firstEnabled = this.viewItems.findIndex((item) => item.isEnabled());
      this.focusedItem = firstEnabled === -1 ? void 0 : firstEnabled;
      this.updateFocus(void 0, void 0, true);
    } else {
      if (index !== void 0) {
        this.focusedItem = index;
      }
      this.updateFocus(void 0, void 0, true);
    }
  }
  focusFirst() {
    this.focusedItem = this.length() - 1;
    return this.focusNext(true);
  }
  focusLast() {
    this.focusedItem = 0;
    return this.focusPrevious(true);
  }
  focusNext(forceLoop) {
    if (typeof this.focusedItem === "undefined") {
      this.focusedItem = this.viewItems.length - 1;
    } else if (this.viewItems.length <= 1) {
      return false;
    }
    const startIndex = this.focusedItem;
    let item;
    do {
      if (!forceLoop && this.options.preventLoopNavigation && this.focusedItem + 1 >= this.viewItems.length) {
        this.focusedItem = startIndex;
        return false;
      }
      this.focusedItem = (this.focusedItem + 1) % this.viewItems.length;
      item = this.viewItems[this.focusedItem];
    } while (this.focusedItem !== startIndex && this.options.focusOnlyEnabledItems && !item.isEnabled());
    this.updateFocus();
    return true;
  }
  focusPrevious(forceLoop) {
    if (typeof this.focusedItem === "undefined") {
      this.focusedItem = 0;
    } else if (this.viewItems.length <= 1) {
      return false;
    }
    const startIndex = this.focusedItem;
    let item;
    do {
      this.focusedItem = this.focusedItem - 1;
      if (this.focusedItem < 0) {
        if (!forceLoop && this.options.preventLoopNavigation) {
          this.focusedItem = startIndex;
          return false;
        }
        this.focusedItem = this.viewItems.length - 1;
      }
      item = this.viewItems[this.focusedItem];
    } while (this.focusedItem !== startIndex && this.options.focusOnlyEnabledItems && !item.isEnabled());
    this.updateFocus(true);
    return true;
  }
  updateFocus(fromRight, preventScroll, forceFocus = false) {
    var _a;
    if (typeof this.focusedItem === "undefined") {
      this.actionsList.focus({ preventScroll });
    }
    if (this.previouslyFocusedItem !== void 0 && this.previouslyFocusedItem !== this.focusedItem) {
      (_a = this.viewItems[this.previouslyFocusedItem]) === null || _a === void 0 ? void 0 : _a.blur();
    }
    const actionViewItem = this.focusedItem !== void 0 && this.viewItems[this.focusedItem];
    if (actionViewItem) {
      let focusItem = true;
      if (!isFunction(actionViewItem.focus)) {
        focusItem = false;
      }
      if (this.options.focusOnlyEnabledItems && isFunction(actionViewItem.isEnabled) && !actionViewItem.isEnabled()) {
        focusItem = false;
      }
      if (!focusItem) {
        this.actionsList.focus({ preventScroll });
        this.previouslyFocusedItem = void 0;
      } else if (forceFocus || this.previouslyFocusedItem !== this.focusedItem) {
        actionViewItem.focus(fromRight);
        this.previouslyFocusedItem = this.focusedItem;
      }
    }
  }
  doTrigger(event) {
    if (typeof this.focusedItem === "undefined") {
      return;
    }
    const actionViewItem = this.viewItems[this.focusedItem];
    if (actionViewItem instanceof BaseActionViewItem) {
      const context = actionViewItem._context === null || actionViewItem._context === void 0 ? event : actionViewItem._context;
      this.run(actionViewItem._action, context);
    }
  }
  run(action, context) {
    return __awaiter(this, void 0, void 0, function* () {
      yield this._actionRunner.run(action, context);
    });
  }
  dispose() {
    dispose(this.viewItems);
    this.viewItems = [];
    this._actionIds = [];
    this.getContainer().remove();
    super.dispose();
  }
}
export {
  ActionBar
};
