// here's Upstart, an event-based Javascript application startup manager
function Upstart() {
	// associative array of events
	this.events = {};
	// returns the number of events left
	this.count = function() {
		var count = 0;
		for(var i in this.events) count++;
		return(count);
	};
	// check if an event is registered
	this.registered = function(name) {
		//	name = name of event
		return(name in this.events);
	};
	// register an event
	this.register = function(event) {
		//	event = {
		//		name:	name of event,
		//		dep:	array of dependencies,
		//		scope:	(optional) "this" of the event,
		//		method:	function of the event,
		//		args:	(optional) arguments to the function
		//	}
		if(this.registered(event)) this.unregister(event.name);
		this.events[event.name] = event;
		console.log('Registered "'+event.name+'"');
	};
	// unregister an event
	this.unregister = function(name) {
		//	name = name of event
		delete this.events[name];
		console.log('Unregistered "'+name+'"');
	};
	// run once
	this.execute = function() {
		var count = 0;
		for(var i in this.events) {
			var e = this.events[i];
			if(e.dep.length) continue;
			console.log('Running "'+e.name+'"');
			try {
				e.method.apply(e.scope?e.scope:e.method,e.args?e.args:[]);
			} catch(e) {
				console.log('Uncaught exception in "'+e.name+'":',e);
				break;
			}
			var name = e.name;
			this.unregister(e.name);
			for(var i in this.events) {
				var e = this.events[i];
				for(var j = 0; j < e.dep.length; j++) if(e.dep[j] == name) e.dep.splice(j,1);
				count++;
			}
			count++;
		}
		return(count);
	};
}

// helper function to loop until there are no events left
// events that have no satisfiable dependencies do not count
// possibly profile code execution to streamline future startups
function UpstartExec(upstart) {
	//	upstart = upstart instance
	if(upstart.execute()) setTimeout(function() { UpstartExec(upstart); },0);
	else {
		var count = upstart.count();
		console.log('Upstart suspended with '+(count==0?'no':count)+' event'+(count==1?'':'s')+' on queue.');
	}
}

// the obligatory demo function
// all output is logged to the debug console
function upstartDemo() {
	// make a new startup manager
	var upstart = new Upstart();
	// register some startup methods
	upstart.register({
		name:	'cedric',
		dep:	['alice','bob'],
		method:	function() {
			console.log('dave');
		}
	});
	upstart.register({
		name:	'bob',
		dep:	['alice','eve'],
		method:	function() {
			console.log('bob');
		}
	});
	upstart.register({
		name:	'alice',
		dep:	[],
		method:	function() {
			console.log('alice');
		}
	});
	upstart.register({
		name:	'eve',
		dep:	['dave'],
		method:	function() {
			console.log('eve');
		}
	});
	upstart.register({
		name:	'dave',
		dep:	[],
		method:	function() {
			console.log('dave');
		}
	});
	// let's get going
	UpstartExec(upstart);
}
