<template>
  <transition name="qf-zoom-in-top" @after-enter="handleEnter" @after-leave="handleLeave">
    <div
      v-show="visible"
      class="qf-picker-panel qf-date-picker qf-popper"
      :class="[{
        'has-sidebar': $slots.sidebar || shortcuts
      }, popperClass]">
      <div class="qf-picker-panel__body-wrapper">
        <slot name="sidebar" class="qf-picker-panel__sidebar"></slot>
        <div class="qf-picker-panel__sidebar" v-if="shortcuts">
          <button
            type="button"
            class="qf-picker-panel__shortcut"
            v-for="shortcut in shortcuts"
            @click="handleShortcutClick(shortcut)">{{ shortcut.text }}
          </button>
        </div>
        <div class="qf-picker-panel__body">
          <div
            class="qf-date-picker__header"
            :class="{ 'qf-date-picker__header--bordered': currentView === 'year' || currentView === 'month' }"
            v-show="currentView !== 'time'">
            <button
              type="button"
              @click="prevYear"
              class="qf-picker-panel__icon-btn qf-date-picker__prev-btn">
              <qf-font-icon name="ic-ic_shangyinian"></qf-font-icon>
            </button>
            <button
              type="button"
              @click="prevMonth"
              v-show="currentView === 'date'"
              class="qf-picker-panel__icon-btn qf-date-picker__prev-btn">
              <qf-font-icon name="ic-ic_shangyiyue"></qf-font-icon>
            </button>
            <span
              @click="showYearPicker"
              role="button"
              class="qf-date-picker__header-label">{{ yearLabel }}</span>
            <span
              @click="showMonthPicker"
              v-show="currentView === 'date'"
              role="button"
              class="qf-date-picker__header-label"
              :class="{ active: currentView === 'month' }">{{t(`qf.datepicker.month${ month + 1 }`)}}</span>
            <button
              type="button"
              @click="nextYear"
              class="qf-picker-panel__icon-btn qf-date-picker__next-btn">
              <qf-font-icon name="ic-ic_xiayinian"></qf-font-icon>
            </button>
            <button
              type="button"
              @click="nextMonth"
              v-show="currentView === 'date'"
              class="qf-picker-panel__icon-btn qf-date-picker__next-btn">
              <qf-font-icon name="ic-ic_xiayiyue"></qf-font-icon>
            </button>
          </div>

          <div class="qf-picker-panel__content">
            <date-table
              v-show="currentView === 'date'"
              @pick="handleDatePick"
              :selection-mode="selectionMode"
              :first-day-of-week="firstDayOfWeek"
              :value="new Date(value)"
              :default-value="defaultValue ? new Date(defaultValue) : null"
              :date="date"
              :disabled-date="disabledDate">
            </date-table>
            <year-table
              v-show="currentView === 'year'"
              @pick="handleYearPick"
              :value="new Date(value)"
              :default-value="defaultValue ? new Date(defaultValue) : null"
              :date="date"
              :disabled-date="disabledDate">
            </year-table>
            <month-table
              v-show="currentView === 'month'"
              @pick="handleMonthPick"
              :value="new Date(value)"
              :default-value="defaultValue ? new Date(defaultValue) : null"
              :date="date"
              :disabled-date="disabledDate">
            </month-table>
          </div>
        </div>
      </div>

      <div
        class="qf-picker-panel__footer"
        v-show="footerVisible && currentView === 'date'">
        <qf-button
          size="mini"
          type="text"
          class="qf-picker-panel__link-btn"
          @click="changeToNow">
          {{ 'qf.datepicker.now' }}
        </qf-button>
        <qf-button
          plain
          size="mini"
          class="qf-picker-panel__link-btn"
          @click="confirm">
          {{ 'qf.datepicker.confirm' }}
        </qf-button>
      </div>
    </div>
  </transition>
</template>

