/*
 * Semaphore
 * 
 * A class to allow the synchronization of events in an appplicaiton
 * 
 * @param name - the name to assign this semaphore
 * @param hitCount - the number of hits before it activates
 * @param active - boolean indicating if it starts active or not
 * 
 * @return - this object
 */
function Semaphore(name, hitCount, active)
{
	this.hits = 0;
	this.hitCount = hitCount; // how many kicks to get the center of the semaphore
	this.name = name;
	this.active = active;
	this.callbacks = new Array();
	this.links = new Array(); // to link semaphores so they all kick at the same time
	
	/*
	 * addLink
	 * 
	 * Links one semaphore with another to ensure synchronicity
	 * 
	 * @param link - the semaphore to link
	 */
	this.addLink = function (link)
	{
		if (link != this)
		{
			var hasLink = false;
			for (var index = 0; index < this.links.length; index++)
			{
				if (this.links[index] == link)
				{
					hasLink = true;
				}
			}
			
			// We want to ensure that linked semaphores are kicked as synchronous as possible
			if (hasLink == false)
			{
				this.links.push(link);
				link.addLink(this); // cross pollinate
			}
		}
	};
	
	/*
	 * activate
	 * 
	 * makes the semaphore active, allows the semaphore to be kicked but not acted upon
	 * 
	 * @param - active boolean
	 */
	this.activate = function(active)
	{
		this.active = active;
	};
	
	
	/*
	 * ready
	 * 
	 * determines if the semaphore has all kicks kicked.
	 * 
	 * @param none
	 * 
	 * @return boolean
	 */
	this.ready = function ()
	{
		var retVal = false;
		
		if (this.hits == this.hitCount)
		{
			retVal = true;
		}
		return retVal;
	};
	
	/*
	 * kick
	 * 
	 * kicks the semaphore to up the hit count.
	 * 
	 * @param none
	 * 
	 * @return none
	 */
	this.kick = function ()
	{
		this.hits++;
		
		if (this.hits == this.hitCount)
		{
			// kick all callbacks provided its active
			if (this.active == true)
			{
				var allReady = true;
				
				// Make sure all linked semaphores are ready to fire
				for (var link = 0; link < this.links.length; link++)
				{
					if (this.links[link].ready() == false)
					{
						allReady = false;
					}
				}
				
				/* Do it */
				if (allReady == true)
				{
					var thisObj = this;
					
					// let the flood commence
					for (var link = 0; link < this.links.length; link++)
					{
						var callObject = this.links[link];
						setTimeout(function () {callObject.issueCallbacks();}, 20);
					}
					setTimeout(function () {thisObj.issueCallbacks();}, 20); // give small delay to allow the caller that kicked it off to return to its normally scheduleded process
				}
			}
		}
	};
	
	/*
	 * reset
	 * 
	 * used to reset the semaphore back to its original state
	 * 
	 * @param none
	 * 
	 * @return none
	 */
	this.reset = function ()
	{
		this.hits = 0;
		this.active = false;
		// wack links?
	};
	
	/*
	 * issueCallbacks
	 * 
	 * issues all of the call backs for this semaphore
	 * 
	 * @param none
	 * 
	 * @return none
	 */
	this.issueCallbacks = function ()
	{
		for (var index = 0; index < this.callbacks.length; index++)
		{
			this.callbacks[index]();
		}
	};
	
	/*
	 * wait
	 * 
	 * used to queue up a callback for when the semaphore is kicked
	 * 
	 * @param callback method
	 * 
	 * @return none
	 */
	this.wait = function(callback)
	{
		this.callbacks.push(callback);
	};
	
	return this;
}
