/* A method called wrapped by an ExclusiveAction object is guaranteed to
 * run exclusively while other ExclusiveAction objects wait their turn.
 * Usage (with help from prototype.js):
 *
 *   function someEventHandler()
 *   {
 *  	new Ajax.Request(
 *  		'myscript.php', 
 *  		{
 *  			method: 'get',
 *  			onComplete: function () { new ExclusiveAction(someCriticalMethod); }
 *  		});
 *   }
 *   function someCriticalMethod() { 
 *     // Do something to a shared resource.
 *	 }
 *
 * Based on code by Bruce Wallace, available here:                                   
 * http://www.onjava.com/pub/a/onjava/2006/04/05/ajax-mutual-exclusion.html  
 *
 * This code is provided with no guarantees or support, implied or otherwise, 
 * whatsoever, at all. Use at your own risk.
 */
 
// Constructor
var ExclusiveAction = function(criticalSection) {
      this.attempt = function(start)
      {
			for (var j = start; j != null; j = ExclusiveAction.next(j.id))
			{
                  // This is the super tricky part.
                  if (j.enter || (j.number && (j.number < this.number || (j.number == this.number && j.id < this.id))))
                  {
                        var me = this;
                        return setTimeout(function() { me.attempt(j); }, 200);
                   }
            }
            // run with exclusive access
            this.criticalSection();
            // release
            this.number = 0;
            ExclusiveAction.waitList[this.id] = null;
      }
     
      this.id = ++ExclusiveAction.commandID;
      this.criticalSection = criticalSection;
     
      ExclusiveAction.waitList[this.id] = this;
     
      this.enter    = true;
      this.number   = (new Date()).getTime();
      this.enter    = false;
     
      this.attempt(ExclusiveAction.next());
}
// Static members
ExclusiveAction.waitList = new Object();
ExclusiveAction.commandID = 0;
ExclusiveAction.next = function(k)
{
      for (i in ExclusiveAction.waitList) {
            if (!k)
            {
                  return ExclusiveAction.waitList[i];
            }
            if (k == i)
            {
                  k = null; // tricky
            }
      }
      return null;
}
