<template>
  <div class="dg-json-view">
    <div :class="['json-view', length ? 'closeable' : '']" :style="'font-size:' + fontSize + 'px'">
      <span v-if="length" :class="['angle', innerclosed ? 'closed' : '']" @click="toggleClose"> </span>
      <div class="content-wrap">
        <p class="first-line">
          <span v-if="jsonKey" class="json-key">"{{ jsonKey }}": </span>
          <span v-if="length">
            {{ prefix }}
            {{ innerclosed ? '...' + subfix : '' }}
            <span class="json-note">
              {{ innerclosed ? ' // count: ' + length : '' }}
            </span>
          </span>
          <span v-if="!length">{{ isArray ? '[]' : '{}' }}</span>
        </p>
        <div v-if="!innerclosed && length" class="json-body">
          <template v-for="(item, index) in items">
            <dg-json-view
              v-if="item.isJSON"
              :key="index"
              :closed="closed"
              :json="item.value"
              :json-key="item.key"
              :is-last="index === items.length - 1"
            ></dg-json-view>
            <p v-else :key="index" class="json-item">
              <span class="json-key">
                {{ isArray ? '' : '"' + item.key + '"' }}
              </span>
              :
              <span class="json-value">
                {{ item.value + (index === items.length - 1 ? '' : ',') }}
              </span>
            </p>
          </template>
          <span v-show="!innerclosed" class="body-line"></span>
        </div>
        <p v-if="!innerclosed && length" class="last-line">
          <span>{{ subfix }}</span>
        </p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'DgJsonView',
  props: {
    json: [Object, Array],
    jsonKey: {
      type: String,
      default: '',
    },
    closed: {
      type: Boolean,
      default: false,
    },
    isLast: {
      type: Boolean,
      default: true,
    },
    fontSize: {
      type: Number,
      default: 13,
    },
  },
  data() {
    return {
      innerclosed: true,
    }
  },
  computed: {
    isArray() {
      return Object.prototype.toString.call(this.json) === '[object Array]'
    },
    length() {
      return this.isArray ? this.json.length : Object.keys(this.json).length
    },
    subfix() {
      return (this.isArray ? ']' : '}') + (this.isLast ? '' : ',')
    },
    prefix() {
      return this.isArray ? '[' : '{'
    },
    items() {
      if (this.isArray) {
        return this.json.map((item) => {
          const isJSON = this.isObjectOrArray(item)
          return {
            value: isJSON ? item : JSON.stringify(item),
            isJSON,
            key: '',
          }
        })
      }
      const json = this.json
      return Object.keys(json).map((key) => {
        const item = json[key]
        const isJSON = this.isObjectOrArray(item)
        return {
          value: isJSON ? item : JSON.stringify(item),
          isJSON,
          key,
        }
      })
    },
  },
  created() {
    this.innerclosed = this.closed
    this.$watch('closed', () => {
      this.innerclosed = this.closed
    })
  },
  methods: {
    isObjectOrArray(source) {
      const type = Object.prototype.toString.call(source)
      const res = type === '[object Array]' || type === '[object Object]'
      return res
    },
    toggleClose() {
      if (this.innerclosed) {
        this.innerclosed = false
      } else {
        this.innerclosed = true
      }
    },
  },
}
</script>
