//taskScheduler 计划任务
import win.ui;
namespace win;

class taskScheduler {

	ctor( winform ){
		if(!winform){
			winform = ..win.form( {} );
			winform.messageOnly();
		}
		
		var timerId;
		var taskJobs = {}; 
		var namedTask = {}; 
	};
	start = function( interval = 1000 ){  
		if(timerId) winform.clearInterval(timerId);
		
		for(name,task in namedTask){ 
			if( task.time ) task.lastRunTime = null; 
			else task.lastRunTime = ..time(); 
		} 
		
		timerId = winform.setInterval(
			function(hwnd,msg,id,tick){ 
				this.trigger();
			},interval
		);
	};
	stop = function(){
		if( timerId ){
			winform.clearInterval(timerId)
			timerId = null;
		}
	};
	create = function( name,job,...){ 
		if( !name ||  namedTask[name] )
			return null,"任务名字冲突";
		
		var task = {};	
		taskJobs[task] = job;  
		task.lastRunTime = ..time();
		task.pending = true;
		task.arguments = {...} 
		task.arguments.length = rget(2,..table.range(task.arguments)); 
		if( task.enabled === null ) task.enabled = true;
		
		namedTask[name] = task;
		return task;
	};
	delete = function(name){
		var task = name && namedTask[name];
		if( !task) return false;
		taskJobs[name] = null;
		taskJobs[task] = null;
		namedTask[name] = null;
		return true;
	}; 
	serialize = function(){
		for(name,task in namedTask){ 
			if( task.beginTime ) task.beginTime.format="%Y/%m/%d %H:%M:%S";
			if( task.expirationTime ) task.expirationTime.format="%Y/%m/%d %H:%M:%S";
		} 
		return ..table.tostring(namedTask);
	};
	deserialize = function( s,defJob ){
		if(!#s) return null,"数据不能为空";
		 
		var ok,tasks = call(eval,,s); 
		if( ! ( ok && type(tasks) == type.table ) ){
			return null,"数据已损坏";
		}
		for(name,task in tasks){ 
			if(task.beginTime) task.beginTime = ..time( task.beginTime,"%Y/%m/%d %H:%M:%S" );
			if(task.expirationTime) task.expirationTime = ..time( task.expirationTime ,"%Y/%m/%d %H:%M:%S"); 
			task.lastRunTime = ..time(); 
			taskJobs[task] = defJob;
		} 
	};
	get = function(name){
		return name && namedTask[name];
	};
	set = function(name,job){
		var task = name && namedTask[name];
		if( task) {
			taskJobs[task] = job;
			return true;
		}
	};
	trigger = function() {
	
		var now = ..time();
		  
		var taskQueue = {};
		for( task,job in taskJobs ){
		
			if( !task.enabled ){
				continue;
			}
		
			if( task.beginTime && now < task.beginTime ){ 
				task.pending = true;
				continue;
			}
			
			if( task.expirationTime && now > task.expirationTime ){ 
				task.pending = true;
				continue;
			}
			 
			for(k,v in task.time ){
				if( type(v) === "table" ){
					if(!..table.find(v,now[k])) { task.pending = true; continue 2;}
				}
				elseif( now[k] != v ){  
					task.pending = true; continue 2; 
				} 
			}  
			
			if(task.time && task.lastRunTime ){
				var same = true;
				for(k,v in task.time){
					if( ( task.lastRunTime[k] !== v )  ){
    					same = false;
					}
				}

				if(same){
					for i,v in ..table.eachIndex({"year";"month";"day";"hour";"minute";"second"}){
						if( task.time[v] !== null ) {
							continue 2; 
						} 
						elseif(now[v]!==task.lastRunTime[v]){ 
							break; 
						} 
					}
				}
			}
			 
			for(k,v in task.interval  ){  
				now.diff = now[ "diff" + k ];
				if( now.diff( task.lastRunTime ) < v  ){
					task.pending = true; continue 2;
				} 
			}  
			 
			if( !task.pending ) continue;
			task.pending = false; 
			 
			task.lastResult = invoke(job,task,..table.unpack(task.arguments,1,task.arguments.length) );
			task.lastRunTime  = ..time();
			task.pending = true;
		}  
	}  
}

/**intellisense()
win.taskScheduler = 计划任务
win.taskScheduler(.(窗体对象) = 参数可省略\n注意仅在线程启动消息循环后起作用\n执行计划任务会阻塞定时器直到任务执行完成\n不希望阻塞定时器可使用 winform.setTimeout、或多线程异步执行代码
win.taskScheduler() = !win_taskScheduler.
!win_taskScheduler.serialize() = 序列化计划任务配置并返回字符串 
!win_taskScheduler.deserialize( = 反序列化计划任务
!win_taskScheduler.deserialize(.(字符串,默认回调函数) = 反序列化计划任务,并指定默认回调函数
!win_taskScheduler.start(.(任务检测间隔) = 开始运行计划任务\n注意仅在线程启动消息循环后起作用\n检测间隔参数可选,默认为1000毫秒\n\n执行计划任务会阻塞定时器直到任务执行完成\n如果在计划任务中执行了win.delay等继续消息循环的代码，\n在计划任务退出前不会再触发同一计划任务（重入）。\n\n不希望阻塞定时器可使用 winform.setTimeout、或多线程异步执行代码
!win_taskScheduler.stop() = 停止计划任务
!win_taskScheduler.create("名字",执行函数) =  @.create("计划任务名字",function( arguments ){\n    \n} , __/*其他调用任务的参数*/ )
!win_taskScheduler.delete(.("任务名字") = 删除指定任务
!win_taskScheduler.get(.("任务名字") = 读取指定任务
!win_taskScheduler.set(.("任务名字",执行函数) = 修改任务执行函数
!win_taskScheduler.get() = !win_taskSchedulerTask.
!win_taskScheduler.create() = !win_taskSchedulerTask.
!win_taskSchedulerTask.enabled = 是否允许执行
!win_taskSchedulerTask.time = @.time = { 
	second =  秒 __/*请指定准时启动任务的时间字段值,\n可以指定数值,也可以用数组指定多个值,\n不作为条件匹配的时间字段不用指定\n即使任务在启动时间内完成也不会重新启动任务*/;
	minute = 分钟 ; 
	hour = 小时 ;
	day = 日 ;
	month = 月 ;
	dayofweek = {1,2,3,4,5,6,0}
}
!win_taskSchedulerTask.interval = @.interval = { 
	second = 间隔秒数 __/*请指定间隔执行的时间字段值*/;
	minute = 间隔分钟数 ;
	hour = 间隔小时数 ;
	day = 间隔天数 ;
	month = 间隔月数 ;
} 
!win_taskSchedulerTask.pending = 任务是否在等待状态\n如果正在执行任务，此属性返回false
!win_taskSchedulerTask.lastRunTime = 任务最后运行的时间
!win_taskSchedulerTask.lastResult = 最后一次执行的返回值
!win_taskSchedulerTask.beginTime = 开始时间\n该值默认为空
!win_taskSchedulerTask.expirationTime = 结束时间\n该值默认为空
end intellisense**/