// 深拷贝，为了解决循环引用和共同引用的问题，引入了WeakMap，又因为引入WeakMap可能会导致被拷贝对象被挂上【作为WeakMap的探针的】匿名函数（是pollyfill的行为吧？），所以不会拷贝非根元素的匿名函数。
function deepClone(target, hash = new WeakMap()) {
  // 定义一个变量
  let result = null
  // 如果当前需要深拷贝的是一个对象的话
  if (typeof target === 'object') {
    if (hash.has(target)) { // 如果是循环引用
      result = hash.get(target)
    } else if (Array.isArray(target)) { // 如果是一个数组的话
      result = [] // 将result赋值为一个数组，并且执行遍历
      hash.set(target, result)
      for (let i in target) {
        if (!(typeof(target[i]) === 'function' && !target.name)) {
          // 递归克隆数组中的每一项
          result.push(deepClone(target[i], hash))
        }
      }
      // 判断如果当前的值是null的话；直接赋值为null
    } else if (target === null) {
      result = null
      // 判断如果当前的值是一个RegExp对象的话，直接赋值
    } else if (target.constructor === RegExp) {
      result = target
    } else {
      // 否则是普通对象，直接for in循环，递归赋值对象的所有值
      result = {}
      hash.set(target, result)
      for (let i in target) {
        if (!(typeof(target[i]) === 'function' && !target.name)) {
          result[i] = deepClone(target[i], hash)
        }
      }
    }
  } else if (typeof target === 'function') {
    result = target
  } else { // 如果不是对象也不是函数，直接赋值
    result = target
  }
  // 返回最终结果
  return result
}

export default {
  /**
 * 返回一个自带消抖效果的函数，用res表示。
 *
 * fn: 需要被消抖的函数
 * delay: 消抖时长
 * isImmediateCall: 是否在一组操作中的第一次调用时立即执行fn
 * isRememberLastCall：是否在一组中最后一次调用后等delay时长再执行fn
 */
  debounce(fn, delay = 250, isImmediateCall = true, isRememberLastCall = true) {
    console.assert(isImmediateCall || isRememberLastCall, 'isImmediateCall 和 isRememberLastCall 至少应有一个是true，否则没有意义！')
    let timer = null
    // 上次调用的时刻
    let lastCallTime = 0

    if (isImmediateCall && !isRememberLastCall) {
      return function (...args) {
        const currentTime = Date.now()
        if (currentTime - lastCallTime >= delay) {
          fn.apply(this, args)
        }
        lastCallTime = currentTime
      }
    } else if (!isImmediateCall && isRememberLastCall) {
      return function (...args) {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn.apply(this, args)
        }, delay)
      }
    } else if (isImmediateCall && isRememberLastCall) {
      return function (...args) {
        const currentTime = Date.now()
        if (currentTime - lastCallTime >= delay) { // 一组操作中的第一次
          fn.apply(this, args)
          lastCallTime = currentTime
          return
        } else { // 一组中的后续调用
          if (timer) { // 在此之前存在中间调用
            lastCallTime = currentTime
            clearTimeout(timer)
          }
          timer = setTimeout(() => {
            fn.apply(this, args)
            lastCallTime = 0
            timer = null
          }, delay)
        }
      }
    } else {
      console.error('不应该执行到这里！')
    }
  },
  throttle(fn, interval = 250) {
    let lastRunTime = 0

    return function (...args) {
      let elapsedTime = Date.now() - lastRunTime
      if (elapsedTime < interval) {
        return null
      }

      let context = this
      lastRunTime = Date.now()
      return fn.apply(context, args)
    }
  },
  copyToClipBoard(content) {
    let tempDom = document.createElement('input')
    tempDom.setAttribute('value', content)
    document.body.appendChild(tempDom)
    tempDom.select()
    tempDom.setSelectionRange(0, 9999)
    document.execCommand('Copy')
    document.body.removeChild(tempDom)
  },
  randomWord(randomFlag, min, max) {
    //随机字符串
    var str = "",
      range = min,
      arr = [
        "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",
        "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",
      ]

    if (randomFlag) {
      // 随机长度
      range = Math.round(Math.random() * (max - min)) + min
    }
    for (var i = 0; i < range; i++) {
      var pos = Math.round(Math.random() * (arr.length - 1))
      str += arr[pos]
    }
    return str
  },
  unique(arr) {
    let map = new Map()
    let array = new Array() // 数组用于返回结果
    for (let i = 0; i < arr.length; i++) {
      if (map.has(arr[i])) {
        // 如果有该key值
        map.set(arr[i], true)
      } else {
        map.set(arr[i], false) // 如果没有该key值
        array.push(arr[i])
      }
    }
    return array
  },
  deepClone,
}

/**
 * 如果想让注册的回调只调用一次就自动注销，在注册的回调中执行注销即可。
 */
export class MessageCenter {
  constructor() {
    this._recorder = {}
  }

  logInvalidParam() {
    console.error('MessageCenter: invalid parameter.')
  }

  subscribe(message, callback) {
    if (typeof (message) !== 'string' || typeof (callback) !== 'function') {
      this.logInvalidParam()
      return
    }

    if (!Object.prototype.hasOwnProperty.call(this._recorder, message)) {
      this._recorder[message] = []
    }
    this._recorder[message].push(callback)
  }

  unsubscribe(message, callback) {
    if (typeof (message) !== 'string' || typeof (callback) !== 'function') {
      this.logInvalidParam()
      return
    }

    if (!Object.prototype.hasOwnProperty.call(this._recorder, message)) {
      const idx = this._recorder[message].indexOf(callback)
      if (idx !== -1) {
        this._recorder[message].splice(idx, 1)
      }
    }
  }

  publish(message, param) {
    if (Object.prototype.hasOwnProperty.call(this._recorder, message)) {
      this._recorder[message].forEach((callback) => {
        callback(param)
      })
    }
  }
}