import*as ComponentHelpers from"../component_helpers/component_helpers.js";import*as LitHtml from"../third_party/lit-html/lit-html.js";import{toHexString}from"./LinearMemoryInspectorUtils.js";const{render:render,html:html}=LitHtml;export class ByteSelectedEvent extends Event{constructor(e){super("byte-selected"),this.data=e}}export class ResizeEvent extends Event{constructor(e){super("resize"),this.data=e}}export class LinearMemoryViewer extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.resizeObserver=new ResizeObserver((()=>this.resize())),this.isObservingResize=!1,this.memory=new Uint8Array,this.address=0,this.memoryOffset=0,this.numRows=1,this.numBytesInRow=LinearMemoryViewer.BYTE_GROUP_SIZE,this.focusOnByte=!0,this.lastKeyUpdateSent=void 0}set data(e){if(e.address<e.memoryOffset||e.address>e.memoryOffset+e.memory.length||e.address<0)throw new Error("Address is out of bounds.");if(e.memoryOffset<0)throw new Error("Memory offset has to be greater or equal to zero.");this.memory=e.memory,this.address=e.address,this.memoryOffset=e.memoryOffset,this.focusOnByte=e.focus,this.update()}connectedCallback(){ComponentHelpers.SetCSSProperty.set(this,"--byte-group-margin",`${LinearMemoryViewer.BYTE_GROUP_MARGIN}px`)}disconnectedCallback(){this.isObservingResize=!1,this.resizeObserver.disconnect()}update(){this.updateDimensions(),this.render(),this.focusOnView(),this.engageResizeObserver()}focusOnView(){if(this.focusOnByte){const e=this.shadow.querySelector(".view");e&&e.focus()}}resize(){this.update(),this.dispatchEvent(new ResizeEvent(this.numBytesInRow*this.numRows))}updateDimensions(){if(0===this.clientWidth||0===this.clientHeight||!this.shadowRoot)return this.numBytesInRow=LinearMemoryViewer.BYTE_GROUP_SIZE,void(this.numRows=1);const e=this.shadowRoot.querySelector(".byte-cell"),t=this.shadowRoot.querySelector(".text-cell"),s=this.shadowRoot.querySelector(".divider"),r=this.shadowRoot.querySelector(".row");if(!e||!t||!s||!r)return this.numBytesInRow=LinearMemoryViewer.BYTE_GROUP_SIZE,void(this.numRows=1);const i=e.getBoundingClientRect().width,o=t.getBoundingClientRect().width,n=LinearMemoryViewer.BYTE_GROUP_SIZE*(i+o)+LinearMemoryViewer.BYTE_GROUP_MARGIN,d=s.getBoundingClientRect().width,h=this.clientWidth-(e.getBoundingClientRect().left-this.getBoundingClientRect().left)-d;if(h<n)return this.numBytesInRow=LinearMemoryViewer.BYTE_GROUP_SIZE,void(this.numRows=1);this.numBytesInRow=Math.floor(h/n)*LinearMemoryViewer.BYTE_GROUP_SIZE,this.numRows=Math.floor(this.clientHeight/r.clientHeight)}engageResizeObserver(){this.resizeObserver&&!this.isObservingResize&&(this.resizeObserver.observe(this),this.isObservingResize=!0)}render(){render(html`
      <style>
        :host {
          flex: auto;
          display: flex;
          min-height: 20px;
        }

        .view {
          overflow: hidden;
          text-overflow: ellipsis;
          box-sizing: border-box;
          background: var(--color-background);
          outline: none;
        }

        .row {
          display: flex;
          height: 20px;
          align-items: center;
        }

        .cell {
          text-align: center;
          border: 1px solid transparent;
          border-radius: 2px;
        }

        .cell.selected {
          border-color: var(--color-syntax-3);
          color: var(--color-syntax-3);
          background-color: var(--item-selection-bg-color);
        }

        .byte-cell {
          min-width: 21px;
          color: var(--color-text-primary);
        }

        .byte-group-margin {
          margin-left: var(--byte-group-margin);
        }

        .text-cell {
          min-width: 14px;
          color: var(--color-syntax-3);
        }

        .address {
          color: var(--color-text-disabled);
        }

        .address.selected {
          font-weight: bold;
          color: var(--color-text-primary);
        }

        .divider {
          width: 1px;
          height: inherit;
          background-color: var(--divider-color);
          margin: 0 4px 0 4px;
        }
      </style>
      <div class="view" tabindex="0" @keydown=${this.onKeyDown}>
          ${this.renderView()}
      </div>
      `,this.shadow,{eventContext:this})}onKeyDown(e){const t=e;let s;"ArrowUp"===t.code?s=this.address-this.numBytesInRow:"ArrowDown"===t.code?s=this.address+this.numBytesInRow:"ArrowLeft"===t.code?s=this.address-1:"ArrowRight"===t.code?s=this.address+1:"PageUp"===t.code?s=this.address-this.numBytesInRow*this.numRows:"PageDown"===t.code&&(s=this.address+this.numBytesInRow*this.numRows),void 0!==s&&s!==this.lastKeyUpdateSent&&(this.lastKeyUpdateSent=s,this.dispatchEvent(new ByteSelectedEvent(s)))}renderView(){const e=[];for(let t=0;t<this.numRows;++t)e.push(this.renderRow(t));return html`${e}`}renderRow(e){const{startIndex:t,endIndex:s}={startIndex:e*this.numBytesInRow,endIndex:(e+1)*this.numBytesInRow},r={address:!0,selected:Math.floor((this.address-this.memoryOffset)/this.numBytesInRow)===e};return html`
    <div class="row">
      <span class="${LitHtml.Directives.classMap(r)}">${toHexString({number:t+this.memoryOffset,pad:8,prefix:!1})}</span>
      <span class="divider"></span>
      ${this.renderByteValues(t,s)}
      <span class="divider"></span>
      ${this.renderCharacterValues(t,s)}
    </div>
    `}renderByteValues(e,t){const s=[];for(let r=e;r<t;++r){const t={cell:!0,"byte-cell":!0,"byte-group-margin":r!==e&&(r-e)%LinearMemoryViewer.BYTE_GROUP_SIZE===0,selected:r===this.address-this.memoryOffset},i=r<this.memory.length,o=i?html`${toHexString({number:this.memory[r],pad:2,prefix:!1})}`:"",n=r+this.memoryOffset,d=i?this.onSelectedByte.bind(this,n):"";s.push(html`<span class="${LitHtml.Directives.classMap(t)}" @click=${d}>${o}</span>`)}return html`${s}`}renderCharacterValues(e,t){const s=[];for(let r=e;r<t;++r){const e={cell:!0,"text-cell":!0,selected:this.address-this.memoryOffset===r},t=r<this.memory.length,i=t?html`${this.toAscii(this.memory[r])}`:"",o=t?this.onSelectedByte.bind(this,r+this.memoryOffset):"";s.push(html`<span class="${LitHtml.Directives.classMap(e)}" @click=${o}>${i}</span>`)}return html`${s}`}toAscii(e){return e>=20&&e<=127?String.fromCharCode(e):"."}onSelectedByte(e){this.dispatchEvent(new ByteSelectedEvent(e))}}LinearMemoryViewer.BYTE_GROUP_MARGIN=8,LinearMemoryViewer.BYTE_GROUP_SIZE=4,customElements.define("devtools-linear-memory-inspector-viewer",LinearMemoryViewer);