<template>
    <div class="co-calendar" :id="id">
        <slot name="header">
          <div class="co-calendar-header" v-if="showButton">
            <div>
              <div class="coicon coicon-return" @click="reduceMonth()"></div>
              <div class="co-calendar-title" v-text="(month > 9 ? month : '0' + parseInt(month)) + '月'"></div>
              <div class="coicon coicon-enter" @click="addMonth()"></div>
            </div>
            <div>
              <div class="coicon coicon-return" @click="reduceYear()"></div>
              <div class="co-calendar-title" v-text="year + '年'"></div>
              <div class="coicon coicon-enter" @click="addYear()"></div>
            </div>
          </div>
        </slot>
        <div class="co-calendar-week-day">
            <div>日</div>
            <div>一</div>
            <div>二</div>
            <div>三</div>
            <div>四</div>
            <div>五</div>
            <div>六</div>
        </div>
        <ul class="co-calendar-month-day">
            <li v-for="row in rows" :class="row.extraClass">
                <div v-if="row.day" @click="clickFn(row)" :class="{'today': row.isToday, 'click':row.isClick, 'two-number': parseInt(row.day)>9 && parseInt(row.day)<20}">
                  <div v-text="row.day"></div>
                </div>
                <div v-else></div>
            </li>
        </ul>
    </div>
</template>

<script>
if (process.env.NODE_ENV === 'component') {
  require('CoUI/packages/font/style.css');
}

/**
 * co-calendar
 * @module components/calendar
 * @desc 日历组件
 * @param {String} [id] - 日历容器id
 * @param {Object} [clickDate] - 点击具体日期时触发的事件
 * @param {Object} [changeMY] - 点击增减月份时触发的事件，参数传递month、year当前值
 * @param {String} [yearAndMonth] - 设置当前组件的年月值'yyyy-MM'
 * @param {slot} - header,用于自定义日历头部
 * @param {slot} [reduceMonth] - 使用slot覆盖日历头部时，在父组件中使用this.$refs.【component】.reduceMonth调用子组件中操作月份递增的方法
 * @param {slot} [addMonth] - 使用slot覆盖日历头部时，在父组件中使用this.$refs.【component】.addMonth调用子组件中操作月份递减的方法
 * @param {Function} [handleClass] - this.$refs调用该方法，可在具体日期addClass或removeClass
 * @param {Boolean} [singleSelect] - 设置是否单选
 *
 * @example
 * <co-calendar></co-calendar>
 * <co-calendar :singleSelect="true" ref="calendar" @changeMY="updateYM" :yearAndMonth="'2018-03'" @clickDate="selectDate"></co-calendar>
 */

