if (rio.Thread) { rio.Thread.disable(); }

rio.Thread = {
	jobs: [],
	groups: {},
	frequency: 100,
	lastPulse: new Date(),
	pulse: function() {
		if (this.jobs.length == 0) {
			this.lastPulse = new Date();
			return;
		}
		
		var start = new Date();
		if (start - this.lastPulse < 50) {
			// rio.log("Thread.skipping_beat - " + (start - this.lastPulse));
			return;
		}

		try {
			var count = this.frequency;

			var job = this.jobs.shift();
			while (job) {
				job();
				if (count--) { job = this.jobs.shift(); } else { job = false; }
			}
		} catch(e) {
			rio.warn("thread failed");
		} finally {
			this.lastPulse = new Date();
			var delay = this.lastPulse - start;

			if (this.jobs.length > 0) {
				if (delay > 100) {
					this.frequency /= 2;
					// rio.log("Thread.frequency changed to: " + this.frequency);
				} else if (delay < 30) {
					this.frequency = (this.frequency * 1.5).ceil();
					// rio.log("Thread.frequency changed to: " + this.frequency);
				}
				// rio.log("Thread.delay - " + delay);
			}
		}
	},
	
	fork: function(fcn, options) {
		var groupName = (options || {}).group;
		if (groupName) {
			var group = this.groups[groupName];
			if (!group) { 
				group = { 
					suspended: options.suspended,
					jobs: []
				};
				this.groups[groupName] = group;
			} else {
				if (options.suspended != undefined) {
					if (group.suspended && !options.suspended) {
						this.resume(groupName);
					} else if (!group.suspended && options.suspended) {
						group.suspended = true;
					}
				}
			}
			
			
			if (!group.suspended) {
				// rio.log("Thread.fork job for group: " + groupName);
				this.jobs.push(fcn);
			} else {
				group.jobs.push(fcn);
			}

		} else {
			this.jobs.push(fcn);
		}
	},
	
	resume: function(groupName, options) {
		try {
			(function() {
				var group = this.groups[groupName];
				for (var i=0, length=group.jobs.length; i<length; i++) {
					this.jobs.push(group.jobs[i]);
				}
				group.jobs.clear();
				group.suspended = false;
			}.bind(this)).delay((options || {}).delay || 0);
		} catch(e) { 
			rio.warn("Thread.resume failed to resume group: " + groupName);
			throw(e);
		}
	},
	
	suspend: function(groupName) {
		var group = this.groups[groupName];
		if (!group) {
			group = {
				jobs: []
			};
			this.groups[groupName] = group;
		}
		group.suspended = true;
	},
	
	enable: function() {
		if (this.pulseIntervalId) { return; }
		this.pulseIntervalId = setInterval(rio.Thread.pulse.bind(rio.Thread), 100);
	},
	
	disable: function() {
		if (this.pulseIntervalId) {
			clearInterval(this.pulseIntervalId);
		}
	}
};

rio.Thread.enable();