<script>
  import DateUtil from '../../util/DateUtil';
  import QfButton from '../../button';
  import QfFontIcon from '../../font-icon';
  import YearTable from '../base/year-table';
  import MonthTable from '../base/month-table';
  import DateTable from '../base/date-table';
  import LocaleMixin from '../../locale/mixin';

  export default {
    mixins: [LocaleMixin],
    watch: {
      value(val) {
        if (DateUtil.isDate(val)) {
          this.date = new Date(val);
        } else {
          this.date = this.defaultValue ? new Date(this.defaultValue) : new Date();
        }
      },
      defaultValue(val) {
        if (!DateUtil.isDate(this.value)) {
          this.date = val ? new Date(val) : new Date();
        }
      },
      selectionMode(newVal) {
        if (newVal === 'month') {
          /* istanbul ignore next */
          if (this.currentView !== 'year' || this.currentView !== 'month') {
            this.currentView = 'month';
          }
        }
      }
    },
    methods: {
      handleClear() {
        this.date = this.defaultValue ? new Date(this.defaultValue) : new Date();
        this.$emit('pick', null);
      },
      emit(value, ...args) {
        if (!value) {
          this.$emit('pick', value, ...args);
          return;
        }
        this.$emit('pick', DateUtil.clearTime(value), ...args);
      },
      showMonthPicker() {
        this.currentView = 'month';
      },
      showYearPicker() {
        this.currentView = 'year';
      },
      prevMonth() {
        this.date = DateUtil.prevMonth(this.date);
      },
      nextMonth() {
        this.date = DateUtil.nextMonth(this.date);
      },
      prevYear() {
        if (this.currentView === 'year') {
          this.date = DateUtil.prevYear(this.date, 10);
        } else {
          this.date = DateUtil.prevYear(this.date);
        }
      },
      nextYear() {
        if (this.currentView === 'year') {
          this.date = DateUtil.nextYear(this.date, 10);
        } else {
          this.date = DateUtil.nextYear(this.date);
        }
      },
      handleShortcutClick(shortcut) {
        if (shortcut.onClick) {
          shortcut.onClick(this);
        }
      },
      handleMonthPick(month) {
        if (this.selectionMode === 'month') {
          this.date = DateUtil.modifyDate(this.date, this.year, month, 1);
          this.emit(this.date);
        } else {
          this.date = DateUtil.changeYearMonthAndClampDate(this.date, this.year, month);
          // TODO: should emit intermediate value ??
          // this.emit(this.date)
          this.currentView = 'date';
        }
      },
      handleDatePick(value) {
        if (this.selectionMode === 'day') {
          this.date = DateUtil.modifyDate(this.date, value.getFullYear(), value.getMonth(), value.getDate());
          this.emit(this.date, this.showTime);
        } else if (this.selectionMode === 'week') {
          this.emit(value.date);
        }
      },
      handleYearPick(year) {
        if (this.selectionMode === 'year') {
          this.date = DateUtil.modifyDate(this.date, year, 0, 1);
          this.emit(this.date);
        } else {
          this.date = DateUtil.changeYearMonthAndClampDate(this.date, year, this.month);
          // TODO: should emit intermediate value ??
          // this.emit(this.date, true)
          this.currentView = 'month';
        }
      },
      changeToNow() {
        // NOTE: not a permanent solution
        //       consider disable "now" button in the future
        if (!this.disabledDate || !this.disabledDate(new Date())) {
          this.date = new Date();
          this.emit(this.date);
        }
      },
      confirm() {
        this.emit(this.date);
      },
      resetView() {
        if (this.selectionMode === 'month') {
          this.currentView = 'month';
        } else if (this.selectionMode === 'year') {
          this.currentView = 'year';
        } else {
          this.currentView = 'date';
        }
      },
      handleEnter() {
        document.body.addEventListener('keydown', this.handleKeydown);
      },
      handleLeave() {
        this.$emit('dodestroy');
        document.body.removeEventListener('keydown', this.handleKeydown);
      },
      handleKeydown(event) {
        const keyCode = event.keyCode;
        const list = [38, 40, 37, 39];
        if (this.visible) {
          if (list.indexOf(keyCode) !== -1) {
            this.handleKeyControl(keyCode);
            event.stopPropagation();
            event.preventDefault();
          }
          if (keyCode === 13) { // Enter
            this.$emit('pick', this.date, false);
          }
        }
      },
      handleKeyControl(keyCode) {
        const mapping = {
          'year': {
            38: -4, 40: 4, 37: -1, 39: 1, offset: (date, step) => date.setFullYear(date.getFullYear() + step)
          },
          'month': {
            38: -4, 40: 4, 37: -1, 39: 1, offset: (date, step) => date.setMonth(date.getMonth() + step)
          },
          'week': {
            38: -1, 40: 1, 37: -1, 39: 1, offset: (date, step) => date.setDate(date.getDate() + step * 7)
          },
          'day': {
            38: -7, 40: 7, 37: -1, 39: 1, offset: (date, step) => date.setDate(date.getDate() + step)
          }
        };
        const mode = this.selectionMode;
        const year = 3.1536e10;
        const now = this.date.getTime();
        const newDate = new Date(this.date.getTime());
        while (Math.abs(now - newDate.getTime()) <= year) {
          const map = mapping[mode];
          map.offset(newDate, map[keyCode]);
          if (typeof this.disabledDate === 'function' && this.disabledDate(newDate)) {
            continue;
          }
          this.date = newDate;
          this.$emit('pick', newDate, true);
          break;
        }
      },
      isValidValue(value) {
        return value && !isNaN(value) && (
          typeof this.disabledDate === 'function'
            ? !this.disabledDate(value)
            : true
        );
      }
    },
    components: {
      YearTable, MonthTable, DateTable, QfButton, QfFontIcon
    },
    data() {
      return {
        popperClass: '',
        date: new Date(),
        value: '',
        defaultValue: null,
        showTime: false,
        selectionMode: 'day',
        shortcuts: '',
        visible: false,
        currentView: 'date',
        disabledDate: '',
        firstDayOfWeek: 7,
        showWeekNumber: false,
        format: '',
        arrowControl: false
      };
    },
    computed: {
      year() {
        return this.date.getFullYear();
      },
      month() {
        return this.date.getMonth();
      },
      week() {
        return DateUtil.getWeekNumber(this.date);
      },
      monthDate() {
        return this.date.getDate();
      },
      footerVisible() {
        return this.showTime;
      },
      visibleDate() {
        const date = this.value || this.defaultValue;
        return date ? DateUtil.format(date, this.dateFormat) : '';
      },
      yearLabel() {
        const yearTranslation = this.t('qf.datepicker.year');
        if (this.currentView === 'year') {
          const startYear = Math.floor(this.year / 10) * 10;
          if (yearTranslation) {
            return startYear + ' ' + yearTranslation + ' - ' + (startYear + 9) + ' ' + yearTranslation;
          }
          return startYear + ' - ' + (startYear + 9);
        }
        return this.year + ' ' + yearTranslation;
      },
      dateFormat() {
        if (this.format) {
          return this.format.replace('HH', '').replace(/[^a-zA-Z]*mm/, '').replace(/[^a-zA-Z]*ss/, '').trim();
        } else {
          return 'yyyy-MM-dd';
        }
      }
    }
  };
</script>
