/** 基本工具类 */

import StringExt from './StringExt.js'; StringExt();
import DateExt from './DateExt.js'; DateExt();
import global from '../config/Global.js';
import code from '../config/Code.js';
import key from '../config/Key.js';
import Crypto from './Crypto.js';
const crypto = Crypto();
// 公共map对象
const map = new Map();

export default class {

	/** 配置类 */
	get cfg() {
		return {
			/** 统一错误代码定义 */
			code,
			/** 加密用的Key */
			key,
			/** 全局常量 */
			global,
		};
	};

	/** 加解密类 */
	get crypto() { return crypto; };

	/** 公共Map缓存类 */
	get map() { return map; };

	/**
	 * 服务器时间
	 * @return {Date} 时间
	 */
	get serverTime() {
		let difTime = this.map.get('server_time') || 0;
		return new Date().incMillisecond(difTime);
	};
	/**
	 * 服务器时间
	 * @param {Date} date 服务器时间
	 */
	set serverTime(date) {
		if (this.isString(date)) {
			if (!Date.parse(date)) return;
			date = new Date(date);
		};

		let difTime = new Date().getTimeDiffer(date, 'ms');
		this.map.set('server_time', difTime);
	};

	/**
	 * 是否是方法
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isFn(any) {
		return Object.prototype.toString.call(any) === '[object Function]';
	};

	/**
	 * 是否是字符串
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isString(any) {
		return Object.prototype.toString.call(any) === '[object String]';
	};

	/**
	 * 是否是数字
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isNumber(any) {
		return Object.prototype.toString.call(any) === '[object Number]' && any.toString() !== 'NaN';
	};

	/**
	 * 是否是数字并且大于0
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isThan0(any) {
		return this.isNumber(any) && any > 0;
	};

	/**
	 * 是否是自然数
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isNatureInt(any) {
		return Number.isInteger(any) && (any >= 0);
	};

	/**
	 * 是否是正整数
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isPositiveInt(any) {
		return Number.isInteger(any) && (any > 0);
	};

	/**
	 * 是否是字符串数字
	 * @param {String} str 
	 * @return {Boolean}
	 * @todo 0001234和000.123均算为数字
	 */
	isStrNumber(str) {
		let regPos = /^\d+(\.\d+)?$/; //非负浮点数
		let regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; //负浮点数
		if (regPos.test(str) || regNeg.test(str)) {
			return true;
		} else {
			return false;
		};
	};

	/**
	 * 是否是日期
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isDate(any) {
		return Object.prototype.toString.call(any) === '[object Date]';
	};

	/**
	 * 是否是时间戳
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isTimespan(any) {
		if (!this.isThan0(Number(any))) return false;

		let minDate = new Date('1970-01-01 00:00:00');
		let maxDate = new Date('2100-01-01 00:00:00');
		let date = new Date(any);
		return date > minDate && date < maxDate;
	};

	/**
	 * 是否是对象
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isObject(any) {
		return any && (Object.prototype.toString.call(any) === '[object Object]' || typeof any == 'object');
	};

	/**
	 * 是否是数组
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isArray(any) {
		return Object.prototype.toString.call(any) === '[object Array]' || typeof any == 'array';
	};

	/**
	 * 是否是有效数组
	 * @param {any} obj 
	 * @return {Boolean}
	 */
	isEffectiveArray(obj) {
		return obj != undefined && obj != null && this.isArray(obj) && obj.length > 0;
	};

	/**
	 * 是否是bool
	 * @param {any} any 
	 * @return {Boolean}
	 */
	isBoolean(any) {
		return Object.prototype.toString.call(any) === '[object Boolean]';
	};

	/**
	 * 深拷贝
	 * @param {any} value 
	 * @return {any}
	 */
	depthClone(value) {
		return this.jsonParse(this.jsonString(value));
	};

	/**
	 * json对象或数组转成字符串
	 * @param {JSON} obj 对象或数组
	 * @return {JSON|Array|String|Number}
	 */
	jsonString(obj) {
		// 返回空
		if (!obj && obj != 0) return obj;
		// 返回字符串
		if (!this.isObject(obj) && !this.isArray(obj)) return obj;

		let str;
		try {
			str = JSON.stringify(obj);
		} catch (err) {
			str = obj;
		};

		return str;
	};

	/**
	 * 生成指定位数随机字符串
	 * @param {Number} len 随机字符的位数
	 * @param {Number} type 1=精确到毫秒时间戳（13位） 2=精确到秒时间戳（10位） null=无时间戳
	 * @param {String} str 字符串集（null则从ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678随机选取）
	 * @return {String}
	 */
	getRandomStr(len = 32, type, str) {
		if (this.isString(type) && !str) {
			str = type;
			type = null;
		};

		let chars = str || 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
		let maxPos = chars.length;
		let s = '';
		for (let i = 0; i < len; i++) {
			s += chars.charAt(Math.floor(Math.random() * maxPos));
		};

		if (type == 1) {
			s += this.serverTime.getTime();
		};

		if (type == 2) {
			s += Math.round(this.serverTime.getTime() / 1000);
		};

		return s;
	};

	/**
	 * json格式的字符串转成对象
	 * @param {String|Number|Boolean|Array} any 字符串
	 * @return {JSON|Array|String|Number}
	 */
	jsonParse(any) {
		if (!any && any != 0) return any;
		if (this.isObject(any) || this.isArray(any)) return any;
		if (this.isStrNumber(any) && !Number.isSafeInteger(Number(any))) return any;

		let obj;
		try {
			obj = JSON.parse(any);
		} catch (err) {
			obj = any;
		};

		return obj;
	};

	/**
	 * 对象转为URL参数
	 * @param {JSON} obj 
	 * @return {String} 如：a=1&b=2&c='a'
	 */
	objToURLParam(obj) {
		let result = '';
		if (!this.isObject(obj)) return result;

		for (const key in obj) {
			if (!obj[key] && obj[key] != 0) continue;

			if (result != '') result += '&';
			result += `${key}=${obj[key]}`;
		};

		return result;
	};

	/**
	 * 通用数据加密
	 * @param {String|JSON} data 数据
	 * @param {Boolean} needTime 需要增加时间
	 */
	enData(data, needTime = true) {
		if (!data && data != 0) return data;
		if (needTime && this.isObject(data)) data.serverTime = new Date();
		return `Xm6Ek7ebm0${this.crypto.encrypt(this.jsonString(data), this.cfg.key.PRIVATE_KEY, 128)}` || '';
	};

	/**
	 * 通用数据解密
	 * @param {String} data 数据
	 */
	deData(data) {
		if (!data && data != 0) return data;
		if (!String(data).isEnStr()) return this.jsonParse(data);
		if (data.slice(0, 10) === 'Xm6Ek7ebm0') {
			data = data.slice(10);
			return this.jsonParse(this.crypto.decrypt(data, this.cfg.key.PRIVATE_KEY, 128)) || {};
		};
		return this.jsonParse(this.crypto.decrypt(data, this.cfg.key.PRIVATE_KEY, 128));
	};
}