<template>
  <sv-picker
    :is-popup="true"
    :slots="slots"
    @cancel="cancel"
    @confirm="confirm"
    @sliding="handlePickerSliding"
    @close="handlePickerClose"
    ref="svPickerRef">
  </sv-picker>
</template>

<script type="es6">
  import svPicker from '../Picker'
  import '../../../scripts/utils'
  export default {
    name: 'sv-datetime-picker',
    components: {
      svPicker
    },
    data () {
      return {
        currentValue: '',
        slots: []
      }
    },
    props: {
      value: {
        type: [String, Object, Array],
        default: ''
      },
      type: {
        type: String,
        default: 'datetime'
      },
      format: {
        type: String,
        default: ''
      },
      formatYear: {
        type: String,
        default: 'yyyy',
        validator (val) {
          if (!val) {
            console.error('format-year属性值为空')
            return false
          }
          if (!val.startsWith('yyyy')) {
            console.error('format-year属性值没有以"yyyy"开头')
            return false
          }
          return true
        }
      },
      formatMonth: {
        type: String,
        default: 'MM',
        validator (val) {
          if (!val) {
            console.error('format-month属性值为空')
            return false
          }
          if (!val.startsWith('MM')) {
            console.error('format-month属性值没有以"MM"开头')
            return false
          }
          return true
        }
      },
      formatDate: {
        type: String,
        default: 'dd',
        validator (val) {
          if (!val) {
            console.error('format-date属性值为空')
            return false
          }
          if (!val.startsWith('dd')) {
            console.error('format-date属性值没有以"dd"开头')
            return false
          }
          return true
        }
      },
      formatHour: {
        type: String,
        default: 'hh',
        validator (val) {
          if (!val) {
            console.error('format-hour属性值为空')
            return false
          }
          if (!val.startsWith('hh')) {
            console.error('format-hour属性值没有以"hh"开头')
            return false
          }
          return true
        }
      },
      formatMinute: {
        type: String,
        default: 'mm',
        validator (val) {
          if (!val) {
            console.error('format-minute属性值为空')
            return false
          }
          if (!val.startsWith('mm')) {
            console.error('format-minute属性值没有以"mm"开头')
            return false
          }
          return true
        }
      },
      minYear: {
        type: Number,
        default () {
          return new Date().getFullYear() - 10
        }
      },
      maxYear: {
        type: Number,
        default () {
          return new Date().getFullYear() + 10
        }
      },
      hideYear: {
        type: Boolean,
        default: false
      },
      hideMinute: {
        type: Boolean,
        default: false
      }
    },
    computed: {
      slotIndexes () {
        let slotIndexes = {}
        if (this.type === 'datetime') {
          if (this.hideYear) {
            if (this.hideMinute) {
              slotIndexes = {
                month: 0,
                date: 1,
                hour: 2
              }
            } else {
              slotIndexes = {
                month: 0,
                date: 1,
                hour: 2,
                minute: 3
              }
            }
          } else {
            if (this.hideMinute) {
              slotIndexes = {
                year: 0,
                month: 1,
                date: 2,
                hour: 3
              }
            } else {
              slotIndexes = {
                year: 0,
                month: 1,
                date: 2,
                hour: 3,
                minute: 4
              }
            }
          }
        } else if (this.type === 'date') {
          slotIndexes = {
            year: 0,
            month: 1,
            date: 2
          }
        } else {
          slotIndexes = {
            hour: 0,
            minute: 1
          }
        }
        return slotIndexes
      }
    },
    watch: {
      value (val) {
        this.currentValue = val
      },
      currentValue (val) {
        this.$emit('input', val)
      }
    },
    methods: {
      initSlots () {
        let slots = []
        let length = 5
        switch (this.type) {
          case 'datetime':
            length = 5
            if (this.hideYear) {
              length--
            }
            if (this.hideMinute) {
              length--
            }
            break
          case 'date':
            length = 3
            break
          case 'time':
            length = 2
            break
        }

        for (let i = 0; i < length; i++) {
          slots.push({
            values: [],
            texts: []
          })
        }
        this.slots = slots
      },
      initSlotValues () {
        switch (this.type) {
          case 'datetime':
            !this.hideYear && this.setYears()
            this.setMonths()
            this.setDates()
            this.setHours()
            !this.hideMinute && this.setMinutes()
            // this.setSeconds()
            break
          case 'date':
            this.setYears()
            this.setMonths()
            this.setDates()
//      this.setSeconds()
            break
          case 'time':
            this.setHours()
            this.setMinutes()
//      this.setSeconds()
            break
        }
      },
      initSlotCheckedValues () {
        let currentDate = null
        if (this.currentValue) {
          if (typeof this.currentValue === 'string') {
            try {
              this.currentValue = this.currentValue.replace(/-/ig, '/')
              currentDate = new Date(this.currentValue)
            } catch (error) {
              console.error('v-model传入的字符串不合法，无法实例化为一个Date对象')
            }
          }else if (typeof this.currentValue === 'object' && this.currentValue instanceof Date) {
            currentDate = this.currentValue
          } else {
            console.error('v-model传入的值不合法，合法的值应该是：一个可以被实例化为Date对象的字符串或为一个Date对象')
            return
          }
        } else {
          currentDate = new Date()
        }
        let currentYear = currentDate.getFullYear()
        let activeYear = currentYear > this.minYear && currentYear <= this.maxYear ? currentYear : this.minYear


        switch (this.type) {
          case 'datetime':
            if (this.hideYear) {
              this.$refs.svPickerRef.setSlotCheckedValue(0, currentDate.getMonth() + 1)
              this.$refs.svPickerRef.setSlotCheckedValue(1, currentDate.getDate())
              this.$refs.svPickerRef.setSlotCheckedValue(2, currentDate.getHours())
              !this.hideMinute && this.$refs.svPickerRef.setSlotCheckedValue(3, currentDate.getMinutes())
            } else {
              this.$refs.svPickerRef.setSlotCheckedValue(0, activeYear)
              this.$refs.svPickerRef.setSlotCheckedValue(1, currentDate.getMonth() + 1)
              this.$refs.svPickerRef.setSlotCheckedValue(2, currentDate.getDate())
              this.$refs.svPickerRef.setSlotCheckedValue(3, currentDate.getHours())
              !this.hideMinute && this.$refs.svPickerRef.setSlotCheckedValue(4, currentDate.getMinutes())
            }
            break
          case 'date':
            this.$refs.svPickerRef.setSlotCheckedValue(0, activeYear)
            this.$refs.svPickerRef.setSlotCheckedValue(1, currentDate.getMonth() + 1)
            this.$refs.svPickerRef.setSlotCheckedValue(2, currentDate.getDate())
            break
          case 'time':
            this.$refs.svPickerRef.setSlotCheckedValue(0, currentDate.getHours())
            this.$refs.svPickerRef.setSlotCheckedValue(1, currentDate.getMinutes())
            break
        }
      },
      paddingLeftZero (str) {
        str = str + ''
        return `00${str}`.substr(str.length)
      },
      formatText (text = '', pattern = '') {
        const SIGN_REGEXP = /[yMdhsm]+/g

        if (typeof text === 'number') {
          text += ''
        }

        return pattern.replace(SIGN_REGEXP, match => {
          switch (match.charAt(0)) {
            case 'y':
              return text.substr(4 - match.length)
            case 'M':
              return text.substr(2 - match.length)
            case 'd':
              return text.substr(2 - match.length)
            case 'h':
              return text.substr(2 - match.length)
            case 'm':
              return text.substr(2 - match.length)
            case 's':
              return text.substr(2 - match.length)
          }
        })
      },
      cancel (event) {
        this.$emit('cancel', event)
      },
      confirm (values) {
        let [year, month, date, hour, minute] = [0, 0, 0, 0, 0, 0]
        let dateObj = new Date()
        switch (this.type) {
          case 'datetime':
            if (this.hideYear) {
              year = dateObj.getFullYear()
              month = values[0] - 1
              date = values[1]
              hour = values[2]
              minute = this.hideMinute ? 0 : values[3]
            } else {
              year = values[0]
              month = values[1] - 1
              date = values[2]
              hour = values[3]
              minute = this.hideMinute ? 0 : values[4]
            }
            break
          case 'date':
            year = values[0]
            month = values[1] - 1
            date = values[2]
            break
          case 'time':
            year = dateObj.getFullYear()
            month = dateObj.getMonth()
            date = dateObj.getDate()
            hour = values[0]
            minute = this.hideMinute ? 0 : values[1]
            break
        }
        dateObj = new Date(year, month, date, hour, minute)

        if (this.format) {
          dateObj = this.$Utils.DateUtil.format(dateObj, this.format)
        }
        this.$emit('confirm', dateObj)
        this.$emit('input', dateObj)
      },
      open () {
        this.$refs.svPickerRef.open()
        this.initSlotValues()
        window.setTimeout(() => {
          this.initSlotCheckedValues()
        } ,200)
      },
      setYears (minYear = this.minYear, maxYear = this.maxYear) {
        for (let i = 0; i <= maxYear - minYear; i++) {
          this.slots[0].texts.push(this.formatText(minYear + i, this.formatYear))
          this.slots[0].values.push(minYear + i)
        }

      },
      setMonths () {
        for (let i = 1; i <= 12; i++){
          this.slots[this.slotIndexes.month].texts.push(this.formatText(this.paddingLeftZero(i), this.formatMonth))
          this.slots[this.slotIndexes.month].values.push(i)
        }
      },
      /**
       * 设置 日
       * @param year 年份
       * @param month 月份
       * 每月的天数会受到闰月等的影响，所以需要传入年份和月份
       * 当然每月的天数也是不固定的，所以需要根据月份确定天数
       */
      setDates (year = new Date().getFullYear(), month = new Date().getMonth() + 1) {
        let [dateValues, dateTexts] = [[], []]
        let lastDate = new Date(year, window.parseInt(month), 0).getDate()
        for (let i = 1; i <= lastDate; i++){
          dateTexts.push(this.formatText(this.paddingLeftZero(i), this.formatDate))
          dateValues.push(i)
        }

        this.slots[this.slotIndexes.date].texts = dateTexts
        this.slots[this.slotIndexes.date].values = dateValues
      },
      getDates () {
        return this.slots[this.slotIndexes.date].values
      },
      setHours () {
        if (this.type === 'date') return

        for (let i = 0; i <= 23; i++){
          this.slots[this.slotIndexes.hour].texts.push(this.formatText(this.paddingLeftZero(i), this.formatHour))
          this.slots[this.slotIndexes.hour].values.push(i)
        }
      },
      setMinutes () {
        if (this.type === 'date') return

        for (let i = 0; i <= 59; i++){
          this.slots[this.slotIndexes.minute].texts.push(this.formatText(this.paddingLeftZero(i), this.formatMinute))
          this.slots[this.slotIndexes.minute].values.push(i)
        }
      },
      setSeconds () {
        if (this.type === 'date') return

        for (let i = 1; i <= 59; i++){
          this.slots[this.slotIndexes.second].texts.push(this.formatText(this.paddingLeftZero(i), this.formatSecond))
          this.slots[this.slotIndexes.second].values.push(i)
        }
      },
      getMaxDate (year, month) {
        return new Date(year, month, 0).getDate()
      },
      handlePickerClose () {
        this.initSlots()
      },
      handlePickerSliding (picker, slotIndex, isSlidingEnd) {
        // 时间类型时，滑动的时候不需要做任何处理
        if (this.type === 'time') return

        let currentYear = new Date().getFullYear()
        if (this.hideYear) {
          if (slotIndex === 0 && isSlidingEnd) {
            /*
             当前选择的月份最大日期小于当前选择的日期时
             日期选中最大日期
             */
            let previousCheckedDate = picker.getSlotCheckedValue(this.slotIndexes.date)
            let currentMaxDate = this.getMaxDate(currentYear, picker.getSlotCheckedValue(this.slotIndexes.month))
            if (previousCheckedDate > currentMaxDate) {
              picker.setSlotCheckedValue(1, currentMaxDate)
            }

            this.setDates(currentYear, picker.getSlotCheckedValue(this.slotIndexes.month))
          }
        } else {
          if (slotIndex === 1 && isSlidingEnd) {
            /*
             当前选择的月份最大日期小于当前选择的日期时
             日期选中最大日期
             */
            let previousCheckedDate = picker.getSlotCheckedValue(this.slotIndexes.date)
            let currentMaxDate = this.getMaxDate(picker.getSlotCheckedValue(this.slotIndexes.year), picker.getSlotCheckedValue(this.slotIndexes.month))
            if (previousCheckedDate > currentMaxDate) {
              picker.setSlotCheckedValue(2, currentMaxDate)
            }

            this.setDates(picker.getSlotCheckedValue(this.slotIndexes.year), picker.getSlotCheckedValue(this.slotIndexes.month))
          }
        }
      }
    },
    mounted () {
      this.initSlots()
      this.currentValue = this.value
    }
  }
</script>

<style lang="scss" rel="stylesheet/scss">
  @import "../../../styles/base";
  /*.sv-picker-group{*/
    /*display: flex;*/
    /*height: pxToRem(540);*/
    /*overflow:hidden;*/
  /*}*/
</style>
