'use strict';

function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }

var isFun = _interopDefault(require('./isFun'));
var isObj = _interopDefault(require('./isObj'));
var isNum = _interopDefault(require('./isNum'));

/**
 * 倒计时类，可用来创建倒计时对象
 * @param {number} time 倒计时时间
 * @param {Object} options 倒计时参数
 * @param {Function} tickCallback 倒计时步进回调
 *
 * @example
 * import { CountDown } from '@bilibili/b-utils';
 *
 * 1. 创建并自动开启一个24小时的倒计时
 * new CountDown(864e5, cd => console.log(cd.hhmmss));
 *
 * 2. 创建并自动开启一个60s的倒计时
 * new CountDown(10000, { cdType: 's' }, cd => console.log(cd.s));
 *
 * 3. 创建一个可以显示毫秒的定时器
 * new CountDown(10000, { interval: 50 }, ({ss, SSS}) => {
 *   console.log(`${ss} ${SSS}`);
 * });
 *
 * 4. 创建一个60s倒计时，手动开始和结束
 * const cd = new CountDown(60000, { autoStart: false }, () => {
 *   console.log(cd);
 * });
 * // A moment later
 * cd.start();
 *
 * 5. 创建一个倒计时，自定义参数再启动
 * const cd = new CountDown();
 * cd.time = 10000;
 * cd.cdType = 's';
 * cd.onTick = cd => console.log(cd);
 * cd.start();
 * // A moment later
 * cd.stop();
 * // A moment later
 * cd.start();
 * // Destory The countdown
 * cd.destory();
 */
function CountDown(time, options, tickCallback) {
  var _this3 = this;

  if (isFun(time)) {
    tickCallback = time;
  } else if (isFun(options)) {
    tickCallback = options;
  }

  options = isObj(options) ? options : {};
  this.options = options;

  // 初始时间
  this.initTime = isNum(time) ? time : null;

  // 剩余时间
  this.restTime = this.time;

  // 定时间隔
  this.interval = isNum(options.interval) ? options.interval : 1000;

  // 是否自动启动倒计时
  this.autoStart = options.autoStart !== false;

  // 倒计时类型，d: 到天，h: 到小时，m: 到分钟，s: 到秒，S: 到毫秒，默认：'h'.
  this.cdType = ['d', 'h', 'm', 's', 'S'].indexOf(options.cdType) > -1 ? options.cdType : 'h';
  this.running = false;
  this.destoryed = false;
  this.completed = false;
  this.tickTimes = 0;
  this.restDays = null;
  this.restHours = null;
  this.restMinuts = null;
  this.restSeconds = null;
  this.restMillisecond = null;
  this.d = null;
  this.h = null;
  this.m = null;
  this.s = null;
  this.S = null;
  this.dd = '--';
  this.hh = '--';
  this.mm = '--';
  this.ss = '--';
  this.SSS = '---';
  this.ms = '-:-';
  this.hms = '-:-:-';
  this.mmss = '--:--';
  this.hhmmss = '--:--:--';
  this.timerId = null;

  /**
   * 开始倒计时
   */
  this.start = function () {
    var _this = this;

    if (this.destoryed) return;
    this.running = true;

    if (this.interval >= 0 && this.restTime >= this.interval) {
      this.completed = false;
      clearInterval(this.timerId);
      this.timerId = setInterval(function () {
        return _this.tick();
      }, this.interval);
    } else {
      this.setComplete();
    }
  };

  /**
   * 暂停倒计时
   */
  this.stop = function () {
    clearInterval(this.timerId);
    this.running = false;
  };

  /**
   * 销毁倒计时
   */
  this.destory = function () {
    clearInterval(this.timerId);
    this.running = false;
    this.destoryed = true;
  };

  /**
   * 定时器结束
   */
  this.setComplete = function () {
    clearInterval(this.timerId);
    this.running = false;
    this.completed = true;
  };

  /**
   * 定时步进
   */
  this.tick = function () {
    this.tickTimes++;

    if (this.restTime > this.interval) {
      this.restTime -= this.interval;
      this.setValue();
    } else {
      this.restTime = 0;
      this.setValue();
      this.setComplete();
    }

    if (isFun(this.onTick)) this.onTick(this);
    if (isFun(tickCallback)) tickCallback(this);
  };

  /**
   * 设置定时器的值
   */
  this.setValue = function () {
    var _this2 = this;

    if (!this.restTime || this.restTime < 0) this.restTime = 0;
    this.restDays = Math.floor(this.restTime / 864e5);
    this.restHours = Math.floor(this.restTime / 36e5);
    this.restMinuts = Math.floor(this.restTime / 6e4);
    this.restSeconds = Math.floor(this.restTime / 1000);
    this.restMillisecond = this.restTime;

    if (this.cdType === 'd') {
      var restSeconds = Math.floor(this.restTime % 864e5 / 1000);
      this.d = this.restDays;
      this.h = Math.floor(restSeconds / 3600);
      this.m = Math.floor(restSeconds % 3600 / 60);
      this.s = Math.floor(restSeconds % 60);
    } else if (this.cdType === 'h') {
      this.d = 0;
      this.h = this.restHours;
      this.m = Math.floor(this.restSeconds % 3600 / 60);
      this.s = Math.floor(this.restSeconds % 60);
    } else if (this.cdType === 'm') {
      this.d = this.h = 0;
      this.m = this.restMinuts;
      this.s = Math.floor(this.restSeconds % 60);
    } else if (this.cdType === 's') {
      this.d = this.h = this.m = 0;
      this.s = this.restSeconds;
    } else if (this.cdType === 'S') {
      this.d = this.h = this.m = this.s = 0;
      this.S = this.restMillisecond;
    }

    if (this.cdType !== 'S') {
      this.S = Math.floor(this.restTime % 1000);
    }

    var dhmsS = 'dhmsS';
    dhmsS.substr(dhmsS.indexOf(this.cdType)).split('').forEach(function (item) {
      var itemStr = String(_this2[item]);
      var itemLen = 2,
          itemTpl = item + item;

      if (item === 'S') {
        itemLen++;
        itemTpl += item;
      }

      _this2[itemTpl] = itemStr.length < itemLen ? ('00' + itemStr).substr(-itemLen) : itemStr;
    });
    var co = ':';
    this.ms = this.m + co + this.s;
    this.hms = this.h + co + this.m + co + this.s;
    this.mmss = this.mm + co + this.ss;
    this.hhmmss = this.hh + co + this.mm + co + this.ss;
    ['dd', 'hh', 'mm', 'ss', 'ms', 'hms', 'mmss', 'hhmmss'].forEach(function (item) {
      _this2[item] = _this2[item].replace(/-/g, '0');
    });
  };

  /**
   * 判断是否自动开启
   */
  if (isNum(this.time)) {
    this.setValue();

    if (this.autoStart) {
      setTimeout(function () {
        return _this3.start();
      });
    }
  }
}

/**
 * 手动设置开始时间
 */
Object.defineProperty(CountDown.prototype, 'time', {
  get: function get() {
    return this.initTime;
  },
  set: function set(val) {
    if (isNum(val)) {
      this.initTime = val;
      this.restTime = val;
    }
  }
});

module.exports = CountDown;