export default {
  name: 'co-calendar',
  props: {
    id: String,
    hideHeader: Boolean,
    yearAndMonth: String,
    singleSelect: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      rows: [], year: '', month: ''
    };
  },
  computed: {
    showButton() {
      return !this.hideHeader;
    }
  },
  methods: {
    refresh() {
      var me = this;
      // 确保月份格式正确
      var _month = this.month > 9 ? this.month : '0' + parseInt(this.month, 10);
      var options = {yearAndMonth: this.year + '-' + _month};
      var data = this.getTimeData(options);
      me.rows = data;
      me.$emit('changeMY', me.year, me.month);
    },
    /**
     * 时间格式化
     * @param date 日期字符串或对象
     * @param fmt 待转日期格式 eg: yyyy-MM-dd
     */
    format(date, format) {
      // return new Date(date).format(fmt);
      var o = {
        'M+': new Date(date).getMonth() + 1, // month
        'd+': new Date(date).getDate(), // day
        'h+': new Date(date).getHours(), // hour
        'm+': new Date(date).getMinutes(), // minute
        's+': new Date(date).getSeconds(), // second
        'q+': Math.floor((new Date(date).getMonth() + 3) / 3), // quarter
        'S': new Date(date).getMilliseconds() // millisecond
      };
      if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (new Date(date).getFullYear() + '').substr(4 - RegExp.$1.length));
      }
      for (var k in o) {
        if (new RegExp('(' + k + ')').test(format)) {
          format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
        }
      }
      return format;
    },
    /**
     * 构造日期块rows
     * @param data.yearAndMonth 指定月份yyyy-MM
     */
    getTimeData(data) {
      var thisTime;
      var yearAndMonth;
      var thisWeek;
      var nullBlock;
      var dayNum;
      var arr = [];
      var thisYearAndMonth;
      var obj;
      var yearMonth;
      thisTime = new Date();
      thisYearAndMonth = this.format(thisTime, 'yyyy-MM');
      yearAndMonth = data.yearAndMonth ? data.yearAndMonth : thisYearAndMonth;
      // 获取年月数据
      yearMonth = yearAndMonth.replace(/-/g, '/').split('/');
      if (yearMonth.length === 2) yearMonth.push('1');
      // 兼容IOS,使用 "/"
      yearMonth = new Date(new Date(yearMonth.join('/')).setDate(1));
      // 获取当前月份第一天是星期几
      thisWeek = yearMonth.getDay();
      // 获取需要空几个空的块  周日为第一周的第一天
      nullBlock = thisWeek - 1 >= 0 ? thisWeek : 0;
      // 获取当前月份有几天
      dayNum = new Date(yearMonth.getFullYear(), yearMonth.getMonth() + 1, 0).getDate();
      // 添加空的块
      for (var i = 0; i < nullBlock; i++) {
        arr.push({});
      }
      // TODO：yearAndMonth需要保证月份数字格式正确
      // 生成有日期数据的块
      for (var j = 1; j < dayNum + 1; j++) {
        obj = {day: j, isOver: true, isToday: false, isClick: false, haveData: false, extraClass: ''};
        if (thisYearAndMonth === yearAndMonth) { // 判断是否是当前月份
          if (thisTime.getDate() === j) {
            obj.isToday = true;
          } else if (thisTime.getDate() < j) {
            obj.isOver = false;
          }
        } else if (thisYearAndMonth < yearAndMonth) {
          obj.isOver = false;
        }
        arr.push(obj);
      }
      return arr;
    },
    // 点击某日期
    clickFn(data) {
      data.year = this.year;
      data.month = this.month;
      this.$emit('clickDate', data);
      if (this.singleSelect) {
        this.rows.forEach((a, i) => {
          if (data.day !== a.day) {
            a.isClick = false;
          }
        });
      }
      data.isClick = !data.isClick;
    },
    reduceMonth() {
      this.month = parseInt(this.month, 10);
      if (this.month === 1) {
        this.month = 12;
        this.year--;
      } else {
        this.month = parseInt(this.month, 10) - 1;
      }
      this.refresh();
    },
    addMonth() {
      this.month = parseInt(this.month, 10);
      if (this.month === 12) {
        this.month = 1;
        this.year++;
      } else {
        this.month = parseInt(this.month, 10) + 1;
      }
      this.refresh();
    },
    reduceYear() {
      this.year = parseInt(this.year, 10) - 1;
      this.refresh();
    },
    addYear() {
      this.year = parseInt(this.year, 10) + 1;
      this.refresh();
    },
    /**
     * 修改rows.extraClass
     * @param {String} opt.type 'before','after','between'
     * @param {Array} opt.date 供new Date()使用
     * @param {Array} opt.addClass 符合条件的日期增加某class
     * @param {Array} opt.removeClass 符合条件的日期删除某class
     */
    handleClass(opt) {
      var self = this;
      if (!opt.date) {
        return false;
      }
      if (typeof opt.date === 'string') {
        opt.date = [opt.date + ''];
      }
      if (opt.addClass && typeof opt.addClass !== 'object' || opt.removeClass && typeof opt.removeClass !== 'object') {
        console.log('参数有误');
        return false;
      }
      var timeStr1;// 时间字符串
      var timeStr2;// 时间字符串
      var startArr = [];
      var endArr = [];
      var currentY;
      var currentM;
      var startDate;
      var endDate;
      startArr = typeof opt.date[0] === 'string' ? opt.date[0].match(/\d+/g) : [];
      endArr = typeof opt.date[1] === 'string' ? opt.date[1].match(/\d+/g) : [];
      if (startArr.length !== 3 || opt.date[1] && endArr.length !== 3) {
        console.log('日期参数有误');
        return false;
      }
      // 格式化self.year、month
      currentY = self.format(self.year + '/' + self.month + '/' + '1', 'yyyy');
      currentM = self.format(self.year + '/' + self.month + '/' + '1', 'MM');
      startDate = opt.date[0].replace(/-/g, '/');
      endDate = opt.date[1] ? opt.date[1].replace(/-/g, '/') : null;
      // 格式化
      startArr = self.format(startDate, 'yyyy/MM/dd').split('/');
      endArr = opt.date[1] ? self.format(endDate, 'yyyy/MM/dd').split('/') : [];
      startDate = startArr[0] + '/' + startArr[1] + '/' + startArr[2];
      if (endArr.length) {
        endDate = endArr[0] + '/' + endArr[1] + '/' + endArr[2];
      }
      console.log(startArr, endArr, currentY + currentM);
      var compare = (startArr[0] + startArr[1]) - (currentY + currentM);
      // 修改class的日期
      var actionDates = [];
      // addClass/removeClass
      var editClassFn = function(arr) {
        self.rows.forEach((a, i) => {
          if (a.day < arr[0] || a.day > arr[1] || !a.day) {
            return false;
          }
          opt.addClass = opt.addClass ? opt.addClass : [];
          opt.removeClass = opt.removeClass ? opt.removeClass : [];
          opt.addClass.forEach((b) => {
            if (a.extraClass.indexOf(b) === -1) {
              a.extraClass += ' ' + b;
            }
          });
          opt.removeClass.forEach((c) => {
            if (a.extraClass.indexOf(c) !== -1) {
              a.extraClass = a.extraClass.replace(c, '').replace(/\s{2}/, ' ');
            }
          });
        });
      };
      switch (opt.type) {
        case 'before':
          if (!compare) {// 指定日期在当前月
            actionDates = self.rows.filter((a) => {
              return a.day <= startArr[2];
            });
            editClassFn([actionDates[0].day, actionDates[actionDates.length - 1].day]);
          } else if (compare > 0) {// 本月全部在指定日期之前
            actionDates = self.rows;
            editClassFn([actionDates[0].day, actionDates[actionDates.length - 1].day]);
          }
          break;
        case 'after':
          if (!compare) {// 指定日期在当前月
            actionDates = self.rows.filter((a) => {
              return a.day >= startArr[2];
            });
            editClassFn([actionDates[0].day, actionDates[actionDates.length - 1].day]);
          } else if (compare < 0) {// 本月全部在指定日期之后
            actionDates = self.rows;
            editClassFn([actionDates[0].day, actionDates[actionDates.length - 1].day]);
          }
          break;
        case 'between':
          if (!endArr.length) {
            endDate = startDate;
          }
          timeStr1 = Date.parse(new Date(startDate));
          timeStr2 = Date.parse(new Date(endDate));
          actionDates = self.rows.filter((a) => {
            if (!a.day) {
              return false;
            }
            var currentDate = Date.parse(new Date(currentY + '/' + currentM + '/' + a.day));
            return currentDate <= Math.max(timeStr1, timeStr2) && currentDate >= Math.min(timeStr1, timeStr2);
          });
          editClassFn([actionDates[0].day, actionDates[actionDates.length - 1].day]);
          break;
        default:
          break;
      }
    }
  },
  mounted() {
    // 初始化year、month
    var day = new Date();
    this.year = this.yearAndMonth !== undefined ? this.yearAndMonth.split('-')[0] : day.getFullYear();
    this.month = this.yearAndMonth !== undefined ? this.yearAndMonth.split('-')[1] : day.getMonth() + 1;
    // 兼容错误初始值
    this.year = parseInt(this.year, 10) || day.getFullYear();
    this.month = parseInt(this.month, 10) || day.getMonth() + 1;
    // 更新
    this.refresh();
  }
};
</script>

