/**
 * [UUID 生成UUID]
 */
class UUID {
  constructor() {
    this.id = this.createUUID();
  }

  /**
   * [valueOf 重写 valueOf 方法]
   * @return {String} [description]
   */
  valueOf() {
    return this.id;
  }

  /**
   * [valueOf 重写 toString 方法]
   * @return {String} [description]
   */
  toString() {
    return this.id;
  }

  /**
   * [createUUID 创建UUID]
   * @return {String} [description]
   */
  createUUID() {
    const dg = new Date(1582, 10, 15, 0, 0, 0, 0);
    const dc = new Date();
    const t = dc.getTime() - dg.getTime();
    const h = '';
    const tl = this.getIntegerBits(t, 0, 31);
    const tm = this.getIntegerBits(t, 32, 47);
    const thv = `${this.getIntegerBits(t, 48, 59)}1`; // version 1, security version is 2
    const csar = this.getIntegerBits(this.rand(4095), 0, 7);
    const csl = this.getIntegerBits(this.rand(4095), 0, 7);
    const n =
      this.getIntegerBits(this.rand(8191), 0, 7) +
      this.getIntegerBits(this.rand(8191), 8, 15) +
      this.getIntegerBits(this.rand(8191), 0, 7) +
      this.getIntegerBits(this.rand(8191), 8, 15) +
      this.getIntegerBits(this.rand(8191), 0, 15); // this last number is two octets long
    return tl + h + tm + h + thv + h + csar + csl + h + n;
  }

  /**
   * [getIntegerBits description]
   * @param  {[type]} val   [description]
   * @param  {[type]} start [description]
   * @param  {[type]} end   [description]
   * @return {[type]}       [description]
   */
  getIntegerBits(val, start, end) {
    const base16 = this.returnBase(val, 16);
    const quadArray = [];
    let quadString = '';
    let i = 0;
    for (i = 0; i < base16.length; i++) {
      quadArray.push(base16.substring(i, i + 1));
    }
    for (i = Math.floor(start / 4); i <= Math.floor(end / 4); i++) {
      if (!quadArray[i] || quadArray[i] === '') {
        quadString += '0';
      } else {
        quadString += quadArray[i];
      }
    }
    return quadString;
  }

  /**
   * [returnBase description]
   * @param  {[type]} number [description]
   * @param  {[type]} base   [description]
   * @return {[type]}        [description]
   */
  returnBase(number, base) {
    const convert = [
      '0',
      '1',
      '2',
      '3',
      '4',
      '5',
      '6',
      '7',
      '8',
      '9',
      'A',
      'B',
      'C',
      'D',
      'E',
      'F',
      'G',
      'H',
      'I',
      'J',
      'K',
      'L',
      'M',
      'N',
      'O',
      'P',
      'Q',
      'R',
      'S',
      'T',
      'U',
      'V',
      'W',
      'X',
      'Y',
      'Z',
    ];
    let output;
    if (number < base) {
      output = convert[number];
    } else {
      const MSD = `${Math.floor(number / base)}`;
      const LSD = number - MSD * base;
      if (MSD >= base) {
        output = this.returnBase(MSD, base) + convert[LSD];
      } else {
        output = convert[MSD] + convert[LSD];
      }
    }
    return output;
  }

  /**
   * [rand description]
   * @param  {[type]} max [description]
   * @return {[type]}     [description]
   */
  // eslint-disable-next-line class-methods-use-this
  rand(max) {
    return Math.floor(Math.random() * max);
  }
}

export default new UUID();
