/**
 * 工具类
 */


/**
 * 格式化日期格式 (用于兼容ios Date对象)
 */
export const formatDate = (time) => {
  // 将xxxx-xx-xx的时间格式，转换为 xxxx/xx/xx的格式 
  return time.replace(/\-/g, "/");
}

/**
 * 对象转URL
 * @param {object} obj
 */
export const urlEncode = (obj = {}) => {
  const result = []
  for (const key in obj) {
    const item = obj[key]
    if (!item) {
      continue
    }
    if (isArray(item)) {
      item.forEach(val => {
        result.push(key + '=' + val)
      })
    } else {
      result.push(key + '=' + item)
    }
  }
  return result.join('&')
}

/**
 * 遍历对象
 */
export const objForEach = (obj, callback) => {
  Object.keys(obj).forEach((key) => {
    callback(obj[key], key)
  });
}

/**
 * 是否在数组内
 */
export const inArray = (search, array) => {
  for (var i in array) {
    if (array[i] == search) return true
  }
  return false
}

/**
 * 对Date的扩展，将 Date 转化为指定格式的String
 * 月(Y)、月(m)、日(d)、小时(H)、分(M)、秒(S) 可以用 1-2 个占位符，
 * 例子：
 * dateFormat('YYYY-mm-dd HH:MM:SS', new Date()) ==> 2020-01-01 08:00:00
 */
export const dateFormat = (fmt, date) => {
  const opt = {
    "Y+": date.getFullYear().toString(), // 年
    "m+": (date.getMonth() + 1).toString(), // 月
    "d+": date.getDate().toString(), // 日
    "H+": date.getHours().toString(), // 时
    "M+": date.getMinutes().toString(), // 分
    "S+": date.getSeconds().toString() // 秒
    // 有其他格式化字符需求可以继续添加，必须转化成字符串
  };
  let ret
  for (let k in opt) {
    ret = new RegExp("(" + k + ")").exec(fmt)
    if (ret) {
      fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
    };
  };
  return fmt
}

/**
 * 判断是否为空对象
 * @param {*} object 源对象
 */
export const isEmptyObject = (object) => {
  return Object.keys(object).length === 0
}

/**
 * 判断是否为对象
 * @param {*} object
 */
export const isObject = (object) => {
  return Object.prototype.toString.call(object) === '[object Object]'
}

/**
 * 判断是否为数组
 * @param {*} array
 */
export const isArray = (array) => {
  return Object.prototype.toString.call(array) === '[object Array]'
}

/**
 * 判断是否为空
 * @param {*} object 源对象
 */
export const isEmpty = (value) => {
  if (isArray(value)) {
    return value.length === 0
  }
  if (isObject(value)) {
    return isEmptyObject(value)
  }
  return !value
}

/**
 * 对象深拷贝
 * @param {*} obj 源对象
 */
export const cloneObj = (obj) => {
  if (typeof obj !== 'object') {
    return;
  }
  let newObj = obj.constructor === Array ? [] : {};
  for (let i in obj) {
    newObj[i] = typeof obj[i] === 'object' ? cloneObj(obj[i]) : obj[i];
  }
  return newObj
}

/**
 * 拷贝数据深度拷贝（和cloneObj的区别在于该方法只拷贝数据，不拷贝方法）
 */
export const cloneData = (obj) => {
  return obj == null ? null : JSON.parse(JSON.stringify(obj))
}

// 节流函数
// 思路： 第一次先设定一个变量true，
// 第二次执行这个函数时，会判断变量是否true，
// 是则返回。当第一次的定时器执行完函数最后会设定变量为flase。
// 那么下次判断变量时则为flase，函数会依次运行。
export function throttle(fn, delay = 100) {
  // 首先设定一个变量，在没有执行我们的定时器时为null
  var timer = null
  return function() {
    // 当我们发现这个定时器存在时，则表示定时器已经在运行中，需要返回
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, arguments)
      timer = null
    }, delay)
  }
}

// 防抖函数
// 首次运行时把定时器赋值给一个变量， 第二次执行时，
// 如果间隔没超过定时器设定的时间则会清除掉定时器，
// 重新设定定时器， 依次反复， 当我们停止下来时，
// 没有执行清除定时器， 超过一定时间后触发回调函数。
// 参考文档：https://segmentfault.com/q/1010000021145192
export function debounce(fn, delay) {
  let timer
  return function() {
    const that = this
    const _args = arguments // 存一下传入的参数
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(function() {
      fn.apply(that, _args)
    }, delay)
  }
}


/**
 * 数组交集
 * @param {Array} 数组1
 * @param {Array} 数组2
 * @return {Array}
 */
export const arrayIntersect = (array1, array2) => {
  return array1.filter(val => array2.indexOf(val) > -1)
}

/**
 * 从数组中查找指定key为指定value的对象的下标
 */
export const findIndex = (array, key, value) => {
	for(let i = 0; i < array.length; i++) {
		if (value + '' == array[i][key] + '') {//为了避免ID数字丢失精度，这里都转成字符串匹配
			return i
		}
	}
	return -1
}

/**
 * 从数组中查找指定key为指定value的对象
 */
export const findInArray = (array, key, value) => {
	for(let i = 0; i < array.length; i++) {
		let item = array[i]
		if (value == item[key]) {
			return item
		}
	}
	return null
}

