/*=============================================================================================
	author:ZhaoJun
	version:1.2
	email:2732810281@qq.com
=============================================================================================*/


//严格模式
/*-------------------------------------------------------------------------------------------*/	
'use strict';
/*-------------------------------------------------------------------------------------------*/

const { exec } = require('child_process');
const utils =require('util')
const filters= require('../fun/filter.fun')
const fs =require('fs')

// 常用操作
/*-------------------------------------------------------------------------------------------*/	
	class sys
	{       
		static err(obj,extender)
		{
			throw filters.echo(obj,extender)
		}  

		static errIo(err,object,extender)
		{
			if(err instanceof Error)
			{
				console.error("[注意]",err.stack);
				object=filters.echo(object,extender)
			}
			else
			{
				object=err
			}
			
			return object
		}

		static include(mod,name,type='model',tag,tagNew)
		{
			if($Sys[name])
			{
				console.info('[绑定模块]模块名已存在-',name)
				return;
			}
			if(tag)
			{
				let nw=$Sys[type](mod)
				if(tagNew)
				{
					$Sys[name]=new nw(tagNew)
				}
				else
				{
					$Sys[name]=nw
				}
				return
			}
			Object.defineProperty
			(
				$Sys,name,
				{
					get()
					{
						let ne= $Sys[type](mod)
						return new ne()
					}
				}
			)
		}

		static includeS(mod,name,type='model')
		{
			sys.include(mod,name,type,true)
		}

		static bind(mod,name,param={},type='model')
		{
			sys.include(mod,name,type,true,param)
		}
		
		static rand(lowerValue,upperValue)
		{
			return Math.floor(Math.random() * (upperValue - lowerValue + 1) + lowerValue);
		}

		static race(pro,time=3000,tag='')
		{
			if(!Number.isInteger(time))
			{
				time=3000;
				tag=time;
			}
			return Promise.race
			(
				[
					pro,
					new Promise
					(
						function(reslove,reject)
						{
							setTimeout
							(
								() => 
								{
									reject(`${tag?tag:'任务'}超时：${time}ms`);
								}, time
							);
						}
					)
				]
			)
		}

		static io(mold,need,opt)
		{
			mold=require(mold)[need];
			mold=utils.promisify(mold);
			if(opt!==null)
			{
				return mold(...opt);
			}
			else
			{
				return mold;
			}
		}

		static com(mold,need,opt,tag,df)
		{
			if(need && mold)
			{
				if(tag===true)mold=new mold;
				mold=mold[need];
				if(opt!==null)
				{
					if(!mold)$Sys.err({message:'[模块]'+df+'-'+need+'未发现'})
					if(Array.isArray(opt))
					{
						return mold(...opt);    
					}
					else
					{
						return mold(opt);
					}
				}
				else
				{
					return mold;
				}
			}
			else
			{
				return mold;
			}	
		}

		static model(df,need=null,opt=null)
		{
			if(opt===false || !df)return  false;
			try  
			{
				var mold=require($Config.root+"/nodejs/model"+df+'.fun.js');
				return sys.com(mold,need,opt,undefined,df);			
			} 
			catch (error) 
			{
				if(error.stack)
				{
					console.error("[执行模型模块]"+df+'------错误------'+'描述:',error.stack);
					$Sys.err({message:"执行模块错误"});
				}
				else
				{
					console.error("[执行模型模块]"+df+'------错误------'+'描述:',error);
					$Sys.err(error);
				}
				
				return false;
			}
		}

		static control(df,need=null,opt=null)
		{
			if(opt===false || !df)return  false;
			try 
			{
				var mold=require($Config.root+"/nodejs/control"+df+'.class.js');
				return sys.com(mold,need,opt,true,df);
			} 
			catch (error) 
			{
				if(error.stack)
				{
					console.error("[执行控制器模块]"+df+'------错误------'+'描述:',error.stack);
					$Sys.err({message:"执行控制器错误"});
				}
				else
				{
					console.error("[执行控制器模块]"+df+'------错误------'+'描述:',error);
					$Sys.err(error);
				}
				return false;
			}
		}

		static middle(df,need=null,opt=null)
		{
			if(opt===false || !df)return  false;
			try 
			{ 
				var mold=require($Config.root+"/nodejs/middle"+df+'.mi.js');
				return sys.com(mold,need,opt,undefined,df);				
			} 
			catch (error) 
			{
				if(error.stack)
				{
					console.error("[执行中间件模块]"+df+'------错误------'+'描述:'+error.stack);
					$Sys.err({message:"执行中间件模块"});
				}
				else
				{
					console.error("[执行中间件模块]"+df+'------错误------'+'描述:',error);
					$Sys.err(error);
				}
				return false;	
			}
		}

		static service(df,need=null,opt=null)
		{
			if(opt===false || !df)return  false;
			try 
			{
				var mold=require($Config.root+"/nodejs/service"+df+'.ser.js');
				return sys.com(mold,need,opt,undefined,df);
			} 
			catch (error) 
			{
				if(error.stack)
				{
					console.error("[执行服务错误]"+df+'------错误------'+'描述:'+error.stack);
					$Sys.err({message:"执行服务错误"});
				}
				else
				{
					console.error("[执行服务错误]"+df+'------错误------'+'描述:',error);
					$Sys.err(error);
				}
				return false;				
			}
		}

		static async viewWorker(df,obj={},cache)
		{
			let aw = await $Sys.model('/fun/worker','parse',[{path:df,type:'view',data:[obj]}])
			if(cache)
			{
				return $Sys.model
				(
					'/db/cache','get',
					[{key:$Sys.model('/fun/com','sha1',[df+JSON.stringify(obj)]),timeout:cache,awaitSet:true,fun(){return aw}}]
				)
			}
			return aw
		}

		static view(df,obj,cache)
		{
			if(!df)
			{
				return '';
			}
			df=$Config.root+'/nodejs/view'+df

			let make = ()=>
			{
				return new Promise
				(
					function(reslove,reject)
					{
						fs.readFile
						(
							df,{encoding:'utf8'},async function(err,str)
							{
								if(err)
								{
									console.error("[视图文件]"+df+'------错误------'+'描述:'+err.stack);
									reject(err)
								}
								else
								{
									if(obj)str=await $Sys.model('/http/render','display')(str,obj);
									reslove(str)
								}
							}
						) 
					}
				)
			}

			if(cache)
			{
				return $Sys.model
				(
					'/db/cache','get',
					[{key:$Sys.model('/fun/com','sha1',[df+JSON.stringify(obj)]),timeout:cache,awaitSet:true,fun:make}]
				)
			}

			return make()
		}

		static config(df)
		{
			if(!df)return false;
			try 
			{
				return require($Config.root+"/nodejs/config"+df+'.cnf.js')	
			} 
			catch (error) 
			{
				console.error("[配置文件]",df+'------错误------'+'描述:'+error.stack);
				return false;
			}
		}

		static cmd(str,parm=process.cwd(),time=6000)
		{
			if(!str)
			{
				console.warn('[cmd]不是一个可用的命令',str)
				return
			}
			
			let opt={cwd:parm,timeout:time}
			if(!process.getegid)opt.encoding='buffer'

			return new Promise
			(
				(resolve,reject)=>
				{
					exec
					(
						str,opt,(error, stdout, stderr) => 
						{
							if(!process.getegid)stdout=$Sys.model('/tool/com/gbk','decode',[stdout])
							
							if(error)reject(stderr)
							resolve(stdout)
						}
					);
				}
			)
		}

		static git(parm=process.cwd(),time=600000)
		{
			//git fetch --all && git reset --hard origin/master && git pull origin master
			//sudo git reset --hard origin/master & sudo git pull origin master 
			return sys.cmd('git fetch --all && git reset --hard origin/master && git pull origin master',parm,time)
		} 	

		static explain(sql,type='html',parm=$Config.root+'/extend/bin',time=6000)
		{
			let so=process.getegid?'':'.exe'
			return sys.cmd(`echo ${sql} | soar${so} -report-type ${type}`,parm,time)
		} 
		
		static gidInfo(gid,tag='-')
		{
			let arr=gid.split(tag)
			if(arr.length<4)throw Error('不是一个标准的全局唯一id')
			let mac=[arr[0].slice(0,2),arr[0].slice(2,4),arr[0].slice(4,6),arr[0].slice(6,8),arr[0].slice(8,10),arr[0].slice(10,12)].join(':')
			let pid=sys.model('/fun/com','hex2int',[arr[1]])
			let time=sys.model('/fun/com','hex2int',[arr[2]])
			let request=sys.model('/fun/com','hex2int',[arr[3]])

			
			
			return {mac,pid,time,request}
		}

		static gid(time=Date.now(),pad=0,tag='-')
		{
			if($Config.uniqueIdCountTime!=time)$Config.uniqueIdCount=0
			let count=$Config.uniqueIdCount
			let uni=[$Config.info.ipMac[0].mac.replace(/:/g,'')
					,$Config.info.pid.toString(16)
					,time.toString(16)
					,count.toString(16)]

			$Config.uniqueIdCount+=1;
			$Config.uniqueIdCountTime=time;
			let unis
			if(pad)unis = uni.join(tag).padEnd(pad,tag)
			else unis = uni.join(tag)

			return {
				unis,
				mac:$Config.info.ipMac[0].mac,
				pid:$Config.info.pid,
				time,
				request:count
			}
		}

		static uid(da)
		{
			return require('mongodb').ObjectID(da)
		} 

		static move(src,dst,pre=$Config.root)
		{
			var fs=require("fs");
			fs.renameSync(pre+src,dst);
		}

		static print()
		{
			let log=console.log;
			console.log=function()
			{
				let stack=''
				if(this.$tag===true)log(...arguments)
				else 
				{
					try
					{
						throw(new Error("调用栈:"));
					}
					catch(e)
					{
						stack=e.stack.replace('Error: ','');
						stack=stack.replace(/(\s*?)(\S.*?[\n|$|\s])/g,'$2');
						stack=stack.replace(/at\sConsole.console.log.*?[\n|$]/g,'')
					}
					let arr=[]
					for (let index = 0; index < arguments.length; index++) 
					{
						arr.push('\x1B[0m\x1B[35m')
						arr.push(arguments[index])
						arr.push('\x1B[0m\r\n')
					}
					log('\x1B[33m@ '+(new Date()).toLocaleTimeString()+'-使用了不建议的日志打印方式\r\n\x1B[37m'+stack+'\x1B[0m\r\n',...arr);
				}
			}
			console.white=function(da,mes){sys.info(da,mes,4)}
			console.info=function(da,mes){sys.info(da,mes,3)}
			console.warn=function(da,mes){sys.info(da,mes,2)}
			console.error=function(da,mes){sys.info(da,mes,1)}
		}

    	static info(da,mes,tag)
    	{ 
			if(tag>$Config.print)return
			
			if(mes===undefined)
			{
				mes=da
				da='[系统提示]'
			}
			
			if(mes !== null)
			{
				if(mes.stack)
				{
					da+=mes.stack;
				}
				else if(mes instanceof Object)
				{
					da+=JSON.stringify(mes);
				}
				else
				{
					da+=mes;
				}
			}

			let dat=new Date();
			// 字色编号：30黑，31红，32绿，33黄，34蓝，35紫，36深绿，37白色
			// 背景编号：40黑，41红，42绿，43黄，44蓝，45紫，46深绿，47白色
			// 0带代表背景色
			// \x1B[0m 关闭所有属性

			//\x1B[41;36m something here \x1B[0m
			//\x1B[背景色编号;字色编号m
			let tagColor=''
			switch (tag) 
			{
				case 1:
					tagColor='31'
				break;
				case 2:
					tagColor='33'
				break;
				case 3:
					tagColor='32'
				break;
				default:
					tagColor='37'
				break;
			}
			dat=dat.toLocaleTimeString();
			if(da.length>$Config.logoLength)
			{
				console.log.call({$tag:true},'\x1B[36m@ '+dat+'\r\n\x1B[0m\x1B['+tagColor+'m'+da.substr(0,$Config.logoLength)+'（超出显示长度....）\x1B[0m'); 
			}
			else
			{
				console.log.call({$tag:true},'\x1B[36m@ '+dat+'\r\n\x1B[0m\x1B['+tagColor+'m'+da+'\r\n\x1B[0m');
			}
		}
	}
/*-------------------------------------------------------------------------------------------*/   
    
module.exports=sys;