

var Tools = function(){
	/**
	  * 计时组件封装
	  * @param: {Object}
	  *	@example1: var timerA = new Tools.timerLoop(3000, 'timerA');
				timerA(function(){});
				timerA.stop();
				timerA.start();
				timerA.setTime();
				timerA.clear();
	  * @return: 
	  * @author: Kimber
	  * @createtime: 2021/10/28
	  */
	var timerLoop = function(timer, name){
		var defaultTiem = 5000;
		var Cache = {timer:timer || defaultTiem, name:name};
		var layer = function(timer){
			Cache.timer = timer;
			Cache.layer = this;
			this.start = () => {
				clearTimeout(Cache.timerPointer);
				Cache.timerPointer = setInterval(Cache.fn.bind(this), Cache.timer);
			};
			var interval = function(fn, timer, name){
				if(typeof fn === 'function'){
					Cache.name = name;
					timer && (Cache.timer = timer);
					Cache.fn = fn;
					Cache.layer.start()
				};
			};
			interval.__proto__ = this.__proto__;
			return interval
		}; layer.prototype = {
			stop: function(){
				clearInterval(Cache.timerPointer);
			},
			start: function(){
				Cache.fn && Cache.layer.start()
			},
			setTime: function(timer){
				timer && (Cache.timer = timer);
				Cache.fn && Cache.layer.start()
			},
			clear: function(){
				clearInterval(Cache.timerPointer);
				Cache = {timer:defaultTiem};
			},
		};
		return new layer(timer)
	};

	// 日期时间工具
	var Dates = function(){
		/* 
			Tools.Dates.format('yyyy-MM-dd EE HH:mm:ss')
			Dates.format.call(new Date(), 'yyyy-MM-dd EE HH:mm:ss')
		*/
		var format = function(fmt){
			var Date_ = this.getDate ? this : new Date();
			var o = {           
			"M+" : Date_.getMonth()+1, //月份           
			"d+" : Date_.getDate(), //日           
			"h+" : Date_.getHours()%12 == 0 ? 12 : Date_.getHours()%12, //小时           
			"H+" : Date_.getHours(), //小时           
			"m+" : Date_.getMinutes(), //分           
			"s+" : Date_.getSeconds(), //秒           
			"q+" : Math.floor((Date_.getMonth()+3)/3), //季度           
			"S" : Date_.getMilliseconds() //毫秒           
			};           
			var week = {           
			"0" : "\u65e5",           
			"1" : "\u4e00",           
			"2" : "\u4e8c",           
			"3" : "\u4e09",           
			"4" : "\u56db",           
			"5" : "\u4e94",           
			"6" : "\u516d"          
			};           
			if(/(y+)/.test(fmt)){           
				fmt=fmt.replace(RegExp.$1, (Date_.getFullYear()+"").substr(4 - RegExp.$1.length));           
			}           
			if(/(E+)/.test(fmt)){           
				fmt=fmt.replace(RegExp.$1, ((RegExp.$1.length>1) ? (RegExp.$1.length>2 ? "\u661f\u671f" : "\u5468") : "")+week[Date_.getDay()+""]);           
			}           
			for(var k in o){           
				if(new RegExp("("+ k +")").test(fmt)){           
					fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));           
				}           
			}           
			return fmt;
		}
		
		var getDayStamp = function(){
			var start = new Date(new Date().toLocaleDateString()).getTime() / 1000;
			var end = ~~(new Date().getTime() / 1000);
			return {start:start, end:end};
		}

		return {format:format, getDayStamp:getDayStamp,}
	};

	/**
	  * 异步遍历
	  * @param: {Object || Array} param
	  * @param: {Function} fn
	  *	@example1: var selectList = this.Dict.selectList;
					Tools.asyncLoop.call(this, selectList, function(key, value, next){
						if(typeof value === 'function'){
							value().then(function(res){
								selectList[key] = res;
								next();
							})
						}else{
							next();
						};
					}, function(){});
	  *	@example1: Tools.asyncLoop.call(this, [{name:'123'}, {name:'234'}], function(key, value, next){
						var reqItem = value;
						reqApi.getItem(reqItem.param).then((res) => {
							if(res && res.stat){
								next();
							};
						});
					}, function(){});
	  * @author: Kimber
	  * @updatetime: 2021/12/10(周五)
	  * @createtime: 2021/12/10(周五)
	  */
	var asyncLoop = function(param, fn, end){
		var list = typeof param === 'object' ? Object.keys(param) : param || [], len = list.length;
		!function loop(i){
			(i < len) ? (()=>{
				var key = list[i];
				var item = param[key];
				fn && fn.call(this,key, item, ()=>{
					loop.call(this, ++i);
				});
			})() : (()=>{end&&end.call(this)})();
		}.bind(this)(0);
	};

	/**
	  * checkbox列表渲染
	  * @param: {Object} opts 
	  *	@example1:	var result = {};	// 域外变量或常量
					Tools.checkbox({
						vue:self || this,
						el:document.getElementById("checkctn2222") || checkctn2222,
						list:[{name:'测试1', value:'a001'}, {name:'测试2', value:'a002'}],
						select:['a001', 'a002'],
						result:result || {},		// 用于外部记录
						change: function(val){},
					});
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2022/1/22
	  * @createtime: 2022/1/22
	  */
	var checkbox = function(opts){
		var that = opts.vue;
		if(that && that.$root){
			var Vue = that.$root.constructor, result = opts.result || {};result.items = {};
			var selBox = new Vue({
				el: opts.el,
				name: 'checkbox',
				data:opts.data,
				props: ['value2'],
				render: function(h){
					var self = this;
					return h('div', {
						'class': {'checkboxctn': true,},
					}, [h('ul', {}, (opts.list || []).map(function (item, index) {
						var checked = opts.select && opts.select.indexOf(item.value) > -1;
						checked && (result.items[item.value] = item.name);
						result.values = Object.keys(result.items);
						return h('li', {
						}, [h('el-checkbox', {
							props:['test'],data:{},
							domProps:{value:item.value,index:index,},
							attrs:{checked:checked,},
							on:{
								'change': function (val, e) {
									var tag = e.target || e.srcElement;
									var lable = tag.labels[0];
									if(val){
										result.items[lable.value] = item.name;
									}else{
										delete result.items[lable.value]
									};
									result.values = Object.keys(result.items);
									opts.change && opts.change(result.values, result.items);
								},
							},
							scopedSlots: {
								default: function (a,b,c) {
									return h('span', item.name)
								}
							},
							children:[],
						}, true)]);
					}))]);
				}
			});
		}else{
			console.log(new Error('vue must is a vue Object'))
		};
	};
	
	// 单窗口无缝滚动
	var singleViewSeamlessScroll = function(el, opts){
		el = typeof el === "string" ? document.getElementById(el) : el;
		if(!el) return console.log('%c sliderPlate Error Element is a invalid param! ', 'color:red');

		var Widget = function(unitEl){
			var scroll = unitEl.firstElementChild.firstElementChild, pointer = 0;
			var list = this.list = scroll.children;
			var listnum = this.listnum = list.length;
			var firstEl = list[pointer];
			firstEl.className = 'is-animating scroll-in';
			var timerA = new timerLoop(5000, 'timerA');
			(listnum > 1) && timerA(function(){
				var index = pointer, newi = ++pointer, pi = index ? index -1 : listnum-1;
				pointer = newi % (listnum);
				var target = list[index];
				var previous = list[pi];
				var next = list[pointer];
				if(previous && previous.classList.contains('is-animating')){
					previous.classList.remove('scroll-in');
					previous.classList.add('scroll-out');
					(function(a){
						setTimeout(() => {
							a.className = '';
						}, 800)
					})(previous);
				};
				target.classList.add('scroll-in');
				setTimeout(() => {
					next.classList.add('is-animating');
				}, 1000)
			});
		}; Widget.prototype = {
			update: function(){},
		};return new Widget(el);
	};

	// 数组对象转对象(用于格式化Dict)
	var arrayJsonToJson = function(arr, key, value){
		var json = {};
		if(arr[0] && arr.push){
			for(var item of arr){
				json[item[value || 'value']] = item[key || 'name'];
			};
		};return json;
	};

	// 利用 canvas 将 File 的 blob stream 转为 base64
	var canvasTobase64 = function(img, w, h){
		// canvas
		var canvas = document.createElement('canvas');
		canvas.width = w;
		canvas.height = h;
		var ctx = canvas.getContext('2d');
		ctx.fillStyle = 'transparent';
		ctx.fillRect(0, 0, w, h);
		ctx.drawImage(img, 0, 0, w, h);
		// 生成结果
		var results = {};
		results.base64 = canvas.toDataURL('image/jpeg', 0.7);
		results.base64Len = results.base64.length;
		canvas = null;		// 释放内存
		return results;
	};
	var blobStreamToBase64 = function(blob, fn){
		var img = new Image();
		img.src = blob;
		img.crossOrigin = "*";
		img.onerror = function() {
			var error = new Error('图片加载失败');
		};
		img.onload = function(){
			var w = img.width, h = img.height;
			return fn(canvasTobase64(img, w, h), img = null);

			//var verify = fn(img);		// 自定义验证
			// 重设比例
			//that.setCoordRatio();
		}
	};
	/**
	  * 图片转 base64
	  * @param: {Element} el
	  * @param: {Function} fn
	  *	@example1: Tools.fileElTobase64(tag, function(res){});
	  * @example2: Tools.fileElTobase64(tag).then(function(res){}).catch(function(err){});
	  * @return: 
	  */
	var fileElTobase64 = function(el, fn, opts){
		var file = el && el.files[0];
		return new Promise((resolve, reject) => {
			if(file.name.indexOf(".jpg") > 0 || file.name.indexOf(".png") > 0){
				var blob = (typeof file === 'string') ? file : URL.createObjectURL(file);
				blobStreamToBase64(blob, function(res){
					return res.base64Len ? fn && fn(res) || resolve(res) : reject(res);
				});
			}else{
				el.value = '';
				return reject({type:4, msg:'图片文件类型不正确！'})
			}
		})
	};


	// 创建选择列表绑定事件
	var createOnSelect = function(dom, arr, opts){
		var len = arr.length, optionText = '';
		for(var i=0; i<len; i++){
			var item = arr[i];
			optionText += '<option value="'+item[opts.value || 'value']+'" data-index="'+i+'">'+item[opts.name || 'name']+'</option>';
		};
		opts.fn && (dom.onchange = function(e){
			var tag = e.target || e.srcElement;
			var option = tag.selectedOptions[0];
			opts.fn(option.value, option);
		});
		return dom.innerHTML = optionText, opts.onload && opts.onload(dom.options[0] && dom.options[0].value), dom;
	};

	var cuPrint = function(dom, options){
		var Print = function () {
		  if (!(this instanceof Print)) return new Print(dom, options);

		  this.options = this.extend({
			'noPrint': '.no-print'
		  }, options);

		  if ((typeof dom) === "string") {
			this.dom = document.querySelector(dom);
		  } else {
			this.isDOM(dom)
			this.dom = this.isDOM(dom) ? dom : dom.$el;
		  }

		  this.init();
		};
		Print.prototype = {
		  init: function () {
			var content = this.getStyle() + this.getHtml();
			this.writeIframe(content);
		  },
		  extend: function (obj, obj2) {
			for (var k in obj2) {
			  obj[k] = obj2[k];
			}
			return obj;
		  },

		  getStyle: function () {
			var str = "",
			  styles = document.querySelectorAll('style,link');
			for (var i = 0; i < styles.length; i++) {
			  str += styles[i].outerHTML;
			}
			str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";

			return str;
		  },

		  getHtml: function () {
			var inputs = document.querySelectorAll('input');
			var textareas = document.querySelectorAll('textarea');
			var selects = document.querySelectorAll('select');

			for (var k = 0; k < inputs.length; k++) {
			  if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
				if (inputs[k].checked == true) {
				  inputs[k].setAttribute('checked', "checked")
				} else {
				  inputs[k].removeAttribute('checked')
				}
			  } else if (inputs[k].type == "text") {
				inputs[k].setAttribute('value', inputs[k].value)
			  } else {
				inputs[k].setAttribute('value', inputs[k].value)
			  }
			}

			for (var k2 = 0; k2 < textareas.length; k2++) {
			  if (textareas[k2].type == 'textarea') {
				textareas[k2].innerHTML = textareas[k2].value
			  }
			}

			for (var k3 = 0; k3 < selects.length; k3++) {
			  if (selects[k3].type == 'select-one') {
				var child = selects[k3].children;
				for (var i in child) {
				  if (child[i].tagName == 'OPTION') {
					if (child[i].selected == true) {
					  child[i].setAttribute('selected', "selected")
					} else {
					  child[i].removeAttribute('selected')
					}
				  }
				}
			  }
			}
			// 包裹要打印的元素
			// fix: https://github.com/xyl66/vuePlugs_printjs/issues/36
			let outerHTML = this.wrapperRefDom(this.dom).outerHTML
			return outerHTML;
		  },
		  // 向父级元素循环，包裹当前需要打印的元素
		  // 防止根级别开头的 css 选择器不生效
		  wrapperRefDom: function (refDom) {
			let prevDom = null
			let currDom = refDom
			// 判断当前元素是否在 body 中，不在文档中则直接返回该节点
			if (!this.isInBody(currDom)) return currDom

			while (currDom) {
			  if (prevDom) {
				let element = currDom.cloneNode(false)
				element.appendChild(prevDom)
				prevDom = element
			  } else {
				prevDom = currDom.cloneNode(true)
			  }

			  currDom = currDom.parentElement
			}

			return prevDom
		  },

		  writeIframe: function (content) {
			var w, doc, iframe = document.createElement('iframe'),
			  f = document.body.appendChild(iframe);
			iframe.id = "myIframe";
			//iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
			iframe.setAttribute('style', 'position:absolute;width:0;height:0;top:-10px;left:-10px;');
			w = f.contentWindow || f.contentDocument;
			doc = f.contentDocument || f.contentWindow.document;
			doc.open();
			doc.write(content);
			doc.close();
			var _this = this
			iframe.onload = function(){
			  _this.toPrint(w);
			  setTimeout(function () {
				document.body.removeChild(iframe)
			  }, 100)
			}
		  },

		  toPrint: function (frameWindow) {
			try {
			  setTimeout(function () {
				frameWindow.focus();
				try {
				  if (!frameWindow.document.execCommand('print', false, null)) {
					frameWindow.print();
				  }
				} catch (e) {
				  frameWindow.print();
				}
				frameWindow.close();
			  }, 10);
			} catch (err) {
			  console.log('err', err);
			}
		  },
		  // 检查一个元素是否是 body 元素的后代元素且非 body 元素本身
		  isInBody: function (node) {
			return (node === document.body) ? false : document.body.contains(node);
		  },
		  isDOM: (typeof HTMLElement === 'object') ?
			function (obj) {
			  return obj instanceof HTMLElement;
			} :
			function (obj) {
			  return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
			}
		};
		Print();
	};

	var downloadFile = function(obj, name, suffix){
		var url = window.URL.createObjectURL(new Blob([obj]));
		var link = document.createElement('a');
		link.style.display = 'none';
		link.href = url;
		var fileName = name + '.' + suffix;
		link.setAttribute('download', fileName);
		document.body.appendChild(link);
		link.click();
		document.body.removeChild(link);
	};

	return {
		timerLoop:timerLoop, Dates:Dates(), arrayJsonToJson, 
		asyncLoop, checkbox, singleViewSeamlessScroll, fileElTobase64, 
		createOnSelect, cuPrint, downloadFile, 
	}
};

