
import { __decorate, __param } from '../../../../../external/tslib/tslib.es6.js';
import { localize } from '../../nls.js';
import { URI } from '../../base/common/uri.js';
import { isEqual, basenameOrAuthority, dirname } from '../../base/common/resources.js';
import { IconLabel } from '../../base/browser/ui/iconLabel/iconLabel.js';
import { ILanguageService } from '../../editor/common/languages/language.service.js';
import { IWorkspaceContextService } from '../../platform/workspace/common/workspace.service.js';
import { IConfigurationService } from '../../platform/configuration/common/configuration.service.js';
import { IModelService } from '../../editor/common/services/model.service.js';
import { ITextFileService } from '../services/textfile/common/textfiles.service.js';
import { IDecorationsService } from '../services/decorations/common/decorations.service.js';
import { Schemas } from '../../base/common/network.js';
import { FILES_ASSOCIATIONS_CONFIG, FileKind } from '../../platform/files/common/files.js';
import { IThemeService } from '../../platform/theme/common/themeService.service.js';
import { Event, Emitter } from '../../base/common/event.js';
import { ILabelService } from '../../platform/label/common/label.service.js';
import { getIconClasses } from '../../editor/common/services/getIconClasses.js';
import { Disposable, dispose, MutableDisposable } from '../../base/common/lifecycle.js';
import { IInstantiationService } from '../../platform/instantiation/common/instantiation.js';
import { normalizeDriveLetter } from '../../base/common/labels.js';
import { extractCellOutputDetails } from '../services/notebook/common/notebookDocumentService.js';
import { INotebookDocumentService } from '../services/notebook/common/notebookDocumentService.service.js';

