<template>
  <transition name="el-zoom-in-top" @after-leave="$emit('dodestroy')">
    <div v-show="visible" class="el-time-panel el-popper" :class="popperClass">
      <div
        class="el-time-panel__content"
        :class="{ 'has-seconds': showSeconds }"
      >
        <time-spinner
          ref="spinner"
          @change="handleChange"
          :arrow-control="useArrow"
          :show-seconds="showSeconds"
          :am-pm-mode="amPmMode"
          @select-range="setSelectionRange"
          :date="date"
        >
        </time-spinner>
      </div>
      <div class="el-time-panel__footer">
        <button
          type="button"
          class="el-time-panel__btn cancel"
          @click="handleCancel"
        >
          {{ t("el.datepicker.cancel") }}
        </button>
        <button
          type="button"
          class="el-time-panel__btn"
          :class="{ confirm: !disabled }"
          @click="handleConfirm()"
        >
          {{ t("el.datepicker.confirm") }}
        </button>
      </div>
    </div>
  </transition>
</template>

<script type="text/babel">
/* eslint-disable */
import {
  limitTimeRange,
  isDate,
  clearMilliseconds,
  timeWithinRange,
} from "element-ui/src/utils/date-util";
import Locale from "element-ui/src/mixins/locale";
import TimeSpinner from "../basic/time-spinner";

export default {
  mixins: [Locale],

  components: {
    TimeSpinner,
  },

  props: {
    visible: Boolean,
    timeArrowControl: Boolean,
  },

  watch: {
    visible(val) {
      if (val) {
        this.oldValue = this.value;
        this.$nextTick(() => this.$refs.spinner.emitSelectRange("hours"));
      } else {
        this.needInitAdjust = true;
      }
    },

    value(newVal) {
      let date;
      if (newVal instanceof Date) {
        date = limitTimeRange(newVal, this.selectableRange, this.format);
      } else if (!newVal) {
        date = this.defaultValue ? new Date(this.defaultValue) : new Date();
      }

      this.date = date;
      if (this.visible && this.needInitAdjust) {
        this.$nextTick((_) => this.adjustSpinners());
        this.needInitAdjust = false;
      }
    },

    selectableRange(val) {
      this.$refs.spinner.selectableRange = val;
    },

    defaultValue(val) {
      if (!isDate(this.value)) {
        this.date = val ? new Date(val) : new Date();
      }
    },
  },

  data() {
    return {
      popperClass: "",
      format: "HH:mm:ss",
      value: "",
      defaultValue: null,
      date: new Date(),
      oldValue: new Date(),
      selectableRange: [],
      selectionRange: [0, 2],
      disabled: false,
      arrowControl: false,
      needInitAdjust: true,
    };
  },

  computed: {
    showSeconds() {
      return (this.format || "").indexOf("ss") !== -1;
    },
    useArrow() {
      return this.arrowControl || this.timeArrowControl || false;
    },
    amPmMode() {
      if ((this.format || "").indexOf("A") !== -1) return "A";
      if ((this.format || "").indexOf("a") !== -1) return "a";
      return "";
    },
  },

  methods: {
    handleCancel() {
      this.$emit("pick", this.oldValue, false);
    },

    handleChange(date) {
      // this.visible avoids edge cases, when use scrolls during panel closing animation
      if (this.visible) {
        this.date = clearMilliseconds(date);
        // if date is out of range, do not emit
        if (this.isValidValue(this.date)) {
          this.$emit("pick", this.date, true);
        }
      }
    },

    setSelectionRange(start, end) {
      this.$emit("select-range", start, end);
      this.selectionRange = [start, end];
    },

    handleConfirm(visible = false, first) {
      if (first) return;
      const date = clearMilliseconds(
        limitTimeRange(this.date, this.selectableRange, this.format)
      );
      this.$emit("pick", date, visible, first);
    },

    handleKeydown(event) {
      const keyCode = event.keyCode;
      const mapping = { 38: -1, 40: 1, 37: -1, 39: 1 };

      // Left or Right
      if (keyCode === 37 || keyCode === 39) {
        const step = mapping[keyCode];
        this.changeSelectionRange(step);
        event.preventDefault();
        return;
      }

      // Up or Down
      if (keyCode === 38 || keyCode === 40) {
        const step = mapping[keyCode];
        this.$refs.spinner.scrollDown(step);
        event.preventDefault();
        return;
      }
    },

    isValidValue(date) {
      return timeWithinRange(date, this.selectableRange, this.format);
    },

    adjustSpinners() {
      return this.$refs.spinner.adjustSpinners();
    },

    changeSelectionRange(step) {
      const list = [0, 3].concat(this.showSeconds ? [6] : []);
      const mapping = ["hours", "minutes"].concat(
        this.showSeconds ? ["seconds"] : []
      );
      const index = list.indexOf(this.selectionRange[0]);
      const next = (index + step + list.length) % list.length;
      this.$refs.spinner.emitSelectRange(mapping[next]);
    },
  },

  mounted() {
    this.$nextTick(() => this.handleConfirm(true, true));
    this.$emit("mounted");
  },
};
</script>
