<script setup lang="ts">
import { ref, watch } from 'vue';
import DissectionDumpHigh from './DissectionDumpHigh.vue';

const props = defineProps({
  base64: {
    type: String,
    required: true,
  },
  select: {
    type: Function,
    default: () => {},
  },
  selected: {
    type: Object,
    default: { id: '', idx: 0, start: 0, length: 0 },
  },
});

const addrLines = ref<string[]>([]);
const hexLines = ref<string[]>([]);
const asciiLines = ref<string[]>([]);

const asciiHighlight = ref([0, 0]);
const hexHighlight = ref([0, 0]);

watch(
  () => props.selected,
  newSelected => {
    const { start, length: size } = newSelected;

    const hexSize = size * 2 + size - 1;
    const hexPos = start * 2 + start;
    const asciiPos = start + Math.floor(start / 16);
    const asciiSize = start + size + Math.floor((start + size) / 16) - asciiPos;

    asciiHighlight.value = [asciiPos, size > 0 ? asciiSize : 0];
    hexHighlight.value = [hexPos, size > 0 ? hexSize : 0];
  },
  { immediate: true }
);

watch(
  () => props.base64,
  base64Str => {
    // Decode base64 to a string
    const binaryString = atob(base64Str);
    // Convert binary string to Uint8Array
    const newBuffer = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      newBuffer[i] = binaryString.charCodeAt(i);
    }

    let addrLinesTemp: string[] = [];
    let hexLinesTemp: string[] = [];
    let asciiLinesTemp: string[] = [];

    for (let i = 0; i < newBuffer.length; i += 16) {
      let address = i.toString(16).padStart(8, '0');
      let block = newBuffer.slice(i, i + 16);
      let hexArray = [];
      let asciiArray = [];

      for (let value of block) {
        hexArray.push(value.toString(16).padStart(2, '0'));
        asciiArray.push(
          value >= 0x20 && value < 0x7f ? String.fromCharCode(value) : '.'
        );
      }

      let hexString =
        hexArray.length > 8
          ? hexArray.slice(0, 8).join(' ') + '　' + hexArray.slice(8).join(' ')
          : hexArray.join(' ');

      let asciiString = asciiArray.join('');

      addrLinesTemp.push(address);
      hexLinesTemp.push(hexString);
      asciiLinesTemp.push(asciiString);
    }

    addrLines.value = addrLinesTemp;
    hexLines.value = hexLinesTemp;
    asciiLines.value = asciiLinesTemp;
  },
  { immediate: true }
);

const onHexClick = (offset: number) => {
  if (typeof props.select !== 'function') return;
  props.select(Math.floor(offset / 3));
};

const onAsciiClick = (offset: number) => {
  if (typeof props.select !== 'function') return;
  props.select(offset - Math.floor(offset / 17));
};
</script>

<template>
  <div class="tbd">
    <div class="tbd-offset">
      {{ addrLines.join('\n') }}
    </div>
    <div class="tbd-box">
      <DissectionDumpHigh
        :text="hexLines.join('\n')"
        :start="hexHighlight[0]"
        :size="hexHighlight[1]"
        :onOffsetClicked="onHexClick"
      />
    </div>
    <div class="tbd-box">
      <DissectionDumpHigh
        :text="asciiLines.join('\n')"
        :start="asciiHighlight[0]"
        :size="asciiHighlight[1]"
        :onOffsetClicked="onAsciiClick"
      />
    </div>
  </div>
</template>

<style lang="css" scoped>
.tbd {
  display: flex;
  white-space: pre;
  word-break: break-all;
  font-size: 0.8125rem;
  line-height: 1.5rem;
}
.tbd-offset {
  color: #6b7280;
  user-select: none;
}
.tbd-box {
  margin-left: 1rem;
  cursor: pointer;
}
</style>
