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


//严格模式
/*-------------------------------------------------------------------------------------------*/	
'use strict';
/*-------------------------------------------------------------------------------------------*/
var path=require('path');
var fs=require("fs");


// 加载操作
/*-------------------------------------------------------------------------------------------*/	
	class load
	{   
		static clearn(df)
		{
			let hp=path.normalize(df);
			let arr=Object.keys(require.cache)
			for (const v of arr) 
			{
				if(v.includes(hp))
				{
					var module=require.cache[require.resolve(v)];
					if (module.parent) 
					{
						module.parent.children.splice(module.parent.children.indexOf(module), 1);
					}
					Reflect.deleteProperty(require.cache,require.resolve(v))
				}
			}
		}


		static hotBack(obj,fpath,tag)
		{
			for (const iterator of obj) 
			{
				if(iterator && iterator.path)
				{
					if(iterator.path instanceof RegExp)
					{
						if(iterator.path.test(fpath)) iterator.fun && iterator.fun(fpath,tag)
					}
					else
					{
						if(fpath.indexOf(String(iterator.path))!=-1) iterator.fun && iterator.fun(fpath,tag)
					}
				}
			}
		}

		static load(_tm,df,ty)
		{
			if($Config.cacheDir.includes(df))
			{
				return;
			}
			if($Config.loadAble)
			{
				var bos=fs.existsSync(df);
				if(!bos)
				{
					return;
				}
				$Config.cacheDir.push(df);
				let fw=fs.watch
				(
					df,function(e,n)
					{
						var date=Date.now();
						var fpath=df+'/'+n; 
						if(date-$Config.loadB<$Config.loadTime && $Config.loadN==fpath)
						{
							return;
						}

						$Config.loadN=fpath;
						$Config.loadB=Date.now();

						setTimeout(async function()
						{
							try 
							{
								var bo=fs.existsSync(fpath);
								if(bo)
								{
									var statInfo = fs.statSync(fpath);
									if(statInfo.isDirectory())
									{
										if(!$Config.cacheDir.includes(fpath))
										{
											_tm(fpath,ty,true);
										}
									}
									else if(statInfo.isFile())
									{
										if(ty)
										{
											load.hotBack($Config.handle.loadPublicFun,fpath,true)
		
											console.white("[前端自更新]",fpath+'------文件更新------'+'来自进程:'+process.pid);
											return;
										}
		
										_tm(fpath,ty,true);
									} 
								}
								else
								{
									if(ty)
									{
										load.hotBack($Config.handle.loadPublicFun,fpath,false)
		
										console.white("[前端自更新]",fpath+'------文件删除------'+'来自进程:'+process.pid);
										return;
									}
									else if(fpath.includes('/nodejs/config/config.cnf.js') || 
									fpath.includes('/nodejs/model/load/load.fun.js') ||
									fpath.includes('/model/load/sys.fun.js'))
									{
										return;
									}
									else
									{
										//load.clearn(fpath)
										load.hotBack($Config.handle.loadJsFun,fpath,false)
										if($Config.loadNotice)console.info("[自更新]",fpath+'------文件移除------'+'来自进程:'+process.pid); 
									}
								} 
							} 
							catch (error) 
							{
								console.error("[自更新]"+fpath+'------发生错误------'+'来自进程:'+process.pid+`------描述：${error.message?error.message:error.stack}`);
							}


						},parseInt($Config.loadTime/2.5))
					}
				)
				fw.on('error',function(){
					console.info("[自更新]",df+'------关闭监听------'+'来自进程:'+process.pid);
					$Config.cacheDir.splice($Config.cacheDir.indexOf(df),1)
					fw.close();
				})
			}
		}

		static async forFile(df,fun)
		{
			df=df.replace(/\\/g,'/');	
			let arr=[]		
			async function check(df)
			{
				var statInfo = fs.statSync(df);
				if(statInfo)
				{
					try 
					{
						if(statInfo.isDirectory())
						{
							if(fun)await fun(df,false)
							var st1=fs.readdirSync(df);
							if(st1)
							{
								for (let x of st1) 
								{
									x= df.concat('/').concat(x);
									check(x);
								}
							}
						}
						else if(statInfo.isFile())
						{
							arr.push(df)
							if(fun)await fun(df,true)
						}	
					} 
					catch (error) 
					{
						console.error('[循环目录]发生错误:',error)
					}
				}
			}
			await check(df);
			return arr
		}

		static cache(df,ty,boo)
		{	
			load.forFile
			(
				df,async(df,tag)=>
				{
					if(tag)
					{	
						if(ty && !boo)
						{
							load.hotBack($Config.handle.loadPublicInitFun,df,tag)
							return
						}
						if(!boo)
						{
							load.hotBack($Config.handle.loadJsInitFun,df,tag)
						}
						
						if(df.includes('/nodejs/config') || 
						df.includes('/nodejs/model/load/load.fun.js') ||
						df.includes('/nodejs/model/fun/worker.fun.js') ||
						df.includes('/model/load/sys.fun.js'))
						{
							return;
						}
						try
						{    
							if($Config.cacheAll)
							{
								if(/\.js$/.test(df))
								{
									load.clearn(df)
									if(!$Config.cacheLazy)require(require.resolve(df));
									if(boo)
									{
										load.hotBack($Config.handle.loadJsFun,df,true)

										if($Config.loadNotice)console.white("[自更新]",df+'------文件重载------'+'来自进程:'+process.pid);  
									}
								}
							} 	
						}
						catch(e)
						{
							e=e.stack;  
							if($Config.loadNotice)console.info("[自更新]",df+'------文件错误------'+'来自进程:'+process.pid+`------描述：${e}`);
						}
					}
					else
					{
						if(!df.includes('/nodejs/bootstrap'))
						{
							load.load(load.cache,df,ty);
						}
					}
				}
			)
		}

		static listen(conPth,fun)
		{
			if(!conPth)return
			load.forFile
			(
				conPth,
				function(df,tag)
				{
					if(!tag)fs.watch
					(
						df,async function(e,name)
						{
							fun && await fun(e,name,df)
						}
					)
				}
			)
		}

		static nginx(conPth)
		{
			load.listen
			(
				conPth,async (e,name,conPth)=>
				{
					try 
					{
						await $Sys.cwd('nginx -s reload')	
						console.info("[nginx配置热更新]","更新成功")
					} 
					catch (error) 
					{
						console.error("[nginx配置热更新]更新待确认",error)
					}
				}
			)
			
		}

		
  }
/*-------------------------------------------------------------------------------------------*/   
    
module.exports=load;