<script setup>
import { computed, ref } from 'vue';
import BigNumber from "bignumber.js";

/**
 * @typedef {string} UnitNameStr
 */

/**
 * @enum {UnitNameStr}
 */
const UnitName = Object.freeze({
  KBYTE: "unit-k-byte",
  MBYTE: "unit-m-byte",
  GBYTE: "unit-g-byte",
  TBYTE: "unit-t-byte",
  KIBYTE: "unit-ki-byte",
  MIBYTE: "unit-mi-byte",
  GIBYTE: "unit-gi-byte",
  TIBYTE: "unit-ti-byte",
  BYTE: "unit-byte",
  BIT: "unit-bit",
  KBIT: "unit-k-bit",
  MBIT: "unit-m-bit",
  GBIT: "unit-g-bit",
  TBIT: "unit-t-bit",
})

/**
 * @enum {number}
 */
const UnitNameToSize = Object.freeze({
  [UnitName.KBYTE]: 1000,
  [UnitName.MBYTE]: 1000 * 1000,
  [UnitName.GBYTE]: 1000 * 1000 * 1000,
  [UnitName.TBYTE]: 1000 * 1000 * 1000 * 1000,
  [UnitName.KIBYTE]: 1024,
  [UnitName.MIBYTE]: 1024 * 1024,
  [UnitName.GIBYTE]: 1024 * 1024 * 1024,
  [UnitName.TIBYTE]: 1024 * 1024 * 1024 * 1024,
  [UnitName.BYTE]: 1,
  [UnitName.BIT]: 1 / 8,
  [UnitName.KBIT]: 1000 / 8,
  [UnitName.MBIT]: 1000000 / 8,
  [UnitName.GBIT]: 1000000000 / 8,
  [UnitName.TBIT]: 1000000000000 / 8,
});

const size = ref({
  [UnitName.KBYTE]: '',
  [UnitName.MBYTE]: '',
  [UnitName.GBYTE]: '',
  [UnitName.TBYTE]: '',
  [UnitName.KIBYTE]: '',
  [UnitName.MIBYTE]: '',
  [UnitName.GIBYTE]: '',
  [UnitName.TIBYTE]: '',
  [UnitName.BYTE]: '',
  [UnitName.BIT]: '',
  [UnitName.KBIT]: '',
  [UnitName.MBIT]: '',
  [UnitName.GBIT]: '',
  [UnitName.TBIT]: '',
});

/**
 * Change ref variable when user inputs some characters.
 * @param {UnitNameStr} unitName 
 * @returns {void}
 */
function sizeChanged(unitName) {
  /**
   * @type {object.<UnitNameStr, string>}
   */
  let result = {};
  // assign 0 to current input if nothing is passed
  if (size.value[unitName].length === 0) result[unitName] = '0';
  let inputedBytes = new BigNumber(UnitNameToSize[unitName]).multipliedBy(size.value[unitName]);
  for (const key in UnitNameToSize) {
    result[key] = inputedBytes.div(UnitNameToSize[key]).toString();
  }
  result[unitName] = size.value[unitName];
  for (const key in UnitNameToSize) {
    if (result[key] !== 'NaN') {
      size.value[key] = result[key];
    } else if (result[key] === 'NaN') {
      size.value[key] = '';
    }
  }
}

const isMultipleOf4KiB = computed(() => {
  let userInput = new BigNumber(size.value[UnitName.KIBYTE]);
  if (userInput.toNumber() === 0) return false;
  return userInput.mod(4).toNumber() === 0 ? true : false;
})
</script>

<template>
  <h1>数据单位换算</h1>
  <div class="unit-conversion-computation-area 1000-in-byte">
    <p>1000 进制并以 Byte 计:</p>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.KBYTE" type="text" v-model="size[UnitName.KBYTE]"
        @input="sizeChanged(UnitName.KBYTE)">
      <span class="unit-name">KB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.MBYTE" type="text" v-model="size[UnitName.MBYTE]"
        @input="sizeChanged(UnitName.MBYTE)">
      <span class="unit-name">MB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.GBYTE" type="text" v-model="size[UnitName.GBYTE]"
        @input="sizeChanged(UnitName.GBYTE)">
      <span class="unit-name">GB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.TBYTE" type="text" v-model="size[UnitName.TBYTE]"
        @input="sizeChanged(UnitName.TBYTE)">
      <span class="unit-name">TB</span>
    </div>
  </div>
  <div class="unit-conversion-computation-area 1024-in-byte">
    <p>1024 进制并以 Byte 计:</p>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.KIBYTE" type="text" v-model="size[UnitName.KIBYTE]"
        @input="sizeChanged(UnitName.KIBYTE)">
      <span class="unit-name">KiB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.MIBYTE" type="text" v-model="size[UnitName.MIBYTE]"
        @input="sizeChanged(UnitName.MIBYTE)">
      <span class="unit-name">MiB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.GIBYTE" type="text" v-model="size[UnitName.GIBYTE]"
        @input="sizeChanged(UnitName.GIBYTE)">
      <span class="unit-name">GiB</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.TIBYTE" type="text" v-model="size[UnitName.TIBYTE]"
        @input="sizeChanged(UnitName.TIBYTE)">
      <span class="unit-name">TiB</span>
    </div>
  </div>
  <div class="unit-conversion-computation-area byte-bit">
    <p>以 Byte (B) / bit (b) 计:</p>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.BYTE" type="text" v-model="size[UnitName.BYTE]"
        @input="sizeChanged(UnitName.BYTE)">
      <span class="unit-name">B</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.BIT" type="text" v-model="size[UnitName.BIT]"
        @input="sizeChanged(UnitName.BIT)">
      <span class="unit-name">b</span>
    </div>
  </div>
  <div class="unit-conversion-computation-area 1000-in-bit">
    <p>1000 进制并以 bit 计:</p>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.KBIT" type="text" v-model="size[UnitName.KBIT]"
        @input="sizeChanged(UnitName.KBIT)">
      <span class="unit-name">Kb</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.MBIT" type="text" v-model="size[UnitName.MBIT]"
        @input="sizeChanged(UnitName.MBIT)">
      <span class="unit-name">Mb</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.GBIT" type="text" v-model="size[UnitName.GBIT]"
        @input="sizeChanged(UnitName.GBIT)">
      <span class="unit-name">Gb</span>
    </div>
    <div class="unit-conversion-computation-node">
      <input class="size-text" :id="UnitName.TBIT" type="text" v-model="size[UnitName.TBIT]"
        @input="sizeChanged(UnitName.TBIT)">
      <span class="unit-name">Tb</span>
    </div>
  </div>
  <div class="unit-conversion-computation-result">
    <p v-show="isMultipleOf4KiB">该结果值是 4 KiB 的倍数</p>
  </div>
</template>

<style>
h1,
p {
  margin: 0.5em 0;
}

.unit-conversion-computation-node {
  margin: 0.5em 0;
}

.unit-conversion-computation-node {
  float: left;
  width: 170px;
  margin: 0 8px 0 0;
}

.unit-conversion-computation-node .size-text {
  margin: 0 6px 0 0;
  width: 125px
}

@media screen and (max-width: 395px) {
  .unit-conversion-computation-node {
    width: 140px;
  }

  .unit-conversion-computation-node .size-text {
    width: 95px;
  }
}

.unit-conversion-computation-area::after {
  content: '';
  display: block;
  clear: both;
}

.unit-conversion-computation-result {
  margin: 0.5em 0 0.5em 0;
  height: 1em;
}
</style>
