import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { getWindowById } from '../../../../base/browser/dom.js';
import { FastDomNode } from '../../../../base/browser/fastDomNode.js';
import { Emitter } from '../../../../base/common/event.js';
import { Disposable, MutableDisposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IWorkbenchLayoutService } from '../../../services/layout/browser/layoutService.js';
import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_ENABLED, IWebviewService } from './webview.js';
let OverlayWebview = class OverlayWebview extends Disposable {
    get window() { return getWindowById(this._windowId, true).window; }
    constructor(initInfo, _layoutService, _webviewService, _baseContextKeyService) {
        super();
        this._layoutService = _layoutService;
        this._webviewService = _webviewService;
        this._baseContextKeyService = _baseContextKeyService;
        this._isFirstLoad = true;
        this._firstLoadPendingMessages = ( new Set());
        this._webview = this._register(( new MutableDisposable()));
        this._webviewEvents = this._register(( new DisposableStore()));
        this._html = '';
        this._initialScrollProgress = 0;
        this._state = undefined;
        this._owner = undefined;
        this._windowId = undefined;
        this._scopedContextKeyService = this._register(( new MutableDisposable()));
        this._shouldShowFindWidgetOnRestore = false;
        this._isDisposed = false;
        this._onDidDispose = this._register(( new Emitter()));
        this.onDidDispose = this._onDidDispose.event;
        this._onDidFocus = this._register(( new Emitter()));
        this.onDidFocus = this._onDidFocus.event;
        this._onDidBlur = this._register(( new Emitter()));
        this.onDidBlur = this._onDidBlur.event;
        this._onDidClickLink = this._register(( new Emitter()));
        this.onDidClickLink = this._onDidClickLink.event;
        this._onDidReload = this._register(( new Emitter()));
        this.onDidReload = this._onDidReload.event;
        this._onDidScroll = this._register(( new Emitter()));
        this.onDidScroll = this._onDidScroll.event;
        this._onDidUpdateState = this._register(( new Emitter()));
        this.onDidUpdateState = this._onDidUpdateState.event;
        this._onMessage = this._register(( new Emitter()));
        this.onMessage = this._onMessage.event;
        this._onMissingCsp = this._register(( new Emitter()));
        this.onMissingCsp = this._onMissingCsp.event;
        this._onDidWheel = this._register(( new Emitter()));
        this.onDidWheel = this._onDidWheel.event;
        this._onFatalError = this._register(( new Emitter()));
        this.onFatalError = this._onFatalError.event;
        this.providedViewType = initInfo.providedViewType;
        this.origin = initInfo.origin ?? generateUuid();
        this._title = initInfo.title;
        this._extension = initInfo.extension;
        this._options = initInfo.options;
        this._contentOptions = initInfo.contentOptions;
    }
    get isFocused() {
        return !!this._webview.value?.isFocused;
    }
    dispose() {
        this._isDisposed = true;
        this._container?.domNode.remove();
        this._container = undefined;
        for (const msg of this._firstLoadPendingMessages) {
            msg.resolve(false);
        }
        this._firstLoadPendingMessages.clear();
        this._onDidDispose.fire();
        super.dispose();
    }
    get container() {
        if (this._isDisposed) {
            throw new Error(`OverlayWebview has been disposed`);
        }
        if (!this._container) {
            const node = document.createElement('div');
            node.style.position = 'absolute';
            node.style.overflow = 'hidden';
            this._container = ( new FastDomNode(node));
            this._container.setVisibility('hidden');
            this._layoutService.getContainer(this.window).appendChild(node);
        }
        return this._container.domNode;
    }
    claim(owner, targetWindow, scopedContextKeyService) {
        if (this._isDisposed) {
            return;
        }
        const oldOwner = this._owner;
        if (this._windowId !== targetWindow.vscodeWindowId) {
            this.release(oldOwner);
            this._webview.clear();
            this._webviewEvents.clear();
            this._container?.domNode.remove();
            this._container = undefined;
        }
        this._owner = owner;
        this._windowId = targetWindow.vscodeWindowId;
        this._show(targetWindow);
        if (oldOwner !== owner) {
            const contextKeyService = (scopedContextKeyService || this._baseContextKeyService);
            this._scopedContextKeyService.clear();
            this._scopedContextKeyService.value = contextKeyService.createScoped(this.container);
            const wasFindVisible = this._findWidgetVisible?.get();
            this._findWidgetVisible?.reset();
            this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(contextKeyService);
            this._findWidgetVisible.set(!!wasFindVisible);
            this._findWidgetEnabled?.reset();
            this._findWidgetEnabled = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_ENABLED.bindTo(contextKeyService);
            this._findWidgetEnabled.set(!!this.options.enableFindWidget);
            this._webview.value?.setContextKeyService(this._scopedContextKeyService.value);
        }
    }
    release(owner) {
        if (this._owner !== owner) {
            return;
        }
        this._scopedContextKeyService.clear();
        this._owner = undefined;
        if (this._container) {
            this._container.setVisibility('hidden');
        }
        if (this._options.retainContextWhenHidden) {
            this._shouldShowFindWidgetOnRestore = !!this._findWidgetVisible?.get();
            this.hideFind(false);
        }
        else {
            this._webview.clear();
            this._webviewEvents.clear();
        }
    }
    layoutWebviewOverElement(element, dimension, clippingContainer) {
        if (!this._container || !this._container.domNode.parentElement) {
            return;
        }
        const whenContainerStylesLoaded = this._layoutService.whenContainerStylesLoaded(this.window);
        if (whenContainerStylesLoaded) {
            whenContainerStylesLoaded.then(() => this.doLayoutWebviewOverElement(element, dimension, clippingContainer));
        }
        else {
            this.doLayoutWebviewOverElement(element, dimension, clippingContainer);
        }
    }
    doLayoutWebviewOverElement(element, dimension, clippingContainer) {
        if (!this._container || !this._container.domNode.parentElement) {
            return;
        }
        const frameRect = element.getBoundingClientRect();
        const containerRect = this._container.domNode.parentElement.getBoundingClientRect();
        const parentBorderTop = (containerRect.height - this._container.domNode.parentElement.clientHeight) / 2.0;
        const parentBorderLeft = (containerRect.width - this._container.domNode.parentElement.clientWidth) / 2.0;
        this._container.setTop(frameRect.top - containerRect.top - parentBorderTop);
        this._container.setLeft(frameRect.left - containerRect.left - parentBorderLeft);
        this._container.setWidth(dimension ? dimension.width : frameRect.width);
        this._container.setHeight(dimension ? dimension.height : frameRect.height);
        if (clippingContainer) {
            const { top, left, right, bottom } = computeClippingRect(frameRect, clippingContainer);
            this._container.domNode.style.clipPath = `polygon(${left}px ${top}px, ${right}px ${top}px, ${right}px ${bottom}px, ${left}px ${bottom}px)`;
        }
    }
    _show(targetWindow) {
        if (this._isDisposed) {
            throw new Error('OverlayWebview is disposed');
        }
        if (!this._webview.value) {
            const webview = this._webviewService.createWebviewElement({
                providedViewType: this.providedViewType,
                origin: this.origin,
                title: this._title,
                options: this._options,
                contentOptions: this._contentOptions,
                extension: this.extension,
            });
            this._webview.value = webview;
            webview.state = this._state;
            if (this._scopedContextKeyService.value) {
                this._webview.value.setContextKeyService(this._scopedContextKeyService.value);
            }
            if (this._html) {
                webview.setHtml(this._html);
            }
            if (this._options.tryRestoreScrollPosition) {
                webview.initialScrollProgress = this._initialScrollProgress;
            }
            this._findWidgetEnabled?.set(!!this.options.enableFindWidget);
            webview.mountTo(this.container, targetWindow);
            this._webviewEvents.clear();
            this._webviewEvents.add(webview.onDidFocus(() => { this._onDidFocus.fire(); }));
            this._webviewEvents.add(webview.onDidBlur(() => { this._onDidBlur.fire(); }));
            this._webviewEvents.add(webview.onDidClickLink(x => { this._onDidClickLink.fire(x); }));
            this._webviewEvents.add(webview.onMessage(x => { this._onMessage.fire(x); }));
            this._webviewEvents.add(webview.onMissingCsp(x => { this._onMissingCsp.fire(x); }));
            this._webviewEvents.add(webview.onDidWheel(x => { this._onDidWheel.fire(x); }));
            this._webviewEvents.add(webview.onDidReload(() => { this._onDidReload.fire(); }));
            this._webviewEvents.add(webview.onFatalError(x => { this._onFatalError.fire(x); }));
            this._webviewEvents.add(webview.onDidScroll(x => {
                this._initialScrollProgress = x.scrollYPercentage;
                this._onDidScroll.fire(x);
            }));
            this._webviewEvents.add(webview.onDidUpdateState(state => {
                this._state = state;
                this._onDidUpdateState.fire(state);
            }));
            if (this._isFirstLoad) {
                this._firstLoadPendingMessages.forEach(async (msg) => {
                    msg.resolve(await webview.postMessage(msg.message, msg.transfer));
                });
            }
            this._isFirstLoad = false;
            this._firstLoadPendingMessages.clear();
        }
        if (this.options.retainContextWhenHidden && this._shouldShowFindWidgetOnRestore) {
            this.showFind(false);
            this._shouldShowFindWidgetOnRestore = false;
        }
        this._container?.setVisibility('visible');
    }
    setHtml(html) {
        this._html = html;
        this._withWebview(webview => webview.setHtml(html));
    }
    setTitle(title) {
        this._title = title;
        this._withWebview(webview => webview.setTitle(title));
    }
    get initialScrollProgress() { return this._initialScrollProgress; }
    set initialScrollProgress(value) {
        this._initialScrollProgress = value;
        this._withWebview(webview => webview.initialScrollProgress = value);
    }
    get state() { return this._state; }
    set state(value) {
        this._state = value;
        this._withWebview(webview => webview.state = value);
    }
    get extension() { return this._extension; }
    set extension(value) {
        this._extension = value;
        this._withWebview(webview => webview.extension = value);
    }
    get options() { return this._options; }
    set options(value) { this._options = { customClasses: this._options.customClasses, ...value }; }
    get contentOptions() { return this._contentOptions; }
    set contentOptions(value) {
        this._contentOptions = value;
        this._withWebview(webview => webview.contentOptions = value);
    }
    set localResourcesRoot(resources) {
        this._withWebview(webview => webview.localResourcesRoot = resources);
    }
    async postMessage(message, transfer) {
        if (this._webview.value) {
            return this._webview.value.postMessage(message, transfer);
        }
        if (this._isFirstLoad) {
            let resolve;
            const p = ( new Promise(r => resolve = r));
            this._firstLoadPendingMessages.add({ message, transfer, resolve: resolve });
            return p;
        }
        return false;
    }
    focus() { this._webview.value?.focus(); }
    reload() { this._webview.value?.reload(); }
    selectAll() { this._webview.value?.selectAll(); }
    copy() { this._webview.value?.copy(); }
    paste() { this._webview.value?.paste(); }
    cut() { this._webview.value?.cut(); }
    undo() { this._webview.value?.undo(); }
    redo() { this._webview.value?.redo(); }
    showFind(animated = true) {
        if (this._webview.value) {
            this._webview.value.showFind(animated);
            this._findWidgetVisible?.set(true);
        }
    }
    hideFind(animated = true) {
        this._findWidgetVisible?.reset();
        this._webview.value?.hideFind(animated);
    }
    runFindAction(previous) { this._webview.value?.runFindAction(previous); }
    _withWebview(f) {
        if (this._webview.value) {
            f(this._webview.value);
        }
    }
    windowDidDragStart() {
        this._webview.value?.windowDidDragStart();
    }
    windowDidDragEnd() {
        this._webview.value?.windowDidDragEnd();
    }
    setContextKeyService(contextKeyService) {
        this._webview.value?.setContextKeyService(contextKeyService);
    }
};
OverlayWebview = ( __decorate([
    ( __param(1, IWorkbenchLayoutService)),
    ( __param(2, IWebviewService)),
    ( __param(3, IContextKeyService))
], OverlayWebview));
function computeClippingRect(frameRect, clipper) {
    const rootRect = clipper.getBoundingClientRect();
    const top = Math.max(rootRect.top - frameRect.top, 0);
    const right = Math.max(frameRect.width - (frameRect.right - rootRect.right), 0);
    const bottom = Math.max(frameRect.height - (frameRect.bottom - rootRect.bottom), 0);
    const left = Math.max(rootRect.left - frameRect.left, 0);
    return { top, right, bottom, left };
}
export { OverlayWebview };
