/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __extends =
  (this && this.__extends) ||
  (function () {
    var extendStatics = function (d, b) {
      extendStatics =
        Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array &&
          function (d, b) {
            d.__proto__ = b;
          }) ||
        function (d, b) {
          for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        };
      return extendStatics(d, b);
    };
    return function (d, b) {
      extendStatics(d, b);
      function __() {
        this.constructor = d;
      }
      d.prototype =
        b === null
          ? Object.create(b)
          : ((__.prototype = b.prototype), new __());
    };
  })();
// import './contextview.css';
import * as DOM from '../../dom.js';
import * as platform from '../../../common/platform.js';
import {
  toDisposable,
  Disposable,
  DisposableStore,
} from '../../../common/lifecycle.js';
import { Range } from '../../../common/range.js';
import { BrowserFeatures } from '../../canIUse.js';
/**
 * Lays out a one dimensional view next to an anchor in a viewport.
 *
 * @returns The view offset within the viewport.
 */
export function layout(viewportSize, viewSize, anchor) {
  var anchorEnd = anchor.offset + anchor.size;
  if (anchor.position === 0 /* Before */) {
    if (viewSize <= viewportSize - anchorEnd) {
      return anchorEnd; // happy case, lay it out after the anchor
    }
    if (viewSize <= anchor.offset) {
      return anchor.offset - viewSize; // ok case, lay it out before the anchor
    }
    return Math.max(viewportSize - viewSize, 0); // sad case, lay it over the anchor
  } else {
    if (viewSize <= anchor.offset) {
      return anchor.offset - viewSize; // happy case, lay it out before the anchor
    }
    if (viewSize <= viewportSize - anchorEnd) {
      return anchorEnd; // ok case, lay it out after the anchor
    }
    return 0; // sad case, lay it over the anchor
  }
}
var ContextView = /** @class */ (function (_super) {
  __extends(ContextView, _super);
  function ContextView(container) {
    var _this = _super.call(this) || this;
    _this.container = null;
    _this.delegate = null;
    _this.toDisposeOnClean = Disposable.None;
    _this.toDisposeOnSetContainer = Disposable.None;
    _this.view = DOM.$('.context-view');
    DOM.hide(_this.view);
    _this.setContainer(container);
    _this._register(
      toDisposable(function () {
        return _this.setContainer(null);
      })
    );
    return _this;
  }
  ContextView.prototype.setContainer = function (container) {
    var _this = this;
    if (this.container) {
      this.toDisposeOnSetContainer.dispose();
      this.container.removeChild(this.view);
      this.container = null;
    }
    if (container) {
      this.container = container;
      this.container.appendChild(this.view);
      var toDisposeOnSetContainer_1 = new DisposableStore();
      ContextView.BUBBLE_UP_EVENTS.forEach(function (event) {
        toDisposeOnSetContainer_1.add(
          DOM.addStandardDisposableListener(_this.container, event, function (
            e
          ) {
            _this.onDOMEvent(e, false);
          })
        );
      });
      ContextView.BUBBLE_DOWN_EVENTS.forEach(function (event) {
        toDisposeOnSetContainer_1.add(
          DOM.addStandardDisposableListener(
            _this.container,
            event,
            function (e) {
              _this.onDOMEvent(e, true);
            },
            true
          )
        );
      });
      this.toDisposeOnSetContainer = toDisposeOnSetContainer_1;
    }
  };
  ContextView.prototype.show = function (delegate) {
    if (this.isVisible()) {
      this.hide();
    }
    // Show static box
    DOM.clearNode(this.view);
    this.view.className = 'context-view';
    this.view.style.top = '0px';
    this.view.style.left = '0px';
    DOM.show(this.view);
    // Render content
    this.toDisposeOnClean = delegate.render(this.view) || Disposable.None;
    // Set active delegate
    this.delegate = delegate;
    // Layout
    this.doLayout();
    // Focus
    if (this.delegate.focus) {
      this.delegate.focus();
    }
  };
  ContextView.prototype.layout = function () {
    if (!this.isVisible()) {
      return;
    }
    if (
      this.delegate.canRelayout === false &&
      !(platform.isIOS && BrowserFeatures.pointerEvents)
    ) {
      this.hide();
      return;
    }
    if (this.delegate.layout) {
      this.delegate.layout();
    }
    this.doLayout();
  };
  ContextView.prototype.doLayout = function () {
    // Check that we still have a delegate - this.delegate.layout may have hidden
    if (!this.isVisible()) {
      return;
    }
    // Get anchor
    var anchor = this.delegate.getAnchor();
    // Compute around
    var around;
    // Get the element's position and size (to anchor the view)
    if (DOM.isHTMLElement(anchor)) {
      var elementPosition = DOM.getDomNodePagePosition(anchor);
      around = {
        top: elementPosition.top,
        left: elementPosition.left,
        width: elementPosition.width,
        height: elementPosition.height,
      };
    } else {
      around = {
        top: anchor.y,
        left: anchor.x,
        width: anchor.width || 1,
        height: anchor.height || 2,
      };
    }
    var viewSizeWidth = DOM.getTotalWidth(this.view);
    var viewSizeHeight = DOM.getTotalHeight(this.view);
    var anchorPosition = this.delegate.anchorPosition || 0; /* BELOW */
    var anchorAlignment = this.delegate.anchorAlignment || 0; /* LEFT */
    var verticalAnchor = {
      offset: around.top - window.pageYOffset,
      size: around.height,
      position:
        anchorPosition === 0 /* BELOW */ ? 0 /* Before */ : 1 /* After */,
    };
    var horizontalAnchor;
    if (anchorAlignment === 0 /* LEFT */) {
      horizontalAnchor = {
        offset: around.left,
        size: 0,
        position: 0 /* Before */,
      };
    } else {
      horizontalAnchor = {
        offset: around.left + around.width,
        size: 0,
        position: 1 /* After */,
      };
    }
    var top =
      layout(window.innerHeight, viewSizeHeight, verticalAnchor) +
      window.pageYOffset;
    // if view intersects vertically with anchor, shift it horizontally
    if (
      Range.intersects(
        { start: top, end: top + viewSizeHeight },
        {
          start: verticalAnchor.offset,
          end: verticalAnchor.offset + verticalAnchor.size,
        }
      )
    ) {
      horizontalAnchor.size = around.width;
      if (anchorAlignment === 1 /* RIGHT */) {
        horizontalAnchor.offset = around.left;
      }
    }
    var left = layout(window.innerWidth, viewSizeWidth, horizontalAnchor);
    DOM.removeClasses(this.view, 'top', 'bottom', 'left', 'right');
    DOM.addClass(
      this.view,
      anchorPosition === 0 /* BELOW */ ? 'bottom' : 'top'
    );
    DOM.addClass(
      this.view,
      anchorAlignment === 0 /* LEFT */ ? 'left' : 'right'
    );
    var containerPosition = DOM.getDomNodePagePosition(this.container);
    this.view.style.top = top - containerPosition.top + 'px';
    this.view.style.left = left - containerPosition.left + 'px';
    this.view.style.width = 'initial';
  };
  ContextView.prototype.hide = function (data) {
    var delegate = this.delegate;
    this.delegate = null;
    if (delegate === null || delegate === void 0 ? void 0 : delegate.onHide) {
      delegate.onHide(data);
    }
    this.toDisposeOnClean.dispose();
    DOM.hide(this.view);
  };
  ContextView.prototype.isVisible = function () {
    return !!this.delegate;
  };
  ContextView.prototype.onDOMEvent = function (e, onCapture) {
    if (this.delegate) {
      if (this.delegate.onDOMEvent) {
        this.delegate.onDOMEvent(e, document.activeElement);
      } else if (onCapture && !DOM.isAncestor(e.target, this.container)) {
        this.hide();
      }
    }
  };
  ContextView.prototype.dispose = function () {
    this.hide();
    _super.prototype.dispose.call(this);
  };
  ContextView.BUBBLE_UP_EVENTS = ['click', 'keydown', 'focus', 'blur'];
  ContextView.BUBBLE_DOWN_EVENTS = ['click'];
  return ContextView;
})(Disposable);
export { ContextView };
