var Events = ( function ( ) {
	var eventCache = {};
	var subscriptions = {};

	return {
		fire : function ( context, event, callback ) {
			var args = Array.prototype.slice.call ( arguments, 3 );
			if ( typeof callback != "function" ) args.unshift ( callback );
			if ( !context || !context.__ecid__ || !event || !eventCache[context.__ecid__][event] ) {
				if ( typeof callback == "function" ) callback.apply ( context );
				return false;
			}
			var total = 0;
			for ( var id in eventCache[context.__ecid__][event].length ) total ++;
			var completed = 0;
			var finish = function ( ) {
				if ( typeof callback == "function" )
					if ( completed++ == total )
						callback.apply ( context );
			}
			for ( var sid in eventCache[context.__ecid__][event] ) {
				var ec = eventCache[context.__ecid__][event][sid];
				if ( !isNaN ( ec.count ) ) {
					eventCache[context.__ecid__][event][sid].count = ec.count = ec.count - 1;
					if ( !ec.count ) Events.unsubscribe ( sid );
				}
				var sync = ec.fn.apply ( context, args.concat ( [ finish ] ) );
				if ( sync !== true ) finish();
			}
		},
		init : function ( context ) {
			if ( !context ) return false;
			if ( context.__ecid__ ) return true;
			context.__ecid__ = (""+Math.random()).substr(2);
			eventCache[context.__ecid__] = {};
			return true;
		},
		subscribe : function ( context, event, fn, count ) {
			if ( !context || !event ) return false;
			if ( !context.__ecid__ ) Events.init ( context );
			var sid = (""+Math.random()).substr(2);
			if ( !eventCache[context.__ecid__][event] )
				eventCache[context.__ecid__][event] = {};
			eventCache[context.__ecid__][event][sid] = { fn : fn, count : isNaN ( count ) ? null : count };
			subscriptions[sid] = eventCache[context.__ecid__][event];
			//console.log ( eventCache, subscriptions );
			return sid;
		},
		subscribeOnce : function ( context, event, fn ) {
			return Events.subscribe ( context, event, fn, 1 );
		},
		unsubscribe : function ( sid ) {
			if ( !sid || !subscriptions[sid] ) return false;
			delete subscriptions[sid][sid];
			delete subscriptions[sid];
			//console.log ( eventCache, subscriptions );
			return true;
		}
	}
} )();

window.setStoppableTimeout = function ( context, fn, time ) {
	var timeout = setTimeout ( fn, time );
	Events.subscribeOnce ( context, 'stop', function ( ) {
		clearTimeout ( timeout );
	} );
	return timeout;
}

window.setStoppableInterval = function ( context, fn, time ) {
	var interval = setInterval ( fn, time );
	Events.subscribeOnce ( function ( ) {
		clearInterval ( interval );
	} );
	return interval;
}

