// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../../../ui/kit/kit.js';
import * as i18n from '../../../core/i18n/i18n.js';
import * as Buttons from '../../../ui/components/buttons/buttons.js';
import * as UI from '../../../ui/legacy/legacy.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as VisualLogging from '../../../ui/visual_logging/visual_logging.js';
import valueInterpreterDisplayStyles from './valueInterpreterDisplay.css.js';
import { format, getDefaultValueTypeMapping, getPointerAddress, isNumber, isPointer, isValidMode, VALUE_TYPE_MODE_LIST, } from './ValueInterpreterDisplayUtils.js';
const UIStrings = {
    /**
     * @description Tooltip text that appears when hovering over an unsigned interpretation of the memory under the Value Interpreter
     */
    unsignedValue: '`Unsigned` value',
    /**
     * @description Tooltip text that appears when hovering over the element to change value type modes of under the Value Interpreter. Value type modes
     *             are different ways of viewing a certain value, e.g.: 10 (decimal) can be 0xa in hexadecimal mode, or 12 in octal mode.
     */
    changeValueTypeMode: 'Change mode',
    /**
     * @description Tooltip text that appears when hovering over a signed interpretation of the memory under the Value Interpreter
     */
    signedValue: '`Signed` value',
    /**
     * @description Tooltip text that appears when hovering over a 'jump-to-address' button that is next to a pointer (32-bit or 64-bit) under the Value Interpreter
     */
    jumpToPointer: 'Jump to address',
    /**
     * @description Tooltip text that appears when hovering over a 'jump-to-address' button that is next to a pointer (32-bit or 64-bit) with an invalid address under the Value Interpreter.
     */
    addressOutOfRange: 'Address out of memory range',
};
const str_ = i18n.i18n.registerUIStrings('panels/linear_memory_inspector/components/ValueInterpreterDisplay.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
const { render, nothing, html } = Lit;
const SORTED_VALUE_TYPES = Array.from(getDefaultValueTypeMapping().keys());
export const DEFAULT_VIEW = (input, _output, target) => {
    function parse(signed, type) {
        return format({ buffer: input.buffer, endianness: input.endianness, type, signed, mode: input.valueTypeModes.get(type) });
    }
    const parseSigned = parse.bind(this, true);
    const parseUnsigned = parse.bind(this, false);
    // Disabled until https://crbug.com/1079231 is fixed.
    // clang-format off
    render(html `
      <style>${UI.inspectorCommonStyles}</style>
      <style>${valueInterpreterDisplayStyles}</style>
      <div class="value-types">
        ${input.valueTypes.map(type => {
        const address = isPointer(type) ? getPointerAddress(type, input.buffer, input.endianness) : 0;
        const jumpDisabled = Number.isNaN(address) || BigInt(address) >= BigInt(input.memoryLength);
        const signed = parseSigned(type);
        const unsigned = parseUnsigned(type);
        return isNumber(type) ? html `
            <span class="value-type-cell selectable-text">${i18n.i18n.lockedString(type)}</span>
              <div>
                <select title=${i18nString(UIStrings.changeValueTypeMode)}
                  data-mode-settings="true"
                  jslog=${VisualLogging.dropDown('linear-memory-inspector.value-type-mode').track({ change: true })}
                  @change=${(e) => input.onValueTypeModeChange(type, e.target.value)}>
                    ${VALUE_TYPE_MODE_LIST.filter(x => isValidMode(type, x)).map(mode => {
            return html `
                        <option value=${mode} .selected=${input.valueTypeModes.get(type) === mode}
                                jslog=${VisualLogging.item(mode).track({ click: true, resize: true })}>${i18n.i18n.lockedString(mode)}
                        </option>`;
        })}
                </select>
              </div>
            ${renderSignedAndUnsigned(signed, unsigned, type, input.valueTypeModes.get(type))}` :
            isPointer(type) ? html `
            <span class="value-type-cell-no-mode value-type-cell selectable-text">${i18n.i18n.lockedString(type)}</span>
            <div class="value-type-cell">
              <div class="value-type-value-with-link" data-value="true">
              <span class="selectable-text">${unsigned}</span>
                <devtools-button
                  data-jump="true"
                  title=${jumpDisabled ? i18nString(UIStrings.addressOutOfRange) : i18nString(UIStrings.jumpToPointer)}
                  .disabled=${jumpDisabled}
                  jslog=${VisualLogging.action('linear-memory-inspector.jump-to-address').track({ click: true })}
                  @click=${() => input.onJumpToAddressClicked(Number(address))}
                  .variant=${"icon_toggle" /* Buttons.Button.Variant.ICON_TOGGLE */}
                  .iconName=${'open-externally'}
                  .size=${"SMALL" /* Buttons.Button.Size.SMALL */}>
                </devtools-button>
              </div>
            </div>` : nothing;
    })}
      </div>
    `, target);
    // clang-format on
};
function renderSignedAndUnsigned(signedValue, unsignedValue, type, mode) {
    const showSignedAndUnsigned = signedValue !== unsignedValue && mode !== "hex" /* ValueTypeMode.HEXADECIMAL */ && mode !== "oct" /* ValueTypeMode.OCTAL */;
    const unsignedRendered = html `<span class="value-type-cell selectable-text"  title=${i18nString(UIStrings.unsignedValue)} data-value="true">${unsignedValue}</span>`;
    if (!showSignedAndUnsigned) {
        return unsignedRendered;
    }
    // Some values are too long to show in one line, we're putting them into the next line.
    const showInMultipleLines = type === "Integer 32-bit" /* ValueType.INT32 */ || type === "Integer 64-bit" /* ValueType.INT64 */;
    const signedRendered = html `<span class="selectable-text" data-value="true" title=${i18nString(UIStrings.signedValue)}>${signedValue}</span>`;
    if (showInMultipleLines) {
        return html `
        <div class="value-type-cell">
          ${unsignedRendered}
          ${signedRendered}
        </div>
        `;
    }
    return html `
      <div class="value-type-cell" style="flex-direction: row;">
        ${unsignedRendered}
        <span class="signed-divider"></span>
        ${signedRendered}
      </div>
    `;
}
export class ValueInterpreterDisplay extends UI.Widget.Widget {
    #view;
    #endianness = "Little Endian" /* Endianness.LITTLE */;
    #buffer = new ArrayBuffer(0);
    #valueTypes = new Set();
    #valueTypeModeConfig = getDefaultValueTypeMapping();
    #memoryLength = 0;
    #onValueTypeModeChange = () => { };
    #onJumpToAddressClicked = () => { };
    constructor(element, view = DEFAULT_VIEW) {
        super(element);
        this.#view = view;
    }
    set onValueTypeModeChange(callback) {
        this.#onValueTypeModeChange = callback;
        this.performUpdate();
    }
    get onValueTypeModeChange() {
        return this.#onValueTypeModeChange;
    }
    set onJumpToAddressClicked(callback) {
        this.#onJumpToAddressClicked = callback;
        this.performUpdate();
    }
    get onJumpToAddressClicked() {
        return this.#onJumpToAddressClicked;
    }
    get valueTypeModes() {
        return this.#valueTypeModeConfig;
    }
    set valueTypeModes(modes) {
        const newMap = getDefaultValueTypeMapping();
        modes.forEach((mode, type) => {
            if (isValidMode(type, mode)) {
                newMap.set(type, mode);
            }
        });
        this.#valueTypeModeConfig = newMap;
        this.requestUpdate();
    }
    get valueTypes() {
        return this.#valueTypes;
    }
    set valueTypes(valueTypes) {
        this.#valueTypes = valueTypes;
        this.requestUpdate();
    }
    get buffer() {
        return this.#buffer;
    }
    set buffer(buffer) {
        this.#buffer = buffer;
        this.requestUpdate();
    }
    get endianness() {
        return this.#endianness;
    }
    set endianness(endianness) {
        this.#endianness = endianness;
        this.requestUpdate();
    }
    get memoryLength() {
        return this.#memoryLength;
    }
    set memoryLength(memoryLength) {
        this.#memoryLength = memoryLength;
        this.requestUpdate();
    }
    performUpdate() {
        const valueTypes = SORTED_VALUE_TYPES.filter(type => this.#valueTypes.has(type));
        this.#view({
            buffer: this.#buffer,
            valueTypes,
            endianness: this.#endianness,
            memoryLength: this.#memoryLength,
            valueTypeModes: this.#valueTypeModeConfig,
            onValueTypeModeChange: this.#onValueTypeModeChange,
            onJumpToAddressClicked: this.#onJumpToAddressClicked,
        }, undefined, this.contentElement);
    }
}
//# sourceMappingURL=ValueInterpreterDisplay.js.map