<style lang="css">
  @component-namespace co {
    @component calendar {
        background: #fff;
        padding-bottom: 5px;

        @descendent header {
            display: flex;
            display: -webkit-flex;
            justify-content: space-between;
            -webkit-justify-content: space-between;
            height: 40px;
            padding: 0px 10px;
            background-color: #e8e8e8;
            &> div{
                display: flex;
                display: -webkit-flex;
                justify-content: space-around;
                -webkit-justify-content: space-around;
            }
            .coicon-return, .coicon-enter {
              width: 30px;
              line-height: 40px;
              color: #717171;
              font-size: .75rem;
              text-align: center;
            }
        }
        @descendent title {
            line-height: 40px;
            font-size: 14px;
            letter-spacing: 0;
            margin: 0 15px;
        }
        @descendent week-day{
          display: flex;
          display: -webkit-flex;
          width: 100%;
          padding: 0px 10px;
          height: 40px;
          div{
            width: calc(100%/7);
            height: 40px;
            text-align: center;
            line-height: 40px;
            font-size: 15px;
            color: #717171;
          }
        }
        @descendent month-day{
          display: flex;
          display: -webkit-flex;
          width: 100%;
          padding: 0px 10px;
          flex-wrap: wrap;
          -webkit-flex-wrap: wrap;
          height: auto;
          overflow: auto;
          li{
            width: calc(100%/7);
            text-align: center;
            height: 30px;
            font-size: 15px;
            color: #717171;
            &> div{
              height: 28px;
              width: 28px;
              margin: 0 auto;
              position: relative;
              border: 1px solid transparent;
              border-radius: 50%;
              &.today{
                margin: 0 auto;
                background: #FF0000;
                border: 1px solid #FF0000;
                color: #ffffff;
              }
              &.today.two-number>div{
                margin-left: -2px;
              }
              &.click{
                border: 1px solid #FF0000;
              }
              /* 日期数字 */
              div{
                height: 28px;
                text-align: center;
                line-height: 28px;
              }
            }
          }
        }
    }
  }
</style>
