/* -*- JavaScript -*-
 *
 * Copyright (c) 2006
 * Spoken Language Systems Group
 * MIT Computer Science and Artificial Intelligence Laboratory
 * Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 **/

function OpQueue(){
   this.operations = [];
   this.isRunning = false;
   this.stopReason = [];
   this.interval = 0;
}

// Make a prototype
new OpQueue();

// Queue a function for execution
OpQueue.prototype.add = function(f){
   this.operations.push(f);
   if (!this.isRunning){
      this.run();
   }
};

OpQueue.prototype.run = function(f){
   if (this.isRunning || 
       this.stopReason.length > 0 ||
       this.operations.length == 0)
      return;

   this.isRunning = true;
   while(!this.stopReason.length > 0 && this.operations.length > 0){
      this.operations.shift()();
   }
   this.isRunning = false;
};

// Stop running functions.
OpQueue.prototype.stop = function(stopReason){
   this.stopReason.push(stopReason);
   this.showStopReason();
}

OpQueue.prototype.showStopReason = function(){
   if (this.stopDisplay){
      if (this.stopReason.length > 0){
	 this.stopDisplay.showStopped(this.stopReason[this.stopReason.length-1]);
      } else {
	 this.stopDisplay.showResumed();
      }
   }
}

// Start running functions again.  For an AJAX sort of thing, do the
// post-response work and then call resume to start the queue running
// again.
OpQueue.prototype.resume = function(){
   this.stopReason.pop();
   this.showStopReason();
   this.run();
}

// Stop the queue until waitfn returns true.  Then call contfn and
// resume the queue.
OpQueue.prototype.waitUntil = function(stopReason, waitfn, contfn){
   this.stop(stopReason);
   var outerthis = this;
   this.interval = 
      setInterval(function(){
		     if (waitfn()){
			clearInterval(outerthis.interval);
			contfn();
			outerthis.resume();
		     }
		  },
		  100);
}

// Do a post for XML, stopping the queue until the result comes back
// kvals are unencoded key/value pairs
OpQueue.prototype.post = function(stopReason, url, kvals, fn){
   var outerthis = this;
   this.add(function(){outerthis.postInternal(stopReason, url, kvals, fn);});
}

// TBD: Some way to time out
OpQueue.prototype.postInternal = function(stopReason, url, kvals, fn){
   var outerthis = this;
   var req;
   if (window.XMLHttpRequest){
      req = new XMLHttpRequest();
   } else if (window.ActiveXObject){
      req = new ActiveXObject("Microsoft.XMLHTTP");
   }
   req.open("POST", url, true);
   req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

   req.onreadystatechange =
      function(){
	 if (!(req.readyState == 4 && req.status == 200)){
	    return;
	 }
	 fn(req.responseXML);
	 outerthis.resume();
      };
   var post="";
   var join="";
   for (var prop in kvals){
      post+=join+prop+"="+encodeURIComponent(kvals[prop]);
      join="&";
   }
   this.stop(stopReason);
   req.send(post);
}

var queue = new OpQueue();
