import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { $ as $$1, append, addDisposableListener, EventType, clearNode, addStandardDisposableListener } from '../../../../base/browser/dom.js';
import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js';
import { HighlightedLabel } from '../../../../base/browser/ui/highlightedlabel/highlightedLabel.js';
import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';
import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js';
import { Codicon } from '../../../../base/common/codicons.js';
import { createMatches } from '../../../../base/common/filters.js';
import { createSingleCallFunction } from '../../../../base/common/functional.js';
import { KeyCode } from '../../../../base/common/keyCodes.js';
import { toDisposable, DisposableStore, dispose } from '../../../../base/common/lifecycle.js';
import { ThemeIcon } from '../../../../base/common/themables.js';
import { localizeWithPath } from '../../../../nls.js';
import { CommandsRegistry } from '../../../../platform/commands/common/commands.js';
import { IContextViewService } from '../../../../platform/contextview/browser/contextView.service.js';
import { IHoverService } from '../../../../platform/hover/browser/hover.service.js';
import { defaultInputBoxStyles } from '../../../../platform/theme/browser/defaultStyles.js';
import { COPY_VALUE_ID, COPY_EVALUATE_PATH_ID } from './debugCommands.js';
import { IDebugService } from '../common/debug.service.js';
import { Expression, Variable, ExpressionContainer } from '../common/debugModel.js';
import { IDebugVisualizerService } from '../common/debugVisualizers.service.js';
import { ReplEvaluationResult } from '../common/replModel.js';
const _moduleId = "vs/workbench/contrib/debug/browser/baseDebugView";
const MAX_VALUE_RENDER_LENGTH_IN_VIEWLET = 1024;
const booleanRegex = /^(true|false)$/i;
const stringRegex = /^(['"]).*\1$/;
const $ = $$1;
function renderViewTree(container) {
    const treeContainer = $('.');
    treeContainer.classList.add('debug-view-content');
    container.appendChild(treeContainer);
    return treeContainer;
}
function renderExpressionValue(expressionOrValue, container, options, hoverService) {
    let value = typeof expressionOrValue === 'string' ? expressionOrValue : expressionOrValue.value;
    container.className = 'value';
    if (value === null || ((expressionOrValue instanceof Expression || expressionOrValue instanceof Variable || expressionOrValue instanceof ReplEvaluationResult) && !expressionOrValue.available)) {
        container.classList.add('unavailable');
        if (value !== Expression.DEFAULT_VALUE) {
            container.classList.add('error');
        }
    }
    else {
        if (typeof expressionOrValue !== 'string' && options.showChanged && expressionOrValue.valueChanged && value !== Expression.DEFAULT_VALUE) {
            container.className = 'value changed';
            expressionOrValue.valueChanged = false;
        }
        if (options.colorize && typeof expressionOrValue !== 'string') {
            if (expressionOrValue.type === 'number' || expressionOrValue.type === 'boolean' || expressionOrValue.type === 'string') {
                container.classList.add(expressionOrValue.type);
            }
            else if (!isNaN(+value)) {
                container.classList.add('number');
            }
            else if (booleanRegex.test(value)) {
                container.classList.add('boolean');
            }
            else if (stringRegex.test(value)) {
                container.classList.add('string');
            }
        }
    }
    if (options.maxValueLength && value && value.length > options.maxValueLength) {
        value = value.substring(0, options.maxValueLength) + '...';
    }
    if (!value) {
        value = '';
    }
    if (options.linkDetector) {
        container.textContent = '';
        const session = (expressionOrValue instanceof ExpressionContainer) ? expressionOrValue.getSession() : undefined;
        container.appendChild(options.linkDetector.linkify(value, false, session ? session.root : undefined, true));
    }
    else {
        container.textContent = value;
    }
    if (options.hover) {
        const { store, commands, commandService } = options.hover instanceof DisposableStore ? { store: options.hover, commands: [], commandService: undefined } : options.hover;
        store.add(hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), container, () => {
            const container = $$1('div');
            const markdownHoverElement = $$1('div.hover-row');
            const hoverContentsElement = append(markdownHoverElement, $$1('div.hover-contents'));
            const hoverContentsPre = append(hoverContentsElement, $$1('pre.debug-var-hover-pre'));
            hoverContentsPre.textContent = value;
            container.appendChild(markdownHoverElement);
            return container;
        }, {
            actions: ( (commands.map(({ id, args }) => {
                const description = CommandsRegistry.getCommand(id)?.metadata?.description;
                return {
                    label: typeof description === 'string' ? description : description ? description.value : id,
                    commandId: id,
                    run: () => commandService.executeCommand(id, ...args),
                };
            })))
        }));
    }
}
function renderVariable(store, commandService, hoverService, variable, data, showChanged, highlights, linkDetector, displayType) {
    if (variable.available) {
        data.type.textContent = '';
        let text = variable.name;
        if (variable.value && typeof variable.name === 'string') {
            if (variable.type && displayType) {
                text += ': ';
                data.type.textContent = variable.type + ' =';
            }
            else {
                text += ' =';
            }
        }
        data.label.set(text, highlights, variable.type && !displayType ? variable.type : variable.name);
        data.name.classList.toggle('virtual', variable.presentationHint?.kind === 'virtual');
        data.name.classList.toggle('internal', variable.presentationHint?.visibility === 'internal');
    }
    else if (variable.value && typeof variable.name === 'string' && variable.name) {
        data.label.set(':');
    }
    data.expression.classList.toggle('lazy', !!variable.presentationHint?.lazy);
    const commands = [
        { id: COPY_VALUE_ID, args: [variable, [variable]] }
    ];
    if (variable.evaluateName) {
        commands.push({ id: COPY_EVALUATE_PATH_ID, args: [{ variable }] });
    }
    renderExpressionValue(variable, data.value, {
        showChanged,
        maxValueLength: MAX_VALUE_RENDER_LENGTH_IN_VIEWLET,
        hover: { store, commands, commandService },
        colorize: true,
        linkDetector
    }, hoverService);
}
let AbstractExpressionDataSource = class AbstractExpressionDataSource {
    constructor(debugService, debugVisualizer) {
        this.debugService = debugService;
        this.debugVisualizer = debugVisualizer;
    }
    async getChildren(element) {
        const vm = this.debugService.getViewModel();
        const children = await this.doGetChildren(element);
        return Promise.all(( (children.map(async (r) => {
            const vizOrTree = vm.getVisualizedExpression(r);
            if (typeof vizOrTree === 'string') {
                const viz = await this.debugVisualizer.getVisualizedNodeFor(vizOrTree, r);
                if (viz) {
                    vm.setVisualizedExpression(r, viz);
                    return viz;
                }
            }
            else if (vizOrTree) {
                return vizOrTree;
            }
            return r;
        }))));
    }
};
AbstractExpressionDataSource = ( (__decorate([
    ( (__param(0, IDebugService))),
    ( (__param(1, IDebugVisualizerService)))
], AbstractExpressionDataSource)));
let AbstractExpressionsRenderer = class AbstractExpressionsRenderer {
    constructor(debugService, contextViewService, hoverService) {
        this.debugService = debugService;
        this.contextViewService = contextViewService;
        this.hoverService = hoverService;
    }
    renderTemplate(container) {
        const templateDisposable = ( (new DisposableStore()));
        const expression = append(container, $('.expression'));
        const name = append(expression, $('span.name'));
        const lazyButton = append(expression, $('span.lazy-button'));
        lazyButton.classList.add(...ThemeIcon.asClassNameArray(Codicon.eye));
        templateDisposable.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), lazyButton, ( localizeWithPath(_moduleId, 0, "Click to expand"))));
        const type = append(expression, $('span.type'));
        const value = append(expression, $('span.value'));
        const label = templateDisposable.add(( (new HighlightedLabel(name))));
        const inputBoxContainer = append(expression, $('.inputBoxContainer'));
        let actionBar;
        if (this.renderActionBar) {
            append(expression, $('.span.actionbar-spacer'));
            actionBar = templateDisposable.add(( (new ActionBar(expression))));
        }
        const template = { expression, name, type, value, label, inputBoxContainer, actionBar, elementDisposable: ( (new DisposableStore())), templateDisposable, lazyButton, currentElement: undefined };
        templateDisposable.add(addDisposableListener(lazyButton, EventType.CLICK, () => {
            if (template.currentElement) {
                this.debugService.getViewModel().evaluateLazyExpression(template.currentElement);
            }
        }));
        return template;
    }
    renderExpressionElement(element, node, data) {
        data.currentElement = element;
        this.renderExpression(node.element, data, createMatches(node.filterData));
        if (data.actionBar) {
            this.renderActionBar(data.actionBar, element, data);
        }
        const selectedExpression = this.debugService.getViewModel().getSelectedExpression();
        if (element === selectedExpression?.expression || (element instanceof Variable && element.errorMessage)) {
            const options = this.getInputBoxOptions(element, !!selectedExpression?.settingWatch);
            if (options) {
                data.elementDisposable.add(this.renderInputBox(data.name, data.value, data.inputBoxContainer, options));
            }
        }
    }
    renderInputBox(nameElement, valueElement, inputBoxContainer, options) {
        nameElement.style.display = 'none';
        valueElement.style.display = 'none';
        inputBoxContainer.style.display = 'initial';
        clearNode(inputBoxContainer);
        const inputBox = ( (new InputBox(
            inputBoxContainer,
            this.contextViewService,
            { ...options, inputBoxStyles: defaultInputBoxStyles }
        )));
        inputBox.value = options.initialValue;
        inputBox.focus();
        inputBox.select();
        const done = createSingleCallFunction((success, finishEditing) => {
            nameElement.style.display = '';
            valueElement.style.display = '';
            inputBoxContainer.style.display = 'none';
            const value = inputBox.value;
            dispose(toDispose);
            if (finishEditing) {
                this.debugService.getViewModel().setSelectedExpression(undefined, false);
                options.onFinish(value, success);
            }
        });
        const toDispose = [
            inputBox,
            addStandardDisposableListener(inputBox.inputElement, EventType.KEY_DOWN, (e) => {
                const isEscape = e.equals(KeyCode.Escape);
                const isEnter = e.equals(KeyCode.Enter);
                if (isEscape || isEnter) {
                    e.preventDefault();
                    e.stopPropagation();
                    done(isEnter, true);
                }
            }),
            addDisposableListener(inputBox.inputElement, EventType.BLUR, () => {
                done(true, true);
            }),
            addDisposableListener(inputBox.inputElement, EventType.CLICK, e => {
                e.preventDefault();
                e.stopPropagation();
            })
        ];
        return toDisposable(() => {
            done(false, false);
        });
    }
    disposeElement(node, index, templateData) {
        templateData.elementDisposable.clear();
    }
    disposeTemplate(templateData) {
        templateData.elementDisposable.dispose();
        templateData.templateDisposable.dispose();
    }
};
AbstractExpressionsRenderer = ( (__decorate([
    ( (__param(0, IDebugService))),
    ( (__param(1, IContextViewService))),
    ( (__param(2, IHoverService)))
], AbstractExpressionsRenderer)));
export { AbstractExpressionDataSource, AbstractExpressionsRenderer, renderExpressionValue, renderVariable, renderViewTree };
