<script lang="ts" setup>
import { computed } from 'vue'

const { buffer } = defineProps<{ buffer: ArrayBuffer }>()

const hexDump = computed(() => {
  const arr = new Uint8Array(buffer)
  const lines: string[] = []

  let offset = 0
  const total = buffer.byteLength

  if (total === 0) {
    return ''.padEnd(80, ' ')
  }

  while (offset < total) {
    const values = [offset.toString(16).padStart(8, '0')]
    const asciiValues: string[] = []
    let cnt = 0
    while (offset < total && cnt < 16) {
      if (cnt === 0 || cnt === 8) {
        values.push('')
      }
      if (cnt === 0) {
        asciiValues.push('  |')
      }

      const byte = arr[offset++]

      values.push(byte.toString(16).padStart(2, '0'))

      const char = String.fromCharCode(byte)
      if (char > ' ' && char <= 'a') {
        asciiValues.push(char)
      } else {
        asciiValues.push('.')
      }

      cnt += 1
    }

    while (cnt > 0 && cnt < 8) {
      if (cnt === 7) {
        values.push('')
      }

      values.push('  ')
      asciiValues.push(' ')
      cnt++
    }

    while (cnt > 0 && cnt < 16) {
      values.push('  ')
      asciiValues.push(' ')
      cnt++
    }

    if (cnt) {
      asciiValues.push('|')
    }

    lines.push(values.join(' ') + asciiValues.join(''))
  }
  lines.push(offset.toString(16).padStart(8, '0').padEnd(80, ' '))
  return lines.join('\n')
})
</script>

<template>
  <pre v-memo="hexDump">{{ hexDump }}</pre>
</template>

<style scoped>
pre {
  width: fit-content;
  padding: 0.5em 1em 10em;
  box-sizing: border-box;
  overflow: scroll;
  min-height: 10rem;
  height: 20rem;
  max-height: 20rem;
  background: rgba(255, 255, 255, 0.15);
  color: #c0c0c0;
  border: 1px solid rgba(255, 255, 255, 0.3);
}
</style>
