
import { registerCss } from '../../../../../../../css.js';
import { BrowserFeatures } from '../../canIUse.js';
import { isHTMLElement, getDomNodePagePosition, getDomNodeZoomLevel, $, hide, createElement, addStandardDisposableListener, clearNode, show, getActiveWindow, getTotalHeight, getTotalWidth, getActiveElement, getWindow, isAncestor } from '../../dom.js';
import { Disposable, toDisposable, DisposableStore } from '../../../common/lifecycle.js';
import { layout2d, AnchorPosition, AnchorAlignment } from '../../../common/layout.js';
export { AnchorAxisAlignment } from '../../../common/layout.js';
import { isIOS } from '../../../common/platform.js';
import * as contextview from './contextview.css';

registerCss(contextview);
var ContextViewDOMPosition;
(function(ContextViewDOMPosition) {
    ContextViewDOMPosition[ContextViewDOMPosition["ABSOLUTE"] = 1] = "ABSOLUTE";
    ContextViewDOMPosition[ContextViewDOMPosition["FIXED"] = 2] = "FIXED";
    ContextViewDOMPosition[ContextViewDOMPosition["FIXED_SHADOW"] = 3] = "FIXED_SHADOW";
})(ContextViewDOMPosition || (ContextViewDOMPosition = {}));
function isAnchor(obj) {
    const anchor = obj;
    return !!anchor && typeof anchor.x === "number" && typeof anchor.y === "number";
}
function getAnchorRect(anchor) {
    if (isHTMLElement(anchor)) {
        const elementPosition = getDomNodePagePosition(anchor);
        const zoom = getDomNodeZoomLevel(anchor);
        return {
            top: elementPosition.top * zoom,
            left: elementPosition.left * zoom,
            width: elementPosition.width * zoom,
            height: elementPosition.height * zoom
        };
    } else if (isAnchor(anchor)) {
        return {
            top: anchor.y,
            left: anchor.x,
            width: anchor.width || 1,
            height: anchor.height || 2
        };
    } else {
        return {
            top: anchor.posy,
            left: anchor.posx,
            width: 2,
            height: 2
        };
    }
}
class ContextView extends Disposable {
    static {
        this.BUBBLE_UP_EVENTS = ["click", "keydown", "focus", "blur"];
    }
    static {
        this.BUBBLE_DOWN_EVENTS = ["click"];
    }
    constructor(container, domPosition) {
        super();
        this.container = null;
        this.useFixedPosition = false;
        this.useShadowDOM = false;
        this.delegate = null;
        this.toDisposeOnClean = Disposable.None;
        this.toDisposeOnSetContainer = Disposable.None;
        this.shadowRoot = null;
        this.shadowRootHostElement = null;
        this.view = $(".context-view");
        hide(this.view);
        this.setContainer(container, domPosition);
        this._register(
            toDisposable(() => this.setContainer(null, ContextViewDOMPosition.ABSOLUTE))
        );
    }
    setContainer(container, domPosition) {
        this.useFixedPosition = domPosition !== ContextViewDOMPosition.ABSOLUTE;
        const usedShadowDOM = this.useShadowDOM;
        this.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;
        if (container === this.container && usedShadowDOM === this.useShadowDOM) {
            return;
        }
        if (this.container) {
            this.toDisposeOnSetContainer.dispose();
            this.view.remove();
            if (this.shadowRoot) {
                this.shadowRoot = null;
                this.shadowRootHostElement?.remove();
                this.shadowRootHostElement = null;
            }
            this.container = null;
        }
        if (container) {
            this.container = container;
            if (this.useShadowDOM) {
                this.shadowRootHostElement = $(".shadow-root-host");
                this.container.appendChild(this.shadowRootHostElement);
                this.shadowRoot = this.shadowRootHostElement.attachShadow({
                    mode: "open"
                });
                const style = createElement("style");
                style.textContent = SHADOW_ROOT_CSS;
                this.shadowRoot.appendChild(style);
                this.shadowRoot.appendChild(this.view);
                this.shadowRoot.appendChild($("slot"));
            } else {
                this.container.appendChild(this.view);
            }
            const toDisposeOnSetContainer = ( new DisposableStore());
            ContextView.BUBBLE_UP_EVENTS.forEach(event => {
                toDisposeOnSetContainer.add(addStandardDisposableListener(this.container, event, e => {
                    this.onDOMEvent(e, false);
                }));
            });
            ContextView.BUBBLE_DOWN_EVENTS.forEach(event => {
                toDisposeOnSetContainer.add(addStandardDisposableListener(this.container, event, e => {
                    this.onDOMEvent(e, true);
                }, true));
            });
            this.toDisposeOnSetContainer = toDisposeOnSetContainer;
        }
    }
    show(delegate) {
        if (this.isVisible()) {
            this.hide();
        }
        clearNode(this.view);
        this.view.className = "context-view monaco-component";
        this.view.style.top = "0px";
        this.view.style.left = "0px";
        this.view.style.zIndex = `${2575 + (delegate.layer ?? 0)}`;
        this.view.style.position = this.useFixedPosition ? "fixed" : "absolute";
        show(this.view);
        this.toDisposeOnClean = delegate.render(this.view) || Disposable.None;
        this.delegate = delegate;
        this.doLayout();
        this.delegate.focus?.();
    }
    getViewElement() {
        return this.view;
    }
    layout() {
        if (!this.isVisible()) {
            return;
        }
        if (this.delegate.canRelayout === false && !(isIOS && BrowserFeatures.pointerEvents)) {
            this.hide();
            return;
        }
        this.delegate?.layout?.();
        this.doLayout();
    }
    doLayout() {
        if (!this.isVisible()) {
            return;
        }
        const anchor = getAnchorRect(this.delegate.getAnchor());
        const activeWindow = getActiveWindow();
        const viewport = {
            top: activeWindow.pageYOffset,
            width: activeWindow.innerWidth,
            height: activeWindow.innerHeight
        };
        const view = {
            width: getTotalWidth(this.view),
            height: getTotalHeight(this.view)
        };
        const anchorPosition = this.delegate.anchorPosition;
        const anchorAlignment = this.delegate.anchorAlignment;
        const anchorAxisAlignment = this.delegate.anchorAxisAlignment;
        const {
            top,
            left
        } = layout2d(viewport, view, anchor, {
            anchorAlignment,
            anchorPosition,
            anchorAxisAlignment
        });
        this.view.classList.remove("top", "bottom", "left", "right");
        this.view.classList.add(anchorPosition === AnchorPosition.BELOW ? "bottom" : "top");
        this.view.classList.add(anchorAlignment === AnchorAlignment.LEFT ? "left" : "right");
        this.view.classList.toggle("fixed", this.useFixedPosition);
        const containerPosition = getDomNodePagePosition(this.container);
        const containerScrollTop = this.container.scrollTop || 0;
        const containerScrollLeft = this.container.scrollLeft || 0;
        this.view.style.top = `${top - (this.useFixedPosition ? getDomNodePagePosition(this.view).top : containerPosition.top) + containerScrollTop}px`;
        this.view.style.left = `${left - (this.useFixedPosition ? getDomNodePagePosition(this.view).left : containerPosition.left) + containerScrollLeft}px`;
        this.view.style.width = "initial";
    }
    hide(data) {
        const delegate = this.delegate;
        this.delegate = null;
        if (delegate?.onHide) {
            delegate.onHide(data);
        }
        this.toDisposeOnClean.dispose();
        hide(this.view);
    }
    isVisible() {
        return !!this.delegate;
    }
    onDOMEvent(e, onCapture) {
        if (this.delegate) {
            if (this.delegate.onDOMEvent) {
                this.delegate.onDOMEvent(e, getActiveElement(getWindow(e).document));
            } else if (onCapture && !isAncestor(e.target, this.container)) {
                this.hide();
            }
        }
    }
    dispose() {
        this.hide();
        super.dispose();
    }
}
const SHADOW_ROOT_CSS =  `
    :host {
        all: initial; /* 1st rule so subsequent properties are reset. */
    }

    .codicon[class*='codicon-'] {
        font: normal normal normal 16px/1 codicon;
        display: inline-block;
        text-decoration: none;
        text-rendering: auto;
        text-align: center;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
    }

    :host {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", system-ui, "Ubuntu", "Droid Sans", sans-serif;
    }

    :host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
    :host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
    :host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
    :host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
    :host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Nanum Gothic", "AppleGothic", sans-serif; }

    :host-context(.windows) { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
    :host-context(.windows:lang(zh-Hans)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
    :host-context(.windows:lang(zh-Hant)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
    :host-context(.windows:lang(ja)) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
    :host-context(.windows:lang(ko)) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }

    :host-context(.linux) { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
    :host-context(.linux:lang(zh-Hans)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
    :host-context(.linux:lang(zh-Hant)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
    :host-context(.linux:lang(ja)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
    :host-context(.linux:lang(ko)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
`;

export { AnchorAlignment, AnchorPosition, ContextView, ContextViewDOMPosition, getAnchorRect, isAnchor };
