<template>
  <div class="el-time-spinner" :class="{ 'has-seconds': showSeconds }">
    <div class="active-block">
      <div class="active-item" :class="{'disabled': disabled || hoursList[hours] }"></div>
      <div class="active-item" :class="{'disabled': disabled || minutesList[minutes] }"></div>
      <div v-if="showSeconds" class="active-item" :class="{'disabled': disabled || secondsList[seconds]}"></div>
    </div>
    <el-scrollbar
        @mouseenter.native="emitSelectRange('hours')"
        @mousemove.native="adjustCurrentSpinner('hours')"
        class="el-time-spinner__wrapper"
        :class="{'el-time-spinner_disable': disabled}"
        wrap-style="max-height: inherit;"
        view-class="el-time-spinner__list"
        noresize
        tag="ul"
        ref="hours">
      <template v-if="disabledHours">
        <li
            @click="handleClick('hours', { value: hour, disabled: enabled })"
            v-for="(enabled, hour) in disabledHours"
            class="el-time-spinner__item"
            :key="hour"
            :class="{ 'active': hour === hours, 'disabled': disabled || enabled }">{{ ('0' + (amPmMode ? (hour % 12 || 12) : hour )).slice(-2) }}{{ amPm(hour) }}{{ hour === hours ? '时' : ''}}</li>
      </template>
      <template v-else>
        <li
            @click="handleClick('hours', { value: hour, disabled: disabled })"
            v-for="(enabled, hour) in hoursList"
            class="el-time-spinner__item"
            :key="hour"
            :class="{ 'active': hour === hours, 'disabled': disabled || enabled }">{{ ('0' + (amPmMode ? (hour % 12 || 12) : hour )).slice(-2) }}{{ amPm(hour) }}{{ hour === hours ? '时' : ''}}</li>
      </template>
    </el-scrollbar>
    <el-scrollbar
        @mouseenter.native="emitSelectRange('minutes')"
        @mousemove.native="adjustCurrentSpinner('minutes')"
        class="el-time-spinner__wrapper"
        :class="{'el-time-spinner_disable': disabled}"
        wrap-style="max-height: inherit;"
        view-class="el-time-spinner__list"
        noresize
        tag="ul"
        ref="minutes">
      <template v-if="disabledMinutes">
        <li
            @click="handleClick('minutes', { value: key, disabled: enabled })"
            v-for="(enabled, key) in disabledMinutes"
            :key="key"
            class="el-time-spinner__item"
            :class="{ 'active': key === minutes, 'disabled': disabled || enabled }">{{ ('0' + key).slice(-2) }}{{ key === minutes ? '分' : '' }}</li>
      </template>
      <template v-else>
        <li
            @click="handleClick('minutes', { value: key, disabled: enabled })"
            v-for="(enabled, key) in minutesList"
            :key="key"
            class="el-time-spinner__item"
            :class="{ 'active': key === minutes, 'disabled': disabled || enabled }">{{ ('0' + key).slice(-2) }}{{ key === minutes ? '分' : ''}}</li>
      </template>
    </el-scrollbar>
    <el-scrollbar
        v-show="showSeconds"
        @mouseenter.native="emitSelectRange('seconds')"
        @mousemove.native="adjustCurrentSpinner('seconds')"
        class="el-time-spinner__wrapper"
        :class="{'el-time-spinner_disable': disabled}"
        wrap-style="max-height: inherit;"
        view-class="el-time-spinner__list"
        noresize
        tag="ul"
        ref="seconds">
      <template v-if="disabledSeconds">
        <li
            @click="handleClick('seconds', { value: key, disabled: second })"
            v-for="(second, key) in disabledSeconds"
            class="el-time-spinner__item"
            :class="{ 'active': key === seconds, 'disabled': disabled || second }"
            :key="key">{{ ('0' + key).slice(-2) }}{{ key === seconds ? '秒' : '' }}</li>
      </template>
      <template v-else>
        <li
            @click="handleClick('seconds', { value: key, disabled: second })"
            v-for="(second, key) in secondsList"
            class="el-time-spinner__item"
            :class="{ 'active': key === seconds, 'disabled': disabled || second }"
            :key="key">{{ ('0' + key).slice(-2) }}{{ key === seconds ? '秒' : '' }}</li>
      </template>
    </el-scrollbar>
  </div>
</template>

<script type="text/babel">
import { getRangeHours, getRangeMinutesOrSeconds, modifyTime } from 'modesign-ui/src/utils/date-util';
import ElScrollbar from 'modesign-ui/packages/scrollbar';
import RepeatClick from 'modesign-ui/src/directives/repeat-click';
import throttle from 'throttle-debounce/throttle';

