<template>
  <!-- <div class="date-time-picker"> -->
  <input ref="dtpInput"
         type="text"
         class="date-time-picker__ipt"
         readonly
         v-model="cvalue"
         @focus="tapShowPicker" />
  <!-- </div> -->
</template>
<script>
import Picker from 'better-picker';
/*
  是否要加0的map
 */
const DOUBLE_MAP = [
  'MM',
  'DD',
  'HH',
  'mm',
  'ss'
];
/*
  是否要加0的列表
 */
const DEFAULT_MAP = {
  y: 'y',
  M: 'M',
  d: 'd',
  h: 'h',
  m: 'm',
  s: 's'
};
export default {
  name: 'DateTimePicker',
  props: {
    /*
      后缀仅允许'-','年','/',':' ,其他汉字
      占位仅允许
      YYYY
      MM或M
      DD或D
      HH或H
      mm或m
      ss或s
     */
    format: {
      type: String,
      // default: ' H时mm分ss秒'
      default: 'YYYY-M-D H:m:s'
    },

    /**
     * 月份要少一
     */
    min: {
      type: Date,
      default() {
        return new Date(1900, 0, 1, 0, 0, 0);
      }
    },
    max: {
      type: Date,
      default() {
        return new Date(2050, 11, 31, 23, 59, 59);
      }
    },
    value: {
      type: [String, Date],
      default() {
        return new Date();
      }
    },
    title: {
      type: String,
      default: ''
    },
    confirmColor: {
      type: String,
      default: '#fdd535'
    },
    // 是否立即把当前日期显示到input框
    immediate: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      picker: null,
      cvalue: '',
      data: [],
      selectedIndex: [],
      selectedValue: [],
      formatSuffix: [],
      hasYear: false,
      hasMonth: false,
      hasDate: false,
      hasHour: false,
      hasMinute: false,
      hasSecond: false,
      years: [],
      months: [],
      dates: [],
      hours: [],
      minutes: [],
      seconds: [],
      currentDate: {},
      initNum: 0
    };
  },
  computed: {

  },
  watch: {
    title(val, oldVal) {
      this.$nextTick(() => {
        this.picker.panelEl.querySelector('.picker-title').innerHTML = val;
      });
    },
    value: {
      handler(val, oldVal) {
        const { format } = this;
        this.formatSuffix = this.getFormat(format);
        this.hasYear = /YYYY/.test(format);
        this.hasMonth = /M+/.test(format);
        this.hasDate = /D+/.test(format);


        if (val === '') {
          this.cvalue = '';
          return;
        }

        this.initNum++;
        const date = val;

        this.resetCurrentDate(date);
        // this.currentDate = {
        //   [DEFAULT_MAP['y']]: date.getFullYear(),
        //   [DEFAULT_MAP['M']]: date.getMonth() + 1,
        //   [DEFAULT_MAP['d']]: date.getDate(),
        //   [DEFAULT_MAP['h']]: date.getHours(),
        //   [DEFAULT_MAP['m']]: date.getMinutes(),
        //   [DEFAULT_MAP['s']]: date.getSeconds()
        // };

        const arr = [];
        this.formatSuffix = this.getFormat(this.format);
        this.formatSuffix.map(item =>
          arr.push(this.currentDate[item.t])
        );
        // 可能需要判断清空的情况
        if (this.immediate || this.initNum !== 1) {
          // 赋值显示到文本框
          this.cvalue = this.getValueByFormat(arr);
          const date = this.formatCurrentDate(arr);
          console.log('arr :', arr);
          this.$emit('on-select', this.cvalue, date);
        }

        // 改变了日期，所以要改变index
        this.resetSelectIndex();
      },
      immediate: true
    }
  },
  created() {
    this.init();
  },
  mounted() {
    this.initPicker();
  },
  methods: {
    initPicker() {
      const { data, selectedIndex, title } = this;
      const picker = this.picker = new Picker({
        data,
        selectedIndex,
        title
      });
      let $item;
      for (let i = 0, len = picker.wheelEl.length; i < len; i++) {
        $item = picker.wheelEl[i];
        $item.style.fontSize = '16px';
      }

      picker.confirmEl.style.color = this.confirmColor;
      picker.maskEl.addEventListener('click', () => {
        picker.hide();
      });
      picker.on('picker.select', (selectedVal, selectedIndex) => {
        this.cvalue = this.getValueByFormat(selectedVal);

        const date = this.formatCurrentDate(selectedVal);

        this.$emit('on-select', this.cvalue, date);
      });
      /**
       * @desc 改变picker的时候触发
       */
      picker.on('picker.change', (index, selectedIndex) => {
        // 改变了年份时候触发天数
        if (index === 0 && this.hasYear && this.hasMonth && this.hasDate) {
          console.log('年份:改变了时候触发天数');
          // 重新获取当前月份天数
          const year = this.getValueByIndex(this.years, selectedIndex);
          const dates = this.getDates(year, this.selectedValue[1]);
          picker.refillColumn(2, this.generateData(1, dates, DEFAULT_MAP['d']));
          this.selectedValue.splice(index, 1, year);
        }
        // 改变月份的时候触发天数
        if (index === 1 && this.hasYear && this.hasMonth && this.hasDate) {
          console.log('月份:改变了时候触发天数');
          const month = this.getValueByIndex(this.months, selectedIndex);
          const dates = this.getDates(this.selectedValue[0], month);
          picker.refillColumn(2, this.generateData(1, dates, DEFAULT_MAP['d']));
          this.selectedValue.splice(index, 1, month);
        }
      });

      picker.on('picker.valuechange', (selectedVal, selectedIndex) => {

      });
    },
    /**
     * @desc 清空
     */
    clear() {
      this.cvalue = '';
      this.$emit('on-select', this.cvalue, '');
    },
    /**
     * @desc 初始化日期方法
     */
    init() {
      // const { format } = this;
      // this.formatSuffix = this.getFormat(format);
      // this.hasYear = /YYYY/.test(format);
      // this.hasMonth = /M+/.test(format);
      // this.hasDate = /D+/.test(format);
      // this.hasHour = /h/.test(format);
      // this.hasMinute = /m/.test(format);
      // this.hasSecond = /s/.test(format);
      this.initSelect();
    },
    initSelect() {
      const { currentDate } = this;
      const minYear = this.min.getFullYear();
      const maxYear = this.max.getFullYear();
      const map = {
        [DEFAULT_MAP['y']]: { f: () => this.generateData(minYear, maxYear, DEFAULT_MAP['y']), type: 'years' },
        [DEFAULT_MAP['M']]: { f: () => this.generateData(1, 12, DEFAULT_MAP['M']), type: 'months' },
        [DEFAULT_MAP['d']]: { f: () => this.generateData(1, this.getDates(currentDate[DEFAULT_MAP['y']], currentDate[DEFAULT_MAP['M']]), 'd'), type: 'dates' },
        [DEFAULT_MAP['h']]: { f: () => this.generateData(0, 23, DEFAULT_MAP['h']), type: 'hours' },
        [DEFAULT_MAP['m']]: { f: () => this.generateData(0, 59, DEFAULT_MAP['m']), type: 'minutes' },
        [DEFAULT_MAP['s']]: { f: () => this.generateData(0, 59, DEFAULT_MAP['s']), type: 'seconds' }
      };

      // 重置
      this.data = [];
      this.selectedIndex = [];
      this.selectedValue = [];
      let tempArr, tempObj;
      this.formatSuffix.map((item, i) => {
        tempObj = map[item.t];
        if (tempObj) {
          tempArr = tempObj['f']();
          this.data.push(tempArr);
          this[tempObj.type] = tempArr;
          this.selectedIndex.push(this.getIndexByValue(tempArr, currentDate[item.t]));
          this.selectedValue.push(currentDate[item.t]);
        }
      });
    },

    /**
     * @desc 重置当前日期
     * @param {Object} date date 日期对象
     */
    resetCurrentDate(date) {
      this.currentDate = {
        [DEFAULT_MAP['y']]: date.getFullYear(),
        [DEFAULT_MAP['M']]: date.getMonth() + 1,
        [DEFAULT_MAP['d']]: date.getDate(),
        [DEFAULT_MAP['h']]: date.getHours(),
        [DEFAULT_MAP['m']]: date.getMinutes(),
        [DEFAULT_MAP['s']]: date.getSeconds()
      };
    },
    /**
     * @desc 格式化当前日期 new Date 包装
     * @param {Array} selectedVal 选中的数组值
     * @return {Object} 返回 Date 对象
     */
    formatCurrentDate(selectedVal) {
      // 当前有年月日的时候
      if (this.hasYear && this.hasMonth && this.hasDate) {
        selectedVal[1] = selectedVal[1] - 1 < 0 ? 0 : selectedVal[1] - 1;

        // 当前只有年份
      } else if (this.hasYear && !this.hasMonth && !this.hasDate) {
        selectedVal[1] = 0;
        // selectedVal[2] = 1;
        // 当前只有年月
      } else if (this.hasYear && this.hasMonth && !this.hasDate) {
        selectedVal[1] = selectedVal[1] - 1 < 0 ? 0 : selectedVal[1] - 1;
      } else {
        // 如果没有年月日，只有时间，那就补全当天的年月日，来作为格式化
        const d = new Date();
        selectedVal = [...[d.getFullYear(), d.getMonth(), d.getDate()], ...selectedVal];
      }
      const date = new Date(...selectedVal);

      console.log('selectedVal :', ...selectedVal);
      // 重置当前选中的日期，用来显示的时候回选列的值
      this.resetCurrentDate(date);

      return date;
    },
    resetSelectIndex() {
      if (this.picker) {
        this.initSelect();
        this.picker.selectedIndex = this.selectedIndex;
      }
    },
    tapShowPicker() {
      this.picker.show(() => {
        this.initSelect();
        /*
         bug修复，如果当前默认日期是2019-6-1，它的天数只有30天，
         然后动态赋值value 2010-7-31，它的天数有31天，
         但是基础数据只有30天，就不会显示31天，需要进行重新赋值基础数据重置列的数据
        */
        // 如果有年月日的场景
        if (this.hasYear && this.hasMonth && this.hasDate) {
          /* 重置列的数据 begin */
          const year = this.currentDate[DEFAULT_MAP['y']];
          const dates = this.getDates(year, this.selectedValue[1]);
          this.picker.refillColumn(2, this.generateData(1, dates, DEFAULT_MAP['d']));
          /* 重置列的数据 end */
        }
        this.selectedIndex.length > 0 && this.selectedIndex.forEach((item, i) => {
          this.picker.scrollColumn(i, this.selectedIndex[i]);
        });
      });
      this.$refs['dtpInput'].blur();
    },
    /**
     * @desc 根据format返回 [{f:'YYYY',t:'y',suffix:'年'}]
     * f：对应的格式化
     * t：该对象的类型
     * suffix：后缀
     * '-','/',':' 这些连接符过滤掉
     * @param {format} 格式化字符串
     * @returns {Array} 返回数组对象
     */
    getFormat(format) {
      // 获取format的连接符
      const arr = format.replace(/Y+|M+|D+|H+|m+|s+/g, '$').split('$').map(item => item);
      arr.shift();
      let retArr = [];
      const map = {
        [DEFAULT_MAP['y']]: new RegExp('Y+'),
        [DEFAULT_MAP['M']]: new RegExp('M+'),
        [DEFAULT_MAP['d']]: new RegExp('D+'),
        [DEFAULT_MAP['h']]: new RegExp('H+'),
        [DEFAULT_MAP['m']]: new RegExp('m+'),
        [DEFAULT_MAP['s']]: new RegExp('s+')
      };
      Object.keys(map).map(item => {
        if (this.format.match(map[item]) !== null) {
          retArr.push({ f: this.format.match(map[item])[0], t: item });
        }
      });
      retArr = retArr.map((item, i) => ({ ...item, ...{ suffix: arr[i] } }));
      return retArr;
    },
    /**
     * @desc 按照后缀过滤规则生成数据,主要入口
     * @param {Number} min 最小值
     * @param {Number} max 最大值
     * @param {String} t 类型
     * @returns {Array} arr 生成后的数组
     */
    generateData(min, max, t) {
      const obj = this.formatSuffix.find(item => item.t === t);
      let last = '';
      if (obj) {
        const s = obj.suffix;
        // 过滤掉后缀条件
        if (s === '-' || s === '/' || s === ':') {
          last = '';
        } else {
          last = s;
        }
      }
      const arr = [];
      let str = '';
      for (let i = min; i <= max; i++) {
        str = this.zerofix(i, obj.f);
        arr.push({ text: `${str}${last || ''}`, value: i });
      }
      return arr;
    },
    /**
      * @desc 补0
      */
    zerofix(val, format) {
      const dd = t => ('0' + t).slice(-2);
      return DOUBLE_MAP.find(item => item === format) ? dd(val) : val;
    },
    /**
     * @desc 根据年份和月份获取每月的天数
     * @param {Number} year 年份
     * @param {Number} month 月份
     * @returns {Number} 总天数
     */
    getDates(year, month) {
      return new Date(year, month, 0).getDate();
    },
    /**
     * @desc 根据数组的值获取index
     * @param {Array} arr 数组
     * @param {String} value 值
     * @returns {Number} index值
     */
    getIndexByValue(arr, value) {
      let index = 0;
      for (let i = 0, len = arr.length; i < len; i++) {
        if (arr[i].value === value) {
          index = i;
          break;
        }
      }
      return index;
    },
    /**
     * @desc 根据数组的Index获取Value
     * @param {Array} arr 数组
     * @param {Number} index 索引
     * @returns {String} value值
     */
    getValueByIndex(arr, index) {
      const item = arr.find((item, i) => i === index);
      return item ? item.value : '';
    },
    /**
     * @desc 获取数据的时候根据fomat格式化数据
     * @param {Array} arr 日期 [2019,01,13,10,23,50]
     * @returns {Array} 返回格式化后的日期字符串
     */
    getValueByFormat(arr) {
      return arr.map((item, i) => {
        if (!this.formatSuffix[i]) { return; }
        return `${this.zerofix(item, this.formatSuffix[i].f)}${this.formatSuffix[i].suffix}`;
      }
      ).join('');
    },
    destroy() {
      const $el = this.picker.pickerEl;
      $el.parentNode && $el.parentNode.removeChild($el);
    }
  },
  destroyed() {
    this.destroy();
  },
  deactivated() {
    // 隐藏而不是销毁
    this.picker.pickerEl.style.display === 'block' && this.picker.hide();
  }
};
</script>


