"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dom = require("../../dom.js");
const event$1 = require("../../event.js");
const touch = require("../../touch.js");
const async = require("../../../common/async.js");
const decorators = require("../../../common/decorators.js");
const event = require("../../../common/event.js");
const lifecycle = require("../../../common/lifecycle.js");
const platform = require("../../../common/platform.js");
require("./sash.css.js");
var __decorate = globalThis && globalThis.__decorate || function(decorators2, 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(decorators2, target, key, desc);
  else
    for (var i = decorators2.length - 1; i >= 0; i--)
      if (d = decorators2[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;
};
let DEBUG = false;
exports.OrthogonalEdge = void 0;
(function(OrthogonalEdge) {
  OrthogonalEdge["North"] = "north";
  OrthogonalEdge["South"] = "south";
  OrthogonalEdge["East"] = "east";
  OrthogonalEdge["West"] = "west";
})(exports.OrthogonalEdge || (exports.OrthogonalEdge = {}));
let globalSize = 4;
const onDidChangeGlobalSize = new event.Emitter();
let globalHoverDelay = 300;
const onDidChangeHoverDelay = new event.Emitter();
class MouseEventFactory {
  constructor() {
    this.disposables = new lifecycle.DisposableStore();
  }
  get onPointerMove() {
    return this.disposables.add(new event$1.DomEmitter(window, "mousemove")).event;
  }
  get onPointerUp() {
    return this.disposables.add(new event$1.DomEmitter(window, "mouseup")).event;
  }
  dispose() {
    this.disposables.dispose();
  }
}
__decorate([
  decorators.memoize
], MouseEventFactory.prototype, "onPointerMove", null);
__decorate([
  decorators.memoize
], MouseEventFactory.prototype, "onPointerUp", null);
class GestureEventFactory {
  constructor(el) {
    this.el = el;
    this.disposables = new lifecycle.DisposableStore();
  }
  get onPointerMove() {
    return this.disposables.add(new event$1.DomEmitter(this.el, touch.EventType.Change)).event;
  }
  get onPointerUp() {
    return this.disposables.add(new event$1.DomEmitter(this.el, touch.EventType.End)).event;
  }
  dispose() {
    this.disposables.dispose();
  }
}
__decorate([
  decorators.memoize
], GestureEventFactory.prototype, "onPointerMove", null);
__decorate([
  decorators.memoize
], GestureEventFactory.prototype, "onPointerUp", null);
class OrthogonalPointerEventFactory {
  constructor(factory) {
    this.factory = factory;
  }
  get onPointerMove() {
    return this.factory.onPointerMove;
  }
  get onPointerUp() {
    return this.factory.onPointerUp;
  }
  dispose() {
  }
}
__decorate([
  decorators.memoize
], OrthogonalPointerEventFactory.prototype, "onPointerMove", null);
__decorate([
  decorators.memoize
], OrthogonalPointerEventFactory.prototype, "onPointerUp", null);
const PointerEventsDisabledCssClass = "pointer-events-disabled";
class Sash extends lifecycle.Disposable {
  constructor(container, layoutProvider, options) {
    super();
    this.hoverDelay = globalHoverDelay;
    this.hoverDelayer = this._register(new async.Delayer(this.hoverDelay));
    this._state = 3;
    this.onDidEnablementChange = this._register(new event.Emitter());
    this._onDidStart = this._register(new event.Emitter());
    this._onDidChange = this._register(new event.Emitter());
    this._onDidReset = this._register(new event.Emitter());
    this._onDidEnd = this._register(new event.Emitter());
    this.orthogonalStartSashDisposables = this._register(new lifecycle.DisposableStore());
    this.orthogonalStartDragHandleDisposables = this._register(new lifecycle.DisposableStore());
    this.orthogonalEndSashDisposables = this._register(new lifecycle.DisposableStore());
    this.orthogonalEndDragHandleDisposables = this._register(new lifecycle.DisposableStore());
    this.onDidStart = this._onDidStart.event;
    this.onDidChange = this._onDidChange.event;
    this.onDidReset = this._onDidReset.event;
    this.onDidEnd = this._onDidEnd.event;
    this.linkedSash = void 0;
    this.el = dom.append(container, dom.$(".monaco-sash"));
    if (options.orthogonalEdge) {
      this.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`);
    }
    if (platform.isMacintosh) {
      this.el.classList.add("mac");
    }
    const onMouseDown = this._register(new event$1.DomEmitter(this.el, "mousedown")).event;
    this._register(onMouseDown((e) => this.onPointerStart(e, new MouseEventFactory()), this));
    const onMouseDoubleClick = this._register(new event$1.DomEmitter(this.el, "dblclick")).event;
    this._register(onMouseDoubleClick(this.onPointerDoublePress, this));
    const onMouseEnter = this._register(new event$1.DomEmitter(this.el, "mouseenter")).event;
    this._register(onMouseEnter(() => Sash.onMouseEnter(this)));
    const onMouseLeave = this._register(new event$1.DomEmitter(this.el, "mouseleave")).event;
    this._register(onMouseLeave(() => Sash.onMouseLeave(this)));
    this._register(touch.Gesture.addTarget(this.el));
    const onTouchStart = event.Event.map(this._register(new event$1.DomEmitter(this.el, touch.EventType.Start)).event, (e) => {
      var _a;
      return Object.assign(Object.assign({}, e), { target: (_a = e.initialTarget) !== null && _a !== void 0 ? _a : null });
    });
    this._register(onTouchStart((e) => this.onPointerStart(e, new GestureEventFactory(this.el)), this));
    const onTap = this._register(new event$1.DomEmitter(this.el, touch.EventType.Tap)).event;
    const onDoubleTap = event.Event.map(event.Event.filter(event.Event.debounce(onTap, (res, event2) => {
      var _a;
      return { event: event2, count: ((_a = res === null || res === void 0 ? void 0 : res.count) !== null && _a !== void 0 ? _a : 0) + 1 };
    }, 250), ({ count }) => count === 2), ({ event: event2 }) => {
      var _a;
      return Object.assign(Object.assign({}, event2), { target: (_a = event2.initialTarget) !== null && _a !== void 0 ? _a : null });
    });
    this._register(onDoubleTap(this.onPointerDoublePress, this));
    if (typeof options.size === "number") {
      this.size = options.size;
      if (options.orientation === 0) {
        this.el.style.width = `${this.size}px`;
      } else {
        this.el.style.height = `${this.size}px`;
      }
    } else {
      this.size = globalSize;
      this._register(onDidChangeGlobalSize.event((size) => {
        this.size = size;
        this.layout();
      }));
    }
    this._register(onDidChangeHoverDelay.event((delay) => this.hoverDelay = delay));
    this.layoutProvider = layoutProvider;
    this.orthogonalStartSash = options.orthogonalStartSash;
    this.orthogonalEndSash = options.orthogonalEndSash;
    this.orientation = options.orientation || 0;
    if (this.orientation === 1) {
      this.el.classList.add("horizontal");
      this.el.classList.remove("vertical");
    } else {
      this.el.classList.remove("horizontal");
      this.el.classList.add("vertical");
    }
    this.el.classList.toggle("debug", DEBUG);
    this.layout();
  }
  get state() {
    return this._state;
  }
  get orthogonalStartSash() {
    return this._orthogonalStartSash;
  }
  get orthogonalEndSash() {
    return this._orthogonalEndSash;
  }
  /**
   * The state of a sash defines whether it can be interacted with by the user
   * as well as what mouse cursor to use, when hovered.
   */
  set state(state) {
    if (this._state === state) {
      return;
    }
    this.el.classList.toggle(
      "disabled",
      state === 0
      /* Disabled */
    );
    this.el.classList.toggle(
      "minimum",
      state === 1
      /* AtMinimum */
    );
    this.el.classList.toggle(
      "maximum",
      state === 2
      /* AtMaximum */
    );
    this._state = state;
    this.onDidEnablementChange.fire(state);
  }
  /**
   * A reference to another sash, perpendicular to this one, which
   * aligns at the start of this one. A corner sash will be created
   * automatically at that location.
   *
   * The start of a horizontal sash is its left-most position.
   * The start of a vertical sash is its top-most position.
   */
  set orthogonalStartSash(sash) {
    this.orthogonalStartDragHandleDisposables.clear();
    this.orthogonalStartSashDisposables.clear();
    if (sash) {
      const onChange = (state) => {
        this.orthogonalStartDragHandleDisposables.clear();
        if (state !== 0) {
          this._orthogonalStartDragHandle = dom.append(this.el, dom.$(".orthogonal-drag-handle.start"));
          this.orthogonalStartDragHandleDisposables.add(lifecycle.toDisposable(() => this._orthogonalStartDragHandle.remove()));
          this.orthogonalStartDragHandleDisposables.add(new event$1.DomEmitter(this._orthogonalStartDragHandle, "mouseenter")).event(() => Sash.onMouseEnter(sash), void 0, this.orthogonalStartDragHandleDisposables);
          this.orthogonalStartDragHandleDisposables.add(new event$1.DomEmitter(this._orthogonalStartDragHandle, "mouseleave")).event(() => Sash.onMouseLeave(sash), void 0, this.orthogonalStartDragHandleDisposables);
        }
      };
      this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
      onChange(sash.state);
    }
    this._orthogonalStartSash = sash;
  }
  /**
   * A reference to another sash, perpendicular to this one, which
   * aligns at the end of this one. A corner sash will be created
   * automatically at that location.
   *
   * The end of a horizontal sash is its right-most position.
   * The end of a vertical sash is its bottom-most position.
   */
  set orthogonalEndSash(sash) {
    this.orthogonalEndDragHandleDisposables.clear();
    this.orthogonalEndSashDisposables.clear();
    if (sash) {
      const onChange = (state) => {
        this.orthogonalEndDragHandleDisposables.clear();
        if (state !== 0) {
          this._orthogonalEndDragHandle = dom.append(this.el, dom.$(".orthogonal-drag-handle.end"));
          this.orthogonalEndDragHandleDisposables.add(lifecycle.toDisposable(() => this._orthogonalEndDragHandle.remove()));
          this.orthogonalEndDragHandleDisposables.add(new event$1.DomEmitter(this._orthogonalEndDragHandle, "mouseenter")).event(() => Sash.onMouseEnter(sash), void 0, this.orthogonalEndDragHandleDisposables);
          this.orthogonalEndDragHandleDisposables.add(new event$1.DomEmitter(this._orthogonalEndDragHandle, "mouseleave")).event(() => Sash.onMouseLeave(sash), void 0, this.orthogonalEndDragHandleDisposables);
        }
      };
      this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
      onChange(sash.state);
    }
    this._orthogonalEndSash = sash;
  }
  onPointerStart(event2, pointerEventFactory) {
    dom.EventHelper.stop(event2);
    let isMultisashResize = false;
    if (!event2.__orthogonalSashEvent) {
      const orthogonalSash = this.getOrthogonalSash(event2);
      if (orthogonalSash) {
        isMultisashResize = true;
        event2.__orthogonalSashEvent = true;
        orthogonalSash.onPointerStart(event2, new OrthogonalPointerEventFactory(pointerEventFactory));
      }
    }
    if (this.linkedSash && !event2.__linkedSashEvent) {
      event2.__linkedSashEvent = true;
      this.linkedSash.onPointerStart(event2, new OrthogonalPointerEventFactory(pointerEventFactory));
    }
    if (!this.state) {
      return;
    }
    const iframes = dom.getElementsByTagName("iframe");
    for (const iframe of iframes) {
      iframe.classList.add(PointerEventsDisabledCssClass);
    }
    const startX = event2.pageX;
    const startY = event2.pageY;
    const altKey = event2.altKey;
    const startEvent = { startX, currentX: startX, startY, currentY: startY, altKey };
    this.el.classList.add("active");
    this._onDidStart.fire(startEvent);
    const style = dom.createStyleSheet(this.el);
    const updateStyle = () => {
      let cursor = "";
      if (isMultisashResize) {
        cursor = "all-scroll";
      } else if (this.orientation === 1) {
        if (this.state === 1) {
          cursor = "s-resize";
        } else if (this.state === 2) {
          cursor = "n-resize";
        } else {
          cursor = platform.isMacintosh ? "row-resize" : "ns-resize";
        }
      } else {
        if (this.state === 1) {
          cursor = "e-resize";
        } else if (this.state === 2) {
          cursor = "w-resize";
        } else {
          cursor = platform.isMacintosh ? "col-resize" : "ew-resize";
        }
      }
      style.textContent = `* { cursor: ${cursor} !important; }`;
    };
    const disposables = new lifecycle.DisposableStore();
    updateStyle();
    if (!isMultisashResize) {
      this.onDidEnablementChange.event(updateStyle, null, disposables);
    }
    const onPointerMove = (e) => {
      dom.EventHelper.stop(e, false);
      const event3 = { startX, currentX: e.pageX, startY, currentY: e.pageY, altKey };
      this._onDidChange.fire(event3);
    };
    const onPointerUp = (e) => {
      dom.EventHelper.stop(e, false);
      this.el.removeChild(style);
      this.el.classList.remove("active");
      this._onDidEnd.fire();
      disposables.dispose();
      for (const iframe of iframes) {
        iframe.classList.remove(PointerEventsDisabledCssClass);
      }
    };
    pointerEventFactory.onPointerMove(onPointerMove, null, disposables);
    pointerEventFactory.onPointerUp(onPointerUp, null, disposables);
    disposables.add(pointerEventFactory);
  }
  onPointerDoublePress(e) {
    const orthogonalSash = this.getOrthogonalSash(e);
    if (orthogonalSash) {
      orthogonalSash._onDidReset.fire();
    }
    if (this.linkedSash) {
      this.linkedSash._onDidReset.fire();
    }
    this._onDidReset.fire();
  }
  static onMouseEnter(sash, fromLinkedSash = false) {
    if (sash.el.classList.contains("active")) {
      sash.hoverDelayer.cancel();
      sash.el.classList.add("hover");
    } else {
      sash.hoverDelayer.trigger(() => sash.el.classList.add("hover"), sash.hoverDelay).then(void 0, () => {
      });
    }
    if (!fromLinkedSash && sash.linkedSash) {
      Sash.onMouseEnter(sash.linkedSash, true);
    }
  }
  static onMouseLeave(sash, fromLinkedSash = false) {
    sash.hoverDelayer.cancel();
    sash.el.classList.remove("hover");
    if (!fromLinkedSash && sash.linkedSash) {
      Sash.onMouseLeave(sash.linkedSash, true);
    }
  }
  /**
   * Forcefully stop any user interactions with this sash.
   * Useful when hiding a parent component, while the user is still
   * interacting with the sash.
   */
  clearSashHoverState() {
    Sash.onMouseLeave(this);
  }
  /**
   * Layout the sash. The sash will size and position itself
   * based on its provided {@link ISashLayoutProvider layout provider}.
   */
  layout() {
    if (this.orientation === 0) {
      const verticalProvider = this.layoutProvider;
      this.el.style.left = verticalProvider.getVerticalSashLeft(this) - this.size / 2 + "px";
      if (verticalProvider.getVerticalSashTop) {
        this.el.style.top = verticalProvider.getVerticalSashTop(this) + "px";
      }
      if (verticalProvider.getVerticalSashHeight) {
        this.el.style.height = verticalProvider.getVerticalSashHeight(this) + "px";
      }
    } else {
      const horizontalProvider = this.layoutProvider;
      this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - this.size / 2 + "px";
      if (horizontalProvider.getHorizontalSashLeft) {
        this.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + "px";
      }
      if (horizontalProvider.getHorizontalSashWidth) {
        this.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + "px";
      }
    }
  }
  getOrthogonalSash(e) {
    if (!e.target || !(e.target instanceof HTMLElement)) {
      return void 0;
    }
    if (e.target.classList.contains("orthogonal-drag-handle")) {
      return e.target.classList.contains("start") ? this.orthogonalStartSash : this.orthogonalEndSash;
    }
    return void 0;
  }
  dispose() {
    super.dispose();
    this.el.remove();
  }
}
exports.Sash = Sash;
