
<template>
  <div
    :class="[b(), className]"
    :style="columnStyle"
    @touchstart="onTouchStart"
    @touchmove.prevent="onTouchMove"
    @touchend="onTouchEnd"
    @touchcancel="onTouchEnd"
  >
    <ul :style="wrapperStyle">
      <li
        v-for="(option, index) in options"
        v-text="getOptionText(option)"
        class="eye-ellipsis"
        :class="b('item', {
          disabled: isDisabled(option),
          selected: index === currentIndex
        })"
        @click="setIndex(index, true)"
      ></li>
    </ul>
  </div>
</template>

<script>

import { Component,Core } from 'eye-core';


const DEFAULT_DURATION = 200;
const range = (num, arr) => Math.min(Math.max(num, arr[0]), arr[1]);

export default Component({

  name: 'picker-column',

  props: {
    labelField: String,
    valueField:String,
    className: String,
    itemHeight: Number,
    visibleItemCount: Number,
    options: {
      type: Array,
      default: () => []
    },
    defaultIndex: {
      type: Number,
      default: 0
    }
  },

  data() {
    return {
      startY: 0,
      offset: 0,
      duration: 0,
      startOffset: 0,
      currentIndex: this.defaultIndex
    };
  },

  onCreate() {
    this.$parent && this.$parent.children.push(this);
  },

  onInit() {
    this.setIndex(this.currentIndex);
  },

  onDestroy() {
    this.$parent && this.$parent.children.splice(this.$parent.children.indexOf(this), 1);
  },

  watch: {
    defaultIndex() {
      this.setIndex(this.defaultIndex);
    },

    options(next, prev) {
      if (JSON.stringify(next) !== JSON.stringify(prev)) {
        this.setIndex(0);
      }
    }
  },

  computed: {
    count() {
      return this.options.length;
    },

    baseOffset() {
      return this.itemHeight * (this.visibleItemCount - 1) / 2;
    },

    columnStyle() {
      return {
        height: (this.itemHeight * this.visibleItemCount) + 'px'
      };
    },

    wrapperStyle() {
      return {
        transition: `${this.duration}ms`,
        transform: `translate3d(0, ${this.offset + this.baseOffset}px, 0)`,
        lineHeight: this.itemHeight + 'px'
      };
    },

    currentValue() {
      return this.options[this.currentIndex];
    },

    currentLabel() {
        return this.getOptionText(this.currentValue)
    }
  },

  methods: {
    onTouchStart(event) {
      this.startY = event.touches[0].clientY;
      this.startOffset = this.offset;
      this.duration = 0;
    },

    onTouchMove(event) {
      const deltaY = event.touches[0].clientY - this.startY;
      this.offset = range(this.startOffset + deltaY, [
        -(this.count * this.itemHeight),
        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.setIndex(index, true);
      }
    },

    adjustIndex(index) {
      index = range(index, [0, this.count]);
      for (let i = index; i < this.count; i++) {
        if (!this.isDisabled(this.options[i])) return i;
      }
      for (let i = index - 1; i >= 0; i--) {
        if (!this.isDisabled(this.options[i])) return i;
      }
    },

    isDisabled(option) {
      return Core._.isObject(option) && option.disabled;
    },

    getOptionText(option) {
      return Core._.isObject(option) && this.labelField in option ? option[this.labelField] : option;
    },

    getOptionValue(option) {
        return Core._.isObject(option) && this.valueField in option ? option[this.valueField] : option;
    },

    setIndex(index, userAction) {
      index = this.adjustIndex(index);
      this.offset = -index * this.itemHeight;

      if (index !== this.currentIndex) {
        this.currentIndex = index;
        userAction && this.$emit('change', index);
      }
    },

    setValue(value) {
        const { options } = this;
        for (let i = 0; i < options.length; i++) {
            if (this.getOptionValue(options[i]) === this.getOptionValue(value)) {
                this.setIndex(i);
                return;
            }
        }
    }
  }
});
</script>
