import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import './media/typeHierarchy.css.js';
import { Dimension, isKeyboardEvent } from '../../../../base/browser/dom.js';
import { SplitView, Sizing } from '../../../../base/browser/ui/splitview/splitview.js';
import { TreeMouseEventTarget } from '../../../../base/browser/ui/tree/tree.js';
import { Color } from '../../../../base/common/color.js';
import { Event } from '../../../../base/common/event.js';
import { DisposableStore, toDisposable } from '../../../../base/common/lifecycle.js';
import { EmbeddedCodeEditorWidget } from '../../../../editor/browser/widget/codeEditor/embeddedCodeEditorWidget.js';
import { Range } from '../../../../editor/common/core/range.js';
import { OverviewRulerLane } from '../../../../editor/common/model.js';
import { ITextModelService } from '../../../../editor/common/services/resolverService.js';
import { PeekViewWidget, peekViewBorder, peekViewTitleBackground, peekViewTitleForeground, peekViewTitleInfoForeground, peekViewResultsBackground, peekViewEditorMatchHighlight, IPeekViewService } from '../../../../editor/contrib/peekView/browser/peekView.js';
import { localizeWithPath } from '../../../../nls.js';
import { createAndFillInActionBarActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { MenuId, IMenuService } from '../../../../platform/actions/common/actions.js';
import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { WorkbenchAsyncDataTree } from '../../../../platform/list/browser/listService.js';
import { IStorageService } from '../../../../platform/storage/common/storage.js';
import { themeColorFromId, IThemeService } from '../../../../platform/theme/common/themeService.js';
import { VirtualDelegate, TypeRenderer, DataSource, Sorter, AccessibilityProvider, IdentityProvider } from './typeHierarchyTree.js';
import { IEditorService } from '../../../services/editor/common/editorService.js';
var TypeHierarchyTreePeekWidget_1;
class LayoutInfo {
    static store(info, storageService) {
        storageService.store('typeHierarchyPeekLayout', JSON.stringify(info), 0 , 1 );
    }
    static retrieve(storageService) {
        const value = storageService.get('typeHierarchyPeekLayout', 0 , '{}');
        const defaultInfo = { ratio: 0.7, height: 17 };
        try {
            return { ...defaultInfo, ...JSON.parse(value) };
        }
        catch {
            return defaultInfo;
        }
    }
    constructor(ratio, height) {
        this.ratio = ratio;
        this.height = height;
    }
}
class TypeHierarchyTree extends WorkbenchAsyncDataTree {
}
let TypeHierarchyTreePeekWidget = class TypeHierarchyTreePeekWidget extends PeekViewWidget {
    static { TypeHierarchyTreePeekWidget_1 = this; }
    static { this.TitleMenu = ( new MenuId('typehierarchy/title')); }
    constructor(editor, _where, _direction, themeService, _peekViewService, _editorService, _textModelService, _storageService, _menuService, _contextKeyService, _instantiationService) {
        super(editor, { showFrame: true, showArrow: true, isResizeable: true, isAccessible: true }, _instantiationService);
        this._where = _where;
        this._direction = _direction;
        this._peekViewService = _peekViewService;
        this._editorService = _editorService;
        this._textModelService = _textModelService;
        this._storageService = _storageService;
        this._menuService = _menuService;
        this._contextKeyService = _contextKeyService;
        this._instantiationService = _instantiationService;
        this._treeViewStates = ( new Map());
        this._previewDisposable = ( new DisposableStore());
        this.create();
        this._peekViewService.addExclusiveWidget(editor, this);
        this._applyTheme(themeService.getColorTheme());
        this._disposables.add(themeService.onDidColorThemeChange(this._applyTheme, this));
        this._disposables.add(this._previewDisposable);
    }
    dispose() {
        LayoutInfo.store(this._layoutInfo, this._storageService);
        this._splitView.dispose();
        this._tree.dispose();
        this._editor.dispose();
        super.dispose();
    }
    get direction() {
        return this._direction;
    }
    _applyTheme(theme) {
        const borderColor = theme.getColor(peekViewBorder) || Color.transparent;
        this.style({
            arrowColor: borderColor,
            frameColor: borderColor,
            headerBackgroundColor: theme.getColor(peekViewTitleBackground) || Color.transparent,
            primaryHeadingColor: theme.getColor(peekViewTitleForeground),
            secondaryHeadingColor: theme.getColor(peekViewTitleInfoForeground)
        });
    }
    _fillHead(container) {
        super._fillHead(container, true);
        const menu = this._menuService.createMenu(TypeHierarchyTreePeekWidget_1.TitleMenu, this._contextKeyService);
        const updateToolbar = () => {
            const actions = [];
            createAndFillInActionBarActions(menu, undefined, actions);
            this._actionbarWidget.clear();
            this._actionbarWidget.push(actions, { label: false, icon: true });
        };
        this._disposables.add(menu);
        this._disposables.add(menu.onDidChange(updateToolbar));
        updateToolbar();
    }
    _fillBody(parent) {
        this._layoutInfo = LayoutInfo.retrieve(this._storageService);
        this._dim = ( new Dimension(0, 0));
        this._parent = parent;
        parent.classList.add('type-hierarchy');
        const message = document.createElement('div');
        message.classList.add('message');
        parent.appendChild(message);
        this._message = message;
        this._message.tabIndex = 0;
        const container = document.createElement('div');
        container.classList.add('results');
        parent.appendChild(container);
        this._splitView = ( new SplitView(container, { orientation: 1  }));
        const editorContainer = document.createElement('div');
        editorContainer.classList.add('editor');
        container.appendChild(editorContainer);
        const editorOptions = {
            scrollBeyondLastLine: false,
            scrollbar: {
                verticalScrollbarSize: 14,
                horizontal: 'auto',
                useShadows: true,
                verticalHasArrows: false,
                horizontalHasArrows: false,
                alwaysConsumeMouseWheel: false
            },
            overviewRulerLanes: 2,
            fixedOverflowWidgets: true,
            minimap: {
                enabled: false
            }
        };
        this._editor = this._instantiationService.createInstance(EmbeddedCodeEditorWidget, editorContainer, editorOptions, {}, this.editor);
        const treeContainer = document.createElement('div');
        treeContainer.classList.add('tree');
        container.appendChild(treeContainer);
        const options = {
            sorter: new Sorter(),
            accessibilityProvider: new AccessibilityProvider(() => this._direction),
            identityProvider: new IdentityProvider(() => this._direction),
            expandOnlyOnTwistieClick: true,
            overrideStyles: {
                listBackground: peekViewResultsBackground
            }
        };
        this._tree = this._instantiationService.createInstance(TypeHierarchyTree, 'TypeHierarchyPeek', treeContainer, new VirtualDelegate(), [this._instantiationService.createInstance(TypeRenderer)], this._instantiationService.createInstance(DataSource, () => this._direction), options);
        this._splitView.addView({
            onDidChange: Event.None,
            element: editorContainer,
            minimumSize: 200,
            maximumSize: Number.MAX_VALUE,
            layout: (width) => {
                if (this._dim.height) {
                    this._editor.layout({ height: this._dim.height, width });
                }
            }
        }, Sizing.Distribute);
        this._splitView.addView({
            onDidChange: Event.None,
            element: treeContainer,
            minimumSize: 100,
            maximumSize: Number.MAX_VALUE,
            layout: (width) => {
                if (this._dim.height) {
                    this._tree.layout(this._dim.height, width);
                }
            }
        }, Sizing.Distribute);
        this._disposables.add(this._splitView.onDidSashChange(() => {
            if (this._dim.width) {
                this._layoutInfo.ratio = this._splitView.getViewSize(0) / this._dim.width;
            }
        }));
        this._disposables.add(this._tree.onDidChangeFocus(this._updatePreview, this));
        this._disposables.add(this._editor.onMouseDown(e => {
            const { event, target } = e;
            if (event.detail !== 2) {
                return;
            }
            const [focus] = this._tree.getFocus();
            if (!focus) {
                return;
            }
            this.dispose();
            this._editorService.openEditor({
                resource: focus.item.uri,
                options: { selection: target.range }
            });
        }));
        this._disposables.add(this._tree.onMouseDblClick(e => {
            if (e.target === TreeMouseEventTarget.Twistie) {
                return;
            }
            if (e.element) {
                this.dispose();
                this._editorService.openEditor({
                    resource: e.element.item.uri,
                    options: { selection: e.element.item.selectionRange, pinned: true }
                });
            }
        }));
        this._disposables.add(this._tree.onDidChangeSelection(e => {
            const [element] = e.elements;
            if (element && isKeyboardEvent(e.browserEvent)) {
                this.dispose();
                this._editorService.openEditor({
                    resource: element.item.uri,
                    options: { selection: element.item.selectionRange, pinned: true }
                });
            }
        }));
    }
    async _updatePreview() {
        const [element] = this._tree.getFocus();
        if (!element) {
            return;
        }
        this._previewDisposable.clear();
        const options = {
            description: 'type-hierarchy-decoration',
            stickiness: 1 ,
            className: 'type-decoration',
            overviewRuler: {
                color: themeColorFromId(peekViewEditorMatchHighlight),
                position: OverviewRulerLane.Center
            },
        };
        let previewUri;
        if (this._direction === "supertypes" ) {
            previewUri = element.parent ? element.parent.item.uri : element.model.root.uri;
        }
        else {
            previewUri = element.item.uri;
        }
        const value = await this._textModelService.createModelReference(previewUri);
        this._editor.setModel(value.object.textEditorModel);
        const decorations = [];
        let fullRange;
        const loc = { uri: element.item.uri, range: element.item.selectionRange };
        if (( loc.uri.toString()) === ( previewUri.toString())) {
            decorations.push({ range: loc.range, options });
            fullRange = !fullRange ? loc.range : Range.plusRange(loc.range, fullRange);
        }
        if (fullRange) {
            this._editor.revealRangeInCenter(fullRange, 1 );
            const decorationsCollection = this._editor.createDecorationsCollection(decorations);
            this._previewDisposable.add(toDisposable(() => decorationsCollection.clear()));
        }
        this._previewDisposable.add(value);
        const title = this._direction === "supertypes"
            ? ( localizeWithPath(
            'vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek',
            'supertypes',
            "Supertypes of '{0}'",
            element.model.root.name
        ))
            : ( localizeWithPath(
            'vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek',
            'subtypes',
            "Subtypes of '{0}'",
            element.model.root.name
        ));
        this.setTitle(title);
    }
    showLoading() {
        this._parent.dataset['state'] = "loading" ;
        this.setTitle(( localizeWithPath(
            'vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek',
            'title.loading',
            "Loading..."
        )));
        this._show();
    }
    showMessage(message) {
        this._parent.dataset['state'] = "message" ;
        this.setTitle('');
        this.setMetaTitle('');
        this._message.innerText = message;
        this._show();
        this._message.focus();
    }
    async showModel(model) {
        this._show();
        const viewState = this._treeViewStates.get(this._direction);
        await this._tree.setInput(model, viewState);
        const root = this._tree.getNode(model).children[0];
        await this._tree.expand(root.element);
        if (root.children.length === 0) {
            this.showMessage(this._direction === "supertypes"
                ? ( localizeWithPath(
                'vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek',
                'empt.supertypes',
                "No supertypes of '{0}'",
                model.root.name
            ))
                : ( localizeWithPath(
                'vs/workbench/contrib/typeHierarchy/browser/typeHierarchyPeek',
                'empt.subtypes',
                "No subtypes of '{0}'",
                model.root.name
            )));
        }
        else {
            this._parent.dataset['state'] = "data" ;
            if (!viewState || this._tree.getFocus().length === 0) {
                this._tree.setFocus([root.children[0].element]);
            }
            this._tree.domFocus();
            this._updatePreview();
        }
    }
    getModel() {
        return this._tree.getInput();
    }
    getFocused() {
        return this._tree.getFocus()[0];
    }
    async updateDirection(newDirection) {
        const model = this._tree.getInput();
        if (model && newDirection !== this._direction) {
            this._treeViewStates.set(this._direction, this._tree.getViewState());
            this._direction = newDirection;
            await this.showModel(model);
        }
    }
    _show() {
        if (!this._isShowing) {
            this.editor.revealLineInCenterIfOutsideViewport(this._where.lineNumber, 0 );
            super.show(Range.fromPositions(this._where), this._layoutInfo.height);
        }
    }
    _onWidth(width) {
        if (this._dim) {
            this._doLayoutBody(this._dim.height, width);
        }
    }
    _doLayoutBody(height, width) {
        if (this._dim.height !== height || this._dim.width !== width) {
            super._doLayoutBody(height, width);
            this._dim = ( new Dimension(width, height));
            this._layoutInfo.height = this._viewZone ? this._viewZone.heightInLines : this._layoutInfo.height;
            this._splitView.layout(width);
            this._splitView.resizeView(0, width * this._layoutInfo.ratio);
        }
    }
};
TypeHierarchyTreePeekWidget = TypeHierarchyTreePeekWidget_1 = ( __decorate([
    ( __param(3, IThemeService)),
    ( __param(4, IPeekViewService)),
    ( __param(5, IEditorService)),
    ( __param(6, ITextModelService)),
    ( __param(7, IStorageService)),
    ( __param(8, IMenuService)),
    ( __param(9, IContextKeyService)),
    ( __param(10, IInstantiationService))
], TypeHierarchyTreePeekWidget));
export { TypeHierarchyTreePeekWidget };
