import"../elements/Icon.js";import*as e from"../third_party/lit-html/lit-html.js";import{Directives as t}from"../third_party/lit-html/lit-html.js";import{SimpleHistoryManager as s}from"../common/common.js";function r(e,t){return e.toString(16).padStart(t,"0").toUpperCase()}const{render:i,html:o}=e;class a extends Event{constructor(e){super("pageNavigation",{}),this.data=e}}class n extends Event{constructor(e){super("historyNavigation",{}),this.data=e}}class d extends Event{constructor(){super("refresh",{})}}class l extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.address=0}set data(e){this.address=e.address,this.render()}render(){i(o`
      <style>
        .navigator {
          min-height: 24px;
          display: flex;
          flex-wrap: nowrap;
          justify-content: space-between;
          overflow: hidden;
          align-items: center;
        }

        input {
          text-align: center;
        }

        .navigator-button {
          background: transparent;
          overflow: hidden;
          vertical-align: middle;
          border: none;
          padding: 0px;
        }
      </style>
      <div class="navigator">
        <div>
          ${this.createButton("ic_undo_16x16_icon",new n("Backward"))}
          ${this.createButton("ic_redo_16x16_icon",new n("Forward"))}
        </div>
        <div>
          ${this.createButton("ic_page_prev_16x16_icon",new a("Backward"))}
          <input data-input="true" contenteditable="true" value="0x${r(this.address,8)}"/>
          ${this.createButton("ic_page_next_16x16_icon",new a("Forward"))}
        </div>
        ${this.createButton("refresh_12x12_icon",new d)}
      </div>
      `,this.shadow,{eventContext:this})}createButton(e,t){return o`
      <button class="navigator-button" data-button=${t.type} @click=${this.dispatchEvent.bind(this,t)}>
        <devtools-icon .data=${{iconName:e,color:"rgb(110 110 110)",width:"16px"}}>
        </devtools-icon>
      </button>`}}customElements.define("devtools-linear-memory-inspector-navigator",l);const{render:h,html:c}=e;class m extends Event{constructor(e){super("byteSelected"),this.data=e}}class p{constructor(e){this.numRows=e.numRows,this.numBytesPerRow=e.numBytesPerRow,this.selectedAddress=e.address;const t=this.getNumBytesPerPage(),s=Math.floor(this.selectedAddress/t);this.pageStartAddress=s*this.getNumBytesPerPage();const r=this.getOffsetFromPageStart(this.selectedAddress);this.selectedRow=Math.floor(r/this.numBytesPerRow)}getRowIndexRange(e){const t=this.pageStartAddress+e*this.numBytesPerRow;return{startIndex:t,endIndex:t+this.numBytesPerRow}}getNumBytesPerPage(){return this.numBytesPerRow*this.numRows}getOffsetFromPageStart(e){return Math.max(e-this.pageStartAddress,0)}}class u extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.resizeObserver=new ResizeObserver(()=>this.update()),this.isObservingResize=!1,this.memory=new Uint8Array,this.address=0,this.byteGroupSize=4,this.pageView=new p({address:this.address,numRows:1,numBytesPerRow:this.byteGroupSize})}set data(e){this.memory=e.memory,this.address=e.address,this.update()}disconnectedCallback(){this.isObservingResize=!1,this.resizeObserver.disconnect()}getNumBytesPerPage(){return this.pageView.getNumBytesPerPage()}update(){this.updatePageView(),this.render(),this.engageResizeObserver()}updatePageView(){const e=new p({address:this.address,numRows:1,numBytesPerRow:this.byteGroupSize});if(0===this.clientWidth||0===this.clientHeight||!this.shadowRoot)return void(this.pageView=e);const t=this.shadowRoot.querySelector(".byte-cell"),s=this.shadowRoot.querySelector(".text-cell"),r=this.shadowRoot.querySelector(".divider"),i=this.shadowRoot.querySelector(".row");if(!(t&&s&&r&&i))return void(this.pageView=e);const o=t.getBoundingClientRect().width,a=s.getBoundingClientRect().width,n=this.byteGroupSize*(o+a)+u.BYTE_GROUP_MARGIN,d=r.getBoundingClientRect().width,l=this.clientWidth-t.getBoundingClientRect().left-d;if(l<n)return void(this.pageView=e);const h=Math.floor(l/n)*this.byteGroupSize,c=Math.ceil(this.memory.length/h),m=Math.min(Math.floor(this.clientHeight/i.getBoundingClientRect().height),c);this.pageView=new p({address:this.address,numRows:m,numBytesPerRow:h})}engageResizeObserver(){this.resizeObserver&&!this.isObservingResize&&(this.resizeObserver.observe(this),this.isObservingResize=!0)}render(){h(c`
      <style>
        :host {
          flex: auto;
          display: flex;
        }

        .view {
          overflow: hidden;
          text-overflow: ellipsis;
          box-sizing: border-box;
          --selected-cell-color: #1a1aa6;
        }

        .row {
          display: flex;
          height: 20px;
        }

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

        .cell.selected {
          border-color: var(--selected-cell-color);
          color: var(--selected-cell-color);
          background-color: #cfe8fc;
        }

        .byte-cell {
          min-width: 21px;
        }

        .byte-group-margin {
          margin-left: ${u.BYTE_GROUP_MARGIN}px;
        }

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

        .address {
          font-size: 11px;
          color: #9aa0a6;
        }

        .address.selected {
          font-weight: bold;
          color: #333333;
        }

        .divider {
          width: 1px;
          background-color: rgb(204, 204, 204);
          margin: 0px 4px 0px 4px;
        }
      </style>
      <div class="view">
          ${this.renderView()}
      </div>
      `,this.shadow,{eventContext:this})}renderView(){const e=[];for(let t=0;t<this.pageView.numRows;++t)e.push(this.renderRow(t));return c`${e}`}renderRow(e){const{startIndex:s,endIndex:i}=this.pageView.getRowIndexRange(e),o={address:!0,selected:this.pageView.selectedRow===e};return c`
    <div class="row">
      <span class="${t.classMap(o)}">${r(s,8)}</span>
      <span class="divider"></span>
      ${this.renderByteValues(s,i)}
      <span class="divider"></span>
      ${this.renderCharacterValues(s,i)}
    </div>
    `}renderByteValues(e,s){const i=[];for(let o=e;o<s;++o){const s={cell:!0,"byte-cell":!0,"byte-group-margin":o!==e&&(o-e)%this.byteGroupSize==0,selected:o===this.address},a=o<this.memory.length?c`${r(this.memory[o],2)}`:"";i.push(c`
        <span class="${t.classMap(s)}" @click=${this.onSelectedByte(o)}>
          ${a}
        </span>`)}return c`${i}`}renderCharacterValues(e,s){const r=[];for(let i=e;i<s;++i){const e={cell:!0,"text-cell":!0,selected:this.address===i},s=i<this.memory.length?c`${this.toAscii(this.memory[i])}`:"";r.push(c`<span class="${t.classMap(e)}">${s}</span>`)}return c`${r}`}toAscii(e){return e>=20&&e<=127?String.fromCharCode(e):"."}onSelectedByte(e){return()=>{this.dispatchEvent(new m(e))}}}u.BYTE_GROUP_MARGIN=8,customElements.define("devtools-linear-memory-inspector-viewer",u);const{render:g,html:w}=e;class y{constructor(e,t){if(this.address=0,e<0)throw new Error("Address should be a greater or equal to zero");this.address=e,this.callback=t}valid(){return!0}reveal(){this.callback(this.address)}}class v extends HTMLElement{constructor(){super(...arguments),this.shadow=this.attachShadow({mode:"open"}),this.history=new s.SimpleHistoryManager(10),this.memory=new Uint8Array,this.address=0}set data(e){this.memory=e.memory,this.address=e.address,this.render()}render(){g(w`
      <style>
        :host {
          flex: auto;
          display: flex;
        }

        .memory-inspector {
          display: flex;
          flex: auto;
          flex-wrap: wrap;
          flex-direction: column;
          font-family: monospace;
          padding: 9px 12px 9px 7px;
        }

        devtools-linear-memory-inspector-navigator + devtools-linear-memory-inspector-viewer {
          margin-top: 12px;
        }
      </style>
      <div class="memory-inspector">
        <devtools-linear-memory-inspector-navigator
          .data=${{address:this.address}}
          @pageNavigation=${this.navigatePage}
          @historyNavigation=${this.navigateHistory}></devtools-linear-memory-inspector-navigator>
        <devtools-linear-memory-inspector-viewer
          .data=${{memory:this.memory,address:this.address}}
          @byteSelected=${e=>this.jumpToAddress(e.data)}></devtools-linear-memory-inspector-viewer>
      </div>
      `,this.shadow,{eventContext:this})}navigateHistory(e){return"Forward"===e.data?this.history.rollover():this.history.rollback()}navigatePage(e){const t=this.shadow.querySelector("devtools-linear-memory-inspector-viewer");if(!t)return;const s="Forward"===e.data?Math.min(this.address+t.getNumBytesPerPage(),this.memory.length-1):Math.max(this.address-t.getNumBytesPerPage(),0);this.jumpToAddress(s)}jumpToAddress(e){const t=new y(e,e=>this.jumpToAddress(e));this.history.push(t),this.address=e,this.render()}}customElements.define("devtools-linear-memory-inspector-inspector",v);class x extends HTMLElement{set data(e){}}var f=Object.freeze({__proto__:null,LinearMemoryInspectorData:void 0,LinearMemoryInspectorClosureInterface:x,createLinearMemoryInspector:function(){return document.createElement("devtools-linear-memory-inspector-inspector")}});export{f as LinearMemoryInspector};