/**
  * 文件下载
  * @return: Object
  * @author: Kimber
  * @updatetime: 2021/7/20
  * @createtime: 2021/7/20
  */
var FileStream = function(){
	function s2ab(s) {
		var buf = new ArrayBuffer(s.length);
		var view = new Uint8Array(buf);
		for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
		return buf;
	};

	/**
	  * 字符转换 Blob 对象
	  * @param: {String} str 
	  * @example1: var aaa = FileStream.toBlob(str);
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2021/7/20
	  * @createtime: 2021/7/20
	  */
	var toBlob = function(str){
		return new Blob([s2ab(str)], {
			type: "application/octet-stream"
		});
	};
	
	/**
	  * 利用 A标签 下载文件
	  * @param: {Blob} url 
	  * @param: {String} saveName	// 文件名
	  * @example1: FileStream.download(blob, 'Test.xlsx');
	  * @return: 
	  * @author: Kimber
	  * @updatetime: 2021/7/20
	  * @createtime: 2021/7/20
	  */
	var download = function(url, saveName){
		if (typeof url == 'object' && url instanceof Blob) {
			url = URL.createObjectURL(url); // 创建blob地址
		}
		var aLink = document.createElement('a');
		aLink.href = url;
		aLink.download = saveName || ''; // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
		var event;
		if (window.MouseEvent) event = new MouseEvent('click');
		else {
			event = document.createEvent('MouseEvents');
			event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
		}
		aLink.dispatchEvent(event);
	};

	return {toBlob:toBlob, download:download}
};

export var Tools = Tools();
export var FileStream = FileStream();

/* exports = {
	HttpReq: HttpReq(),
	Dates: Dates(),
	Tools: Tools(),
}; */
