<template>
  <div class="dv-active-ring-chart">
    <div class="active-ring-chart-container" ref="active-ring-chart" />
    <div class="active-ring-info">
      <dv-digital-flop :config="digitalFlop" />
      <div class="active-ring-name" :style="fontSize">{{ ringName }}</div>
    </div>
  </div>
</template>

<script>
import Charts from '@jiaminghi/charts'

import dvDigitalFlop from '../digitalFlop'

import { deepMerge } from '@jiaminghi/charts/lib/util/index'

import { deepClone } from '@jiaminghi/c-render/lib/plugin/util'

export default {
  name: 'ActiveRingChart',
  components: {
    dvDigitalFlop
  },
  props: {
    config: {
      type: Object,
      default: () => ({})
    }
  },
  data () {
    return {
      defaultConfig: {
        /**
         * @description Ring radius
         * @type {String|Number}
         * @default radius = '50%'
         * @example radius = '50%' | 100
         */
        radius: '50%',
        /**
         * @description Active ring radius
         * @type {String|Number}
         * @default activeRadius = '55%'
         * @example activeRadius = '55%' | 110
         */
        activeRadius: '55%',
        /**
         * @description Ring data
         * @type {Array}
         * @default data = [{ name: '', value: 0 }]
         */
        data: [{ name: '', value: 0 }],
        /**
         * @description Ring line width
         * @type {Number}
         * @default lineWidth = 20
         */
        lineWidth: 20,
        /**
         * @description Active time gap (ms)
         * @type {Number}
         * @default activeTimeGap = 3000
         */
        activeTimeGap: 3000,
        /**
         * @description Ring color (hex|rgb|rgba)
         * @type {Array<String>}
         * @default color = [Charts Default Color]
         */
        color: [],
        /**
         * @description Digital flop style
         * @type {Object}
         */
        digitalFlopStyle: {
          fontSize: 25,
          fill: '#fff'
        },
        /**
         * @description CRender animationCurve
         * @type {String}
         * @default animationCurve = 'easeOutCubic'
         */
        animationCurve: 'easeOutCubic',
        /**
         * @description CRender animationFrame
         * @type {String}
         * @default animationFrame = 50
         */
        animationFrame: 50
      },

      mergedConfig: null,

      chart: null,

      activeIndex: 0,

      animationHandler: ''
    }
  },
  computed: {
    digitalFlop () {
      const { mergedConfig, activeIndex } = this

      if (!mergedConfig) return {}

      const { digitalFlopStyle, data } = mergedConfig

      const value = data.map(({ value }) => value)

      const sum = value.reduce((all, v) => all + v, 0)

      const percent = parseInt(value[activeIndex] / sum * 100)

      return {
        content: '{nt}%',
        number: [percent],
        style: digitalFlopStyle
      }
    },
    ringName () {
      const { mergedConfig, activeIndex } = this

      if (!mergedConfig) return ''

      return mergedConfig.data[activeIndex].name
    },
    fontSize () {
      const { mergedConfig } = this

      if (!mergedConfig) return ''

      return `font-size: ${mergedConfig.digitalFlopStyle.fontSize}px;`
    }
  },
  watch: {
    config () {
      const { animationHandler, mergeConfig, setRingOption } = this

      clearTimeout(animationHandler)

      this.activeIndex = 0

      mergeConfig()

      setRingOption()
    }
  },
  methods: {
    init () {
      const { initChart, mergeConfig, setRingOption } = this

      initChart()

      mergeConfig()

      setRingOption()
    },
    initChart () {
      const { $refs } = this

      this.chart = new Charts($refs['active-ring-chart'])
    },
    mergeConfig () {
      const { defaultConfig, config } = this

      this.mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {})
    },
    setRingOption () {
      const { getRingOption, chart, ringAnimation } = this

      const option = getRingOption()

      chart.setOption(option)

      ringAnimation()
    },
    getRingOption () {
      const { mergedConfig, getRealRadius } = this

      const radius = getRealRadius()

      mergedConfig.data.forEach(dataItem => {
        dataItem.radius = radius
      })

      return {
        series: [
          {
            type: 'pie',
            ...mergedConfig,
            outsideLabel: {
              show: false
            }
          }
        ]
      }
    },
    getRealRadius (active = false) {
      const { mergedConfig, chart } = this

      const { radius, activeRadius, lineWidth } = mergedConfig

      const maxRadius = Math.min(...chart.render.area) / 2

      const halfLineWidth = lineWidth / 2

      let realRadius = active ? activeRadius : radius

      if (typeof realRadius !== 'number') realRadius = parseInt(realRadius) / 100 * maxRadius

      const insideRadius = realRadius - halfLineWidth
      const outSideRadius = realRadius + halfLineWidth

      return [insideRadius, outSideRadius]
    },
    ringAnimation () {
      let { activeIndex, getRingOption, chart, getRealRadius } = this

      const radius = getRealRadius()
      const active = getRealRadius(true)

      const option = getRingOption()

      const { data } = option.series[0]

      data.forEach((dataItem, i) => {
        if (i === activeIndex) {
          dataItem.radius = active
        } else {
          dataItem.radius = radius
        }
      })

      chart.setOption(option)

      const { activeTimeGap } = option.series[0]

      this.animationHandler = setTimeout(foo => {
        activeIndex += 1

        if (activeIndex >= data.length) activeIndex = 0

        this.activeIndex = activeIndex

        this.ringAnimation()
      }, activeTimeGap)
    }
  },
  mounted () {
    const { init } = this

    init()
  },
  beforeDestroy () {
    const { animationHandler } = this

    clearTimeout(animationHandler)
  }
}
</script>

<style lang="less">
.dv-active-ring-chart {
  position: relative;

  .active-ring-chart-container {
    width: 100%;
    height: 100%;
  }

  .active-ring-info {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0px;
    top: 0px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    .dv-digital-flop {
      width: 100px;
      height: 30px;
    }

    .active-ring-name {
      width: 100px;
      height: 30px;
      color: #fff;
      text-align: center;
      vertical-align: middle;
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }
  }
}
</style>