/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
var __decorate = (this && this.__decorate) || function (decorators, 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(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[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;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { registerEditorContribution } from '../../../browser/editorExtensions.js';
import { ILanguageFeaturesService } from '../../../common/services/languageFeatures.js';
import { StickyScrollWidget, StickyScrollWidgetState } from './stickyScrollWidget.js';
import { StickyLineCandidateProvider, StickyRange } from './stickyScrollProvider.js';
let StickyScrollController = class StickyScrollController extends Disposable {
    constructor(editor, _languageFeaturesService) {
        super();
        this.sessionStore = new DisposableStore();
        this.editor = editor;
        this.stickyScrollWidget = new StickyScrollWidget(this.editor);
        this.stickyLineCandidateProvider = new StickyLineCandidateProvider(this.editor, _languageFeaturesService);
        this._register(this.editor.onDidChangeConfiguration(e => {
            if (e.hasChanged(34 /* EditorOption.experimental */)) {
                this.readConfiguration();
            }
        }));
        this.readConfiguration();
    }
    readConfiguration() {
        const options = this.editor.getOption(34 /* EditorOption.experimental */);
        if (options.stickyScroll.enabled === false) {
            this.editor.removeOverlayWidget(this.stickyScrollWidget);
            this.sessionStore.clear();
            return;
        }
        else {
            this.editor.addOverlayWidget(this.stickyScrollWidget);
            this.sessionStore.add(this.editor.onDidScrollChange(() => this.renderStickyScroll()));
            this.sessionStore.add(this.editor.onDidLayoutChange(() => this.onDidResize()));
            this.sessionStore.add(this.editor.onDidChangeModelTokens((e) => this.onTokensChange(e)));
            this.sessionStore.add(this.stickyLineCandidateProvider.onStickyScrollChange(() => this.renderStickyScroll()));
            const lineNumberOption = this.editor.getOption(62 /* EditorOption.lineNumbers */);
            if (lineNumberOption.renderType === 2 /* RenderLineNumbersType.Relative */) {
                this.sessionStore.add(this.editor.onDidChangeCursorPosition(() => this.renderStickyScroll()));
            }
        }
    }
    needsUpdate(event) {
        const stickyLineNumbers = this.stickyScrollWidget.getCurrentLines();
        for (const stickyLineNumber of stickyLineNumbers) {
            for (const range of event.ranges) {
                if (stickyLineNumber >= range.fromLineNumber && stickyLineNumber <= range.toLineNumber) {
                    return true;
                }
            }
        }
        return false;
    }
    onTokensChange(event) {
        if (this.needsUpdate(event)) {
            this.renderStickyScroll();
        }
    }
    onDidResize() {
        const width = this.editor.getLayoutInfo().width - this.editor.getLayoutInfo().minimap.minimapCanvasOuterWidth - this.editor.getLayoutInfo().verticalScrollbarWidth;
        this.stickyScrollWidget.getDomNode().style.width = `${width}px`;
    }
    renderStickyScroll() {
        if (!(this.editor.hasModel())) {
            return;
        }
        const model = this.editor.getModel();
        if (this.stickyLineCandidateProvider.getVersionId() !== model.getVersionId()) {
            // Old _ranges not updated yet
            return;
        }
        this.stickyScrollWidget.setState(this.getScrollWidgetState());
    }
    getScrollWidgetState() {
        const lineHeight = this.editor.getOption(61 /* EditorOption.lineHeight */);
        const scrollTop = this.editor.getScrollTop();
        let lastLineRelativePosition = 0;
        const lineNumbers = [];
        const arrayVisibleRanges = this.editor.getVisibleRanges();
        if (arrayVisibleRanges.length !== 0) {
            const fullVisibleRange = new StickyRange(arrayVisibleRanges[0].startLineNumber, arrayVisibleRanges[arrayVisibleRanges.length - 1].endLineNumber);
            const candidateRanges = this.stickyLineCandidateProvider.getCandidateStickyLinesIntersecting(fullVisibleRange);
            for (const range of candidateRanges) {
                const start = range.startLineNumber;
                const end = range.endLineNumber;
                const depth = range.nestingDepth;
                if (end - start > 0) {
                    const topOfElementAtDepth = (depth - 1) * lineHeight;
                    const bottomOfElementAtDepth = depth * lineHeight;
                    const bottomOfBeginningLine = this.editor.getBottomForLineNumber(start) - scrollTop;
                    const topOfEndLine = this.editor.getTopForLineNumber(end) - scrollTop;
                    const bottomOfEndLine = this.editor.getBottomForLineNumber(end) - scrollTop;
                    if (topOfElementAtDepth > topOfEndLine && topOfElementAtDepth <= bottomOfEndLine) {
                        lineNumbers.push(start);
                        lastLineRelativePosition = bottomOfEndLine - bottomOfElementAtDepth;
                        break;
                    }
                    else if (bottomOfElementAtDepth > bottomOfBeginningLine && bottomOfElementAtDepth <= bottomOfEndLine) {
                        lineNumbers.push(start);
                    }
                }
            }
        }
        return new StickyScrollWidgetState(lineNumbers, lastLineRelativePosition);
    }
    dispose() {
        super.dispose();
        this.sessionStore.dispose();
    }
};
StickyScrollController.ID = 'store.contrib.stickyScrollController';
StickyScrollController = __decorate([
    __param(1, ILanguageFeaturesService)
], StickyScrollController);
registerEditorContribution(StickyScrollController.ID, StickyScrollController);