export default {
  components: { ElScrollbar },

  directives: {
    repeatClick: RepeatClick
  },

  props: {
    date: {},
    value: {},
    defaultValue: {}, // reserved for future use
    showSeconds: {
      type: Boolean,
      default: true
    },
    amPmMode: {
      type: String,
      default: '' // 'a': am/pm; 'A': AM/PM
    },
    disabled: {
      type: Boolean,
      default: () => false
    }
  },
  computed: {
    hours() {
      return this.date && this.date.getHours();
    },
    minutes() {
      return this.date && this.date.getMinutes();
    },
    seconds() {
      return this.date && this.date.getSeconds()
    },
    hoursList() {
      return getRangeHours(this.$parent.disabledHours || []);
    },
    minutesList() {
      return getRangeMinutesOrSeconds(this.$parent.disabledMinutes || []);
    },
    secondsList() {
      return getRangeMinutesOrSeconds(this.$parent.disabledSeconds || [])
    }
  },
  data() {
    return {
      selectableRange: [],
      disabledHours: null,
      disabledMinutes: null,
      disabledSeconds: null,
      currentScrollbar: null
    };
  },

  mounted() {
    this.throttledHandler = throttle(400, (type) => {
      this.adjustCurrentSpinner(type);
    });
    this.$nextTick(() => {
      this.bindScrollEvent();
      this.initSpinnerHeight()
      this.$emit('mounted');
    });
    
  },

  methods: {
    initSpinnerHeight() {
      const nowClient = document.getElementsByClassName('el-time-spinner__wrapper')[0]
      let style = document.createElement('style')
      document.head.appendChild(style)
      let sheet = style.sheet
      sheet.addRule('.el-time-spinner__list:after', `height: ${nowClient.clientHeight - 28}px;`);
      sheet.insertRule(`.el-time-spinner__list:after{height: ${nowClient.clientHeight - 28}px;}`);
    },
    modifyDateField(type, value) {
      switch (type) {
        case 'hours':
          this.$emit('change', modifyTime(this.value ? new Date(this.value) : new Date(), value, this.minutes, this.seconds));
          break;
        case 'minutes':
          this.$emit('change', modifyTime(this.value ? new Date(this.value) : new Date(), this.hours, value, this.seconds));
          break;
        case 'seconds':
          this.$emit('change', modifyTime(this.value ? new Date(this.value) : new Date(), this.hours, this.minutes, value));
          break;
      }
    },

    handleClick(type, {value, disabled}) {
      if (!disabled) {
        this.modifyDateField(type, value);
        this.emitSelectRange(type);
        this.adjustSpinner(type, value);
      }
    },

    emitSelectRange(type) {
      if (type === 'hours') {
        this.$emit('select-range', 0, 2);
      } else if (type === 'minutes') {
        this.$emit('select-range', 3, 5);
      } else if (type === 'seconds') {
        this.$emit('select-range', 6, 8);
      }
      this.currentScrollbar = type;
    },

    bindScrollEvent() {
      const bindFuntion = (type) => {
        if(this.$refs[type]) {
          this.$refs[type].wrap.onscroll = (e) => {
            // TODO: scroll is emitted when set scrollTop programatically
            // should find better solutions in the future!
            this.handleScroll(type, e);
          };
        }
      };
      bindFuntion('hours');
      bindFuntion('minutes');
      if (this.showSeconds) {
        bindFuntion('seconds');
      }
    },

    handleScroll(type) {
      // 4 和 el-time-spinner__item的margin-top margin-bottom有关
      const value = Math.min(Math.round(this.$refs[type].wrap.scrollTop / (this.typeItemHeight(type) + 4)), (type === 'hours' ? 23 : 59));
      if (this.checkTime(value, type)) return
      this.modifyDateField(type, value);
      this.throttledHandler(type);
    },
    // 选择时间校验
    checkTime(val, type) {
      if (type === 'hours') {
        return this.disabledHours && this.disabledHours[val]
      }
      if (type === 'minutes') {
        return this.disabledMinutes && this.disabledMinutes[val]
      }
      if (type === 'seconds') {
        return this.disabledSeconds && this.disabledSeconds[val]
      }
    },
    // NOTE: used by datetime / date-range panel
    //       renamed from adjustScrollTop
    //       should try to refactory it
    adjustSpinners() {
      this.adjustSpinner('hours', this.hours);
      this.adjustSpinner('minutes', this.minutes);
      if (this.showSeconds) {
        this.adjustSpinner('seconds', this.seconds);
      }
    },

    adjustCurrentSpinner(type) {
      this.adjustSpinner(type, this[type]);
    },

    adjustSpinner(type, value) {
      const el = this.$refs[type].wrap;
      if (el) {
        // 4 和 el-time-spinner__item的margin-top margin-bottom有关
        el.scrollTop = Math.max(0, value * (this.typeItemHeight(type) + 4));
      }
    },

    scrollDown(step) {
      if (!this.currentScrollbar) {
        this.emitSelectRange('hours');
      }

      const label = this.currentScrollbar;
      const hoursList = this.hoursList;
      let now = this[label];

      if (this.currentScrollbar === 'hours') {
        let total = Math.abs(step);
        step = step > 0 ? 1 : -1;
        let length = hoursList.length;
        while (length-- && total) {
          now = (now + step + hoursList.length) % hoursList.length;
          if (hoursList[now]) {
            continue;
          }
          total--;
        }
        if (hoursList[now]) return;
      } else {
        now = (now + step + 60) % 60;
      }

      this.modifyDateField(label, now);
      this.adjustSpinner(label, now);
      this.$nextTick(() => this.emitSelectRange(this.currentScrollbar));
    },
    amPm(hour) {
      let shouldShowAmPm = this.amPmMode.toLowerCase() === 'a';
      if (!shouldShowAmPm) return '';
      let isCapital = this.amPmMode === 'A';
      let content = (hour < 12) ? ' am' : ' pm';
      if (isCapital) content = content.toUpperCase();
      return content;
    },
    typeItemHeight(type) {
      return this.$refs[type].$el.querySelector('li').offsetHeight;
    },
    scrollBarHeight(type) {
      return this.$refs[type].$el.offsetHeight;
    }
  }
};
</script>