/**
 * 从数组中查找指定key为指定value的对象的下标
 */
export const getNewArray = (oldArray, oldKeys, newKeys) => {
	let newArray = []
	for(let i = 0; i < oldArray.length; i++) {
		let oldItem = oldArray[i]
		let newItem = {}
		for (let j = 0; j < oldKeys.length; j++) {
			let oldKey = oldKeys[j]
			let newKey = newKeys[j]
			newItem[newKey] = oldItem[oldKey]
		}
		newArray.push(newItem)
	}
	return newArray
}

/** 将时间字符串转为Date对象 */
export const dateParse = (dateStr) => {
	return new Date(dateStr.replace(/\-/g, "/"))
}

/** 获取当前时间 */
export const now = () => {
	return dateFormat('YYYY-mm-dd HH:MM:SS', new Date())
}

/** 获取当前日期 */
export const nowDate = () => {
	return dateFormat('YYYY-mm-dd', new Date())
}

/** 获取指定日期是周几 */
export const weekDateCN = (dateStr) => {
	let date = dateStr ? new Date(dateStr.replace(/\-/g, "/")) : new Date()
	let day = date.getDay()
	let weeks = ['周日','周一','周二','周三','周四','周五','周六']
	return weeks[day]
}

/** 获取指定日期的后几天，如果负数则为前几天 */
export const nextDay = (dateStr, num) => {
	let date = dateStr ? new Date(dateStr.replace(/\-/g, "/")) : new Date()
	date.setDate(date.getDate() + num)
	return dateFormat('YYYY-mm-dd', date)
}

/** 获取指定日期的后几月，如果负数则为前几月 */
export const nextMonth = (dateStr, num) => {
	let date = dateStr ? new Date(dateStr.replace(/\-/g, "/")) : new Date()
	date.setMonth(date.getMonth() + num)
	return dateFormat('YYYY-mm-dd', date)
}

/** 获取指定月份的最后一天 */
export const getMonthLastDay = (dateStr) => {
	let date = dateStr ? new Date(dateStr.replace(/\-/g, "/")) : new Date()
	date.setMonth(date.getMonth() + 1)//先调到下个月
	date.setDate(0)//下个月的0日，就是本月的最后一日
	return dateFormat('YYYY-mm-dd', date)
}

/** 获取指定日期的后几年，如果负数则为前几年 */
export const nextYear = (dateStr, num) => {
	return nextMonth(dateStr, num * 12)
}

/** 获取两个日期间隔的天数，包括两个日期在内 */
export const dayDiff = (startDate, endDate) => {
	let start = new Date(startDate.replace(/\-/g, "/"))
	let end = new Date(endDate.replace(/\-/g, "/"))
	return Math.abs(Math.floor((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))) + 1
}

/** 获取两个时间间隔的分钟数，秒数四舍五入 */
export const minuteDiff = (startTime, endTime) => {
	let start = new Date(startTime.replace(/\-/g, "/"))
	let end = new Date(endTime.replace(/\-/g, "/"))
	let rs = Math.abs(Math.round((end.getTime() - start.getTime()) / (1000 * 60)))
	console.log('s=' + start.getTime() + ';e=' + end.getTime() + ';d=' + rs)
	return rs
}

const _charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789'
function RandomIndex(min, max, i) {
	let index = Math.floor(Math.random() * (max - min + 1) + min)
	let numStart = _charStr.length - 10
	//如果字符串第一位是数字，则递归获取
	if (i == 0 && index >= numStart) {
		index = RandomIndex(min, max, i)
	}
	return index
}

export const getRandomString = (len) => {
	let min = 0
	let max = _charStr.length - 1
	let _str = ''
	len = len || 10
	for (let i = 0; i < len; i++) {
		let index = RandomIndex(min, max, i)
		_str += _charStr[index]
	}
	return _str
}

export const m2hm = (all) => {//分钟显示成几小时几分
	if (all < 60) {//1小时以内
		return all + 'm'
	} else {
		let h = Math.floor(all / 60) //几小时
		let m = all % 60 //剩余几分
		if (m == 0) {//整点
			return h + 'h'
		} else{
			return h + 'h·' + m + 'm'
		}
	}
}

//获取随机字符串
export const randomString = (len) => {
	len = len || 32
	let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz'    /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
	let maxPos = chars.length
	let pwd = ''
	for (let i = 0; i < len; i++) {
		pwd += chars.charAt(Math.floor(Math.random() * maxPos))
	}
	return pwd
}

//响应双击事件
let lastClickTimeoutFn = null //timeout的id
let lastClickTimeStamp = 0 //上一次点击时间戳
export const clickEvent = (e, singleClickFn, doubleClickFn) => {
	let currentTime = e.timeStamp //当前点击时间
	if (currentTime - lastClickTimeStamp < 300) {//两次点击间隔小于300毫秒，则认为是双击
		clearTimeout(lastClickTimeoutFn) //先取消单击事件
		doubleClickFn() //再执行双击事件
	} else {//单击事件要延迟300毫秒执行，为了防止后续再次点击
		if (singleClickFn) {//如果有单击事件的话
			lastClickTimeoutFn = setTimeout(singleClickFn, 300)
		}
	}
	lastClickTimeStamp = currentTime //记录当前时间
}