function toResource(props) {
    if (!props?.resource) {
        return undefined;
    }
    if (URI.isUri(props.resource)) {
        return props.resource;
    }
    return props.resource.primary;
}
const DEFAULT_LABELS_CONTAINER = {
    onDidChangeVisibility: Event.None
};
let ResourceLabels = class ResourceLabels extends Disposable {
    get onDidChangeDecorations() {
        return this._onDidChangeDecorations.event;
    }
    constructor(
        container,
        instantiationService,
        configurationService,
        modelService,
        workspaceService,
        languageService,
        decorationsService,
        themeService,
        labelService,
        textFileService
    ) {
        super();
        this.instantiationService = instantiationService;
        this.configurationService = configurationService;
        this.modelService = modelService;
        this.workspaceService = workspaceService;
        this.languageService = languageService;
        this.decorationsService = decorationsService;
        this.themeService = themeService;
        this.labelService = labelService;
        this.textFileService = textFileService;
        this._onDidChangeDecorations = this._register(( new Emitter()));
        this.widgets = [];
        this.labels = [];
        this.registerListeners(container);
    }
    registerListeners(container) {
        this._register(container.onDidChangeVisibility(visible => {
            this.widgets.forEach(widget => widget.notifyVisibilityChanged(visible));
        }));
        this._register(
            this.languageService.onDidChange(() => this.widgets.forEach(widget => widget.notifyExtensionsRegistered()))
        );
        this._register(this.modelService.onModelLanguageChanged(e => {
            if (!e.model.uri) {
                return;
            }
            this.widgets.forEach(widget => widget.notifyModelLanguageChanged(e.model));
        }));
        this._register(this.modelService.onModelAdded(model => {
            if (!model.uri) {
                return;
            }
            this.widgets.forEach(widget => widget.notifyModelAdded(model));
        }));
        this._register(this.workspaceService.onDidChangeWorkspaceFolders(() => {
            this.widgets.forEach(widget => widget.notifyWorkspaceFoldersChange());
        }));
        this._register(this.decorationsService.onDidChangeDecorations(e => {
            let notifyDidChangeDecorations = false;
            this.widgets.forEach(widget => {
                if (widget.notifyFileDecorationsChanges(e)) {
                    notifyDidChangeDecorations = true;
                }
            });
            if (notifyDidChangeDecorations) {
                this._onDidChangeDecorations.fire();
            }
        }));
        this._register(
            this.themeService.onDidColorThemeChange(() => this.widgets.forEach(widget => widget.notifyThemeChange()))
        );
        this._register(this.configurationService.onDidChangeConfiguration(e => {
            if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) {
                this.widgets.forEach(widget => widget.notifyFileAssociationsChange());
            }
        }));
        this._register(this.labelService.onDidChangeFormatters(e => {
            this.widgets.forEach(widget => widget.notifyFormattersChange(e.scheme));
        }));
        this._register(this.textFileService.untitled.onDidChangeLabel(model => {
            this.widgets.forEach(widget => widget.notifyUntitledLabelChange(model.resource));
        }));
    }
    get(index) {
        return this.labels[index];
    }
    create(container, options) {
        const widget = this.instantiationService.createInstance(ResourceLabelWidget, container, options);
        const label = {
            element: widget.element,
            get onDidRender() {
                return widget.onDidRender;
            },
            setLabel: (label, description, options) => widget.setLabel(label, description, options),
            setResource: (label, options) => widget.setResource(label, options),
            setFile: (resource, options) => widget.setFile(resource, options),
            clear: () => widget.clear(),
            dispose: () => this.disposeWidget(widget)
        };
        this.labels.push(label);
        this.widgets.push(widget);
        return label;
    }
    disposeWidget(widget) {
        const index = this.widgets.indexOf(widget);
        if (index > -1) {
            this.widgets.splice(index, 1);
            this.labels.splice(index, 1);
        }
        dispose(widget);
    }
    clear() {
        this.widgets = dispose(this.widgets);
        this.labels = [];
    }
    dispose() {
        super.dispose();
        this.clear();
    }
};
ResourceLabels = ( __decorate([( __param(1, IInstantiationService)), ( __param(2, IConfigurationService)), ( __param(3, IModelService)), ( __param(4, IWorkspaceContextService)), ( __param(5, ILanguageService)), ( __param(6, IDecorationsService)), ( __param(7, IThemeService)), ( __param(8, ILabelService)), ( __param(9, ITextFileService))], ResourceLabels));
let ResourceLabel = class ResourceLabel extends ResourceLabels {
    get element() {
        return this.label;
    }
    constructor(
        container,
        options,
        instantiationService,
        configurationService,
        modelService,
        workspaceService,
        languageService,
        decorationsService,
        themeService,
        labelService,
        textFileService
    ) {
        super(
            DEFAULT_LABELS_CONTAINER,
            instantiationService,
            configurationService,
            modelService,
            workspaceService,
            languageService,
            decorationsService,
            themeService,
            labelService,
            textFileService
        );
        this.label = this._register(this.create(container, options));
    }
};
ResourceLabel = ( __decorate([( __param(2, IInstantiationService)), ( __param(3, IConfigurationService)), ( __param(4, IModelService)), ( __param(5, IWorkspaceContextService)), ( __param(6, ILanguageService)), ( __param(7, IDecorationsService)), ( __param(8, IThemeService)), ( __param(9, ILabelService)), ( __param(10, ITextFileService))], ResourceLabel));
var Redraw;
(function(Redraw) {
    Redraw[Redraw["Basic"] = 1] = "Basic";
    Redraw[Redraw["Full"] = 2] = "Full";
})(Redraw || (Redraw = {}));
let ResourceLabelWidget = class ResourceLabelWidget extends IconLabel {
    get onDidRender() {
        return this._onDidRender.event;
    }
    constructor(
        container,
        options,
        languageService,
        modelService,
        decorationsService,
        labelService,
        textFileService,
        contextService,
        notebookDocumentService
    ) {
        super(container, options);
        this.languageService = languageService;
        this.modelService = modelService;
        this.decorationsService = decorationsService;
        this.labelService = labelService;
        this.textFileService = textFileService;
        this.contextService = contextService;
        this.notebookDocumentService = notebookDocumentService;
        this._onDidRender = this._register(( new Emitter()));
        this.label = undefined;
        this.decoration = this._register(( new MutableDisposable()));
        this.options = undefined;
        this.computedIconClasses = undefined;
        this.computedLanguageId = undefined;
        this.computedPathLabel = undefined;
        this.computedWorkspaceFolderLabel = undefined;
        this.needsRedraw = undefined;
        this.isHidden = false;
    }
    notifyVisibilityChanged(visible) {
        if (visible === this.isHidden) {
            this.isHidden = !visible;
            if (visible && this.needsRedraw) {
                this.render({
                    updateIcon: this.needsRedraw === Redraw.Full,
                    updateDecoration: this.needsRedraw === Redraw.Full
                });
                this.needsRedraw = undefined;
            }
        }
    }
    notifyModelLanguageChanged(model) {
        this.handleModelEvent(model);
    }
    notifyModelAdded(model) {
        this.handleModelEvent(model);
    }
    handleModelEvent(model) {
        const resource = toResource(this.label);
        if (!resource) {
            return;
        }
        if (isEqual(model.uri, resource)) {
            if (this.computedLanguageId !== model.getLanguageId()) {
                this.computedLanguageId = model.getLanguageId();
                this.render({
                    updateIcon: true,
                    updateDecoration: false
                });
            }
        }
    }
    notifyFileDecorationsChanges(e) {
        if (!this.options) {
            return false;
        }
        const resource = toResource(this.label);
        if (!resource) {
            return false;
        }
        if (this.options.fileDecorations && e.affectsResource(resource)) {
            return this.render({
                updateIcon: false,
                updateDecoration: true
            });
        }
        return false;
    }
    notifyExtensionsRegistered() {
        this.render({
            updateIcon: true,
            updateDecoration: false
        });
    }
    notifyThemeChange() {
        this.render({
            updateIcon: false,
            updateDecoration: false
        });
    }
    notifyFileAssociationsChange() {
        this.render({
            updateIcon: true,
            updateDecoration: false
        });
    }
    notifyFormattersChange(scheme) {
        if (toResource(this.label)?.scheme === scheme) {
            this.render({
                updateIcon: false,
                updateDecoration: false
            });
        }
    }
    notifyUntitledLabelChange(resource) {
        if (isEqual(resource, toResource(this.label))) {
            this.render({
                updateIcon: false,
                updateDecoration: false
            });
        }
    }
    notifyWorkspaceFoldersChange() {
        if (typeof this.computedWorkspaceFolderLabel === "string") {
            const resource = toResource(this.label);
            if (URI.isUri(resource) && this.label?.name === this.computedWorkspaceFolderLabel) {
                this.setFile(resource, this.options);
            }
        }
    }
    setFile(resource, options) {
        const hideLabel = options?.hideLabel;
        let name;
        if (!hideLabel) {
            if (options?.fileKind === FileKind.ROOT_FOLDER) {
                const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
                if (workspaceFolder) {
                    name = workspaceFolder.name;
                    this.computedWorkspaceFolderLabel = name;
                }
            }
            if (!name) {
                name = normalizeDriveLetter(basenameOrAuthority(resource));
            }
        }
        let description;
        if (!options?.hidePath) {
            const descriptionCandidate = this.labelService.getUriLabel(dirname(resource), {
                relative: true
            });
            if (descriptionCandidate && descriptionCandidate !== ".") {
                description = descriptionCandidate;
            }
        }
        this.setResource({
            resource,
            name,
            description,
            range: options?.range
        }, options);
    }
    setResource(label, options = Object.create(null)) {
        const resource = toResource(label);
        const isSideBySideEditor = label?.resource && !URI.isUri(label.resource);
        if (!options.forceLabel && !isSideBySideEditor && resource?.scheme === Schemas.untitled) {
            const untitledModel = this.textFileService.untitled.get(resource);
            if (untitledModel && !untitledModel.hasAssociatedFilePath) {
                if (typeof label.name === "string") {
                    label.name = untitledModel.name;
                }
                if (typeof label.description === "string") {
                    const untitledDescription = untitledModel.resource.path;
                    if (label.name !== untitledDescription) {
                        label.description = untitledDescription;
                    } else {
                        label.description = undefined;
                    }
                }
                const untitledTitle = untitledModel.resource.path;
                if (untitledModel.name !== untitledTitle) {
                    options.title = `${untitledModel.name} • ${untitledTitle}`;
                } else {
                    options.title = untitledTitle;
                }
            }
        }
        if (!options.forceLabel && !isSideBySideEditor && resource?.scheme === Schemas.vscodeNotebookCell) {
            const notebookDocument = this.notebookDocumentService.getNotebook(resource);
            const cellIndex = notebookDocument?.getCellIndex(resource);
            if (notebookDocument && cellIndex !== undefined && typeof label.name === "string") {
                options.title = ( localize(3157, "{0} • Cell {1}", label.name, `${cellIndex + 1}`));
            }
            if (typeof label.name === "string" && notebookDocument && cellIndex !== undefined && typeof label.name === "string") {
                label.name = ( localize(3157, "{0} • Cell {1}", label.name, `${cellIndex + 1}`));
            }
        }
        if (!options.forceLabel && !isSideBySideEditor && resource?.scheme === Schemas.vscodeNotebookCellOutput) {
            const notebookDocument = this.notebookDocumentService.getNotebook(resource);
            const outputUriData = extractCellOutputDetails(resource);
            if (outputUriData?.cellFragment) {
                if (!outputUriData.notebook) {
                    return;
                }
                const cellUri = outputUriData.notebook.with({
                    scheme: Schemas.vscodeNotebookCell,
                    fragment: outputUriData.cellFragment
                });
                const cellIndex = notebookDocument?.getCellIndex(cellUri);
                const outputIndex = outputUriData.outputIndex;
                if (cellIndex !== undefined && outputIndex !== undefined && typeof label.name === "string") {
                    label.name = ( localize(
                        3158,
                        "{0} • Cell {1} • Output {2}",
                        label.name,
                        `${cellIndex + 1}`,
                        `${outputIndex + 1}`
                    ));
                } else if (cellIndex !== undefined && typeof label.name === "string") {
                    label.name = ( localize(3159, "{0} • Cell {1} • Output", label.name, `${cellIndex + 1}`));
                }
            }
        }
        if (options.namePrefix) {
            if (typeof label.name === "string") {
                label.name = options.namePrefix + label.name;
            } else if (Array.isArray(label.name) && label.name.length > 0) {
                label.name = [options.namePrefix + label.name[0], ...label.name.slice(1)];
            }
        }
        if (options.nameSuffix) {
            if (typeof label.name === "string") {
                label.name = label.name + options.nameSuffix;
            } else if (Array.isArray(label.name) && label.name.length > 0) {
                label.name = [
                    ...label.name.slice(0, label.name.length - 1),
                    label.name[label.name.length - 1] + options.nameSuffix
                ];
            }
        }
        const hasResourceChanged = this.hasResourceChanged(label);
        const hasPathLabelChanged = hasResourceChanged || this.hasPathLabelChanged(label);
        const hasFileKindChanged = this.hasFileKindChanged(options);
        const hasIconChanged = this.hasIconChanged(options);
        this.label = label;
        this.options = options;
        if (hasResourceChanged) {
            this.computedLanguageId = undefined;
        }
        if (hasPathLabelChanged) {
            this.computedPathLabel = undefined;
        }
        this.render({
            updateIcon: hasResourceChanged || hasFileKindChanged || hasIconChanged,
            updateDecoration: hasResourceChanged || hasFileKindChanged
        });
    }
    hasFileKindChanged(newOptions) {
        const newFileKind = newOptions?.fileKind;
        const oldFileKind = this.options?.fileKind;
        return newFileKind !== oldFileKind;
    }
    hasResourceChanged(newLabel) {
        const newResource = toResource(newLabel);
        const oldResource = toResource(this.label);
        if (newResource && oldResource) {
            return ( newResource.toString()) !== ( oldResource.toString());
        }
        if (!newResource && !oldResource) {
            return false;
        }
        return true;
    }
    hasPathLabelChanged(newLabel) {
        const newResource = toResource(newLabel);
        return !!newResource && this.computedPathLabel !== this.labelService.getUriLabel(newResource);
    }
    hasIconChanged(newOptions) {
        return this.options?.icon !== newOptions?.icon;
    }
    clear() {
        this.label = undefined;
        this.options = undefined;
        this.computedLanguageId = undefined;
        this.computedIconClasses = undefined;
        this.computedPathLabel = undefined;
        this.setLabel("");
    }
    render(options) {
        if (this.isHidden) {
            if (this.needsRedraw !== Redraw.Full) {
                this.needsRedraw = (options.updateIcon || options.updateDecoration) ? Redraw.Full : Redraw.Basic;
            }
            return false;
        }
        if (options.updateIcon) {
            this.computedIconClasses = undefined;
        }
        if (!this.label) {
            return false;
        }
        const iconLabelOptions = {
            title: "",
            bold: this.options?.bold,
            italic: this.options?.italic,
            strikethrough: this.options?.strikethrough,
            matches: this.options?.matches,
            descriptionMatches: this.options?.descriptionMatches,
            extraClasses: [],
            separator: this.options?.separator,
            domId: this.options?.domId,
            disabledCommand: this.options?.disabledCommand,
            labelEscapeNewLines: this.options?.labelEscapeNewLines,
            descriptionTitle: this.options?.descriptionTitle,
            supportIcons: this.options?.supportIcons
        };
        const resource = toResource(this.label);
        if (this.options?.title !== undefined) {
            iconLabelOptions.title = this.options.title;
        }
        if (resource && resource.scheme !== Schemas.data  && ((!this.options?.title) || ((typeof this.options.title !== "string") && !this.options.title.markdownNotSupportedFallback))) {
            if (!this.computedPathLabel) {
                this.computedPathLabel = this.labelService.getUriLabel(resource);
            }
            if (!iconLabelOptions.title || (typeof iconLabelOptions.title === "string")) {
                iconLabelOptions.title = this.computedPathLabel;
            } else if (!iconLabelOptions.title.markdownNotSupportedFallback) {
                iconLabelOptions.title.markdownNotSupportedFallback = this.computedPathLabel;
            }
        }
        if (this.options && !this.options.hideIcon) {
            if (!this.computedIconClasses) {
                this.computedIconClasses = getIconClasses(
                    this.modelService,
                    this.languageService,
                    resource,
                    this.options.fileKind,
                    this.options.icon
                );
            }
            if (URI.isUri(this.options.icon)) {
                iconLabelOptions.iconPath = this.options.icon;
            }
            iconLabelOptions.extraClasses = this.computedIconClasses.slice(0);
        }
        if (this.options?.extraClasses) {
            iconLabelOptions.extraClasses.push(...this.options.extraClasses);
        }
        if (this.options?.fileDecorations && resource) {
            if (options.updateDecoration) {
                this.decoration.value = this.decorationsService.getDecoration(resource, this.options.fileKind !== FileKind.FILE);
            }
            const decoration = this.decoration.value;
            if (decoration) {
                if (decoration.tooltip) {
                    if (typeof iconLabelOptions.title === "string") {
                        iconLabelOptions.title = `${iconLabelOptions.title} • ${decoration.tooltip}`;
                    } else if (typeof iconLabelOptions.title?.markdown === "string") {
                        const title = `${iconLabelOptions.title.markdown} • ${decoration.tooltip}`;
                        iconLabelOptions.title = {
                            markdown: title,
                            markdownNotSupportedFallback: title
                        };
                    }
                }
                if (decoration.strikethrough) {
                    iconLabelOptions.strikethrough = true;
                }
                if (this.options.fileDecorations.colors) {
                    iconLabelOptions.extraClasses.push(decoration.labelClassName);
                }
                if (this.options.fileDecorations.badges) {
                    iconLabelOptions.extraClasses.push(decoration.badgeClassName);
                    iconLabelOptions.extraClasses.push(decoration.iconClassName);
                }
            }
        }
        if (this.label.range) {
            iconLabelOptions.suffix = this.label.range.startLineNumber !== this.label.range.endLineNumber ? `:${this.label.range.startLineNumber}-${this.label.range.endLineNumber}` : `:${this.label.range.startLineNumber}`;
        }
        this.setLabel(this.label.name ?? "", this.label.description, iconLabelOptions);
        this._onDidRender.fire();
        return true;
    }
    dispose() {
        super.dispose();
        this.label = undefined;
        this.options = undefined;
        this.computedLanguageId = undefined;
        this.computedIconClasses = undefined;
        this.computedPathLabel = undefined;
        this.computedWorkspaceFolderLabel = undefined;
    }
};
ResourceLabelWidget = ( __decorate([( __param(2, ILanguageService)), ( __param(3, IModelService)), ( __param(4, IDecorationsService)), ( __param(5, ILabelService)), ( __param(6, ITextFileService)), ( __param(7, IWorkspaceContextService)), ( __param(8, INotebookDocumentService))], ResourceLabelWidget));

export { DEFAULT_LABELS_CONTAINER, ResourceLabel, ResourceLabels };
