<template>
  <div
    :class="['bx-picker-well', className]"
    @touchstart="onTouchStart"
    @touchmove.prevent="onTouchMove"
    @touchend="onTouchEnd"
    @touchcancel="onTouchEnd"
    :style="pickerStyle"
    >
    <ul
      class="bx-picker-scroll"
      :style="wrapperStyle"
      ref="bxPickerUl"
      >
      <li
        v-for="(item,index) in options"
        :key="index"
        :class="['bx-picker-item',{'disabled': isDisabled(item)},{'selected': index === currentIndex}]"
        :ref="(index === currentIndex?'bxPickerLiSelect':'bxPickerLi')"
        :style="{opacity: isTouchInline?0.5:(1-Math.abs(index-currentIndex)*0.3)}"
        @click="setOptionIndex(index,true)"
        >
        {{ typeof item === 'object' && item[valueKey] ? item[valueKey] : item }}
      </li>
    </ul>
  </div>
</template>
<script>
function range(num, min, max) {
  return Math.min(Math.max(num, min), max)
}
const DEFAULT_DURATION = 200

export default {
  name: 'picker-item',
  props: {
    values: {
      type: Array,
      default: () => [],
    },
    defaultIndex: {
      type: Number,
      default: 0,
    },
    itemCount: {
      type: Number,
      default: 7,
    },

    valueKey: {
      type: String,
      default: 'text',
    },
    className: {
      type: String,
      default: '',
    },
  },
  components: {},
  data() {
    return {
      pickerTranslateY: 0,
      pickerState: {
        data: this.values,
        selectedId: null,
        index: 0,
        startPos: null,
        translateY: 0,
        startTranslateY: 0,
        dragging: true,
      },
      options: JSON.parse(JSON.stringify(this.values)),
      currentIndex: this.defaultIndex, // 当前选择项

      startY: 0,
      offset: 0,
      duration: 0,
      startOffset: 0,
      isTouchInline: false,
      itemHeight: 30,
      itemSelectHeight: 40,
    }
  },
  watch: {
    defaultIndex() {
      this.setOptionIndex(this.defaultIndex)
    },
    values(n) {
      if (n) {
        this.options = JSON.parse(JSON.stringify(n))
      }
    },
  },
  computed: {
    pickerStyle() {
      return {
        height: `${this.itemHeight * (this.itemCount - 1) +
          this.itemSelectHeight}px`,
      }
    },
    count() {
      return this.options.length
    },
    baseOffset() {
      return (this.itemHeight * (this.itemCount - 1)) / 2
    },
    wrapperStyle() {
      return {
        transition: `${this.duration}ms`,
        '-webkit-transition': `${this.duration}ms`,
        '-moz-transition': `${this.duration}ms`,
        '-o-transition': `${this.duration}ms`,
        transform: `translate3d(0, ${this.offset + this.baseOffset}px, 0)`,
        '-ms-transform': `translate3d(0, ${this.offset +
          this.baseOffset}px, 0)`,
        '-webkit-transform': `translate3d(0, ${this.offset +
          this.baseOffset}px, 0)`,
        '-o-transform': `translate3d(0, ${this.offset + this.baseOffset}px, 0)`,
        '-moz-transform': `translate3d(0, ${this.offset +
          this.baseOffset}px, 0)`,
        lineHeight: `${this.itemHeight}px`,
      }
    },
  },
  methods: {
    onTouchStart(event) {
      this.startY = event.touches[0].clientY
      this.startOffset = this.offset
      this.duration = 0
      this.isTouchInline = false
    },
    onTouchMove(event) {
      const deltaY = event.touches[0].clientY - this.startY
      this.isTouchInline = true
      this.offset = range(
        this.startOffset + deltaY,
        -((this.count - 1) * this.itemHeight + this.itemSelectHeight),
        this.itemHeight,
      )
    },
    onTouchEnd() {
      if (this.offset !== this.startOffset) {
        this.duration = DEFAULT_DURATION
        const index = range(
          Math.round(-this.offset / this.itemHeight),
          0,
          this.count - 1,
        )
        this.setOptionIndex(index, true)
      }
      this.isTouchInline = false
    },
    isDisabled(option) {
      return this.isObject(option) && option.disabled
    },
    isObject(value) {
      const type = typeof value
      return value != null && (type === 'object' || type === 'function')
    },
    setOptionIndex(index, userAction) {
      if (index < this.options.length) {
        if (index !== this.currentIndex) {
          this.currentIndex = index
          if (userAction) {
            this.$emit('change', index)
          }
        }
      } else if (index !== this.currentIndex) {
        this.currentIndex = this.options.length - 1
        if (userAction) {
          this.$emit('change', this.currentIndex)
        }
      }
      this.offset = -this.currentIndex * this.itemHeight
    },
    getOptionText(option) {
      return this.isObject(option) && this.valueKey in option
        ? option[this.valueKey]
        : option
    },
    setValue(value) {
      const { options } = this
      for (let i = 0; i < options.length; i += 1) {
        if (this.getOptionText(options[i]) === value) {
          return this.setOptionIndex(i, true)
        }
      }
      return this.setOptionIndex(0, true)
    },
    getValue() {
      return this.options[this.currentIndex]
    },
  },
  created() {
    if (this.$parent && this.$parent.children) {
      this.$parent.children.push(this)
    }
  },
  mounted() {
    this.setOptionIndex(this.currentIndex)
    this.$nextTick(() => {
      if (this.$refs.bxPickerLi) {
        this.itemHeight = this.$refs.bxPickerLi[0].offsetHeight
      }
      if (this.$refs.bxPickerLiSelect) {
        this.itemSelectHeight = this.$refs.bxPickerLiSelect[0].offsetHeight
      }
    })
  },
  destroyed() {
    const { children } = this.$parent
    if (children) {
      children.splice(children.indexOf(this), 1)
    }
  },
}
</script>
<style lang="postcss">
@import './index.css';
</style>
