
var Thread = {
  
  hostRunning: true,
  activeLoops: 0,
  _timers: [],
  
  spin: function(ctrl) { 
    ctrl.startTime = ctrl.startTime || Date.now();
    ctrl.timeout = false;
    this.activeLoops++;
    this._spinInternal(ctrl);
    this.activeLoops--;
    ctrl.elapsed = Date.now() - ctrl.startTime;
    return ctrl.timeout;
  },
  
  _spinInternal: function(ctrl) {
    var t = ctrl.startTime;
    var maxTime = parseInt(ctrl.maxTime);
    if (maxTime) {
      while(ctrl.running && this.hostRunning) {
        this.yield();
        if (Date.now() - t > maxTime) {
          ctrl.timeout = true;
          ctrl.running = false;
          break;
        }
      }
    } else while(ctrl.running && this.hostRunning) this.yield();
  },
  
  yield: function() {
    this.current.processNextEvent(true);
  },
  
  yieldAll: function() {
    var t = this.current;
    while(t.hasPendingEvents()) t.processNextEvent(false);
  },
  
  get current() {
    delete this.current;
    var obj = "@mozilla.org/thread-manager;1" in Cc 
      ? Cc["@mozilla.org/thread-manager;1"].getService() 
      : Cc["@mozilla.org/thread;1"].createInstance(Ci.nsIThread);
    this.__defineGetter__("current", function() { return obj.currentThread; });
    return this.current; 
  },
  
  get currentQueue() {
    delete this.currentQueue;
    var eqs = null;
    const CTRID = "@mozilla.org/event-queue-service;1";
    if (CTRID in Cc) {
      const IFace = Ci.nsIEventQueueService;
      eqs = Cc[CTRID].getService(IFace);
    }
    this.__defineGetter__("currentQueue", eqs
      ? function() { return eqs.getSpecialEventQueue(IFace.CURRENT_THREAD_EVENT_QUEUE); }
      : this.__lookupGetter__("current")
    );
    return this.currentQueue;  
  },
  
  delay: function(callback, time, self, args) {
    var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
    this._timers.push(timer);
    timer.initWithCallback({
      notify: this._delayRunner,
      context: { callback: callback, args: args || DUMMY_ARRAY, self: self || null }
    }, time || 1, 0);
  },
  
  dispatch: function(runnable) {
    this.current.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL);
  },
  
  asap: function(callback, self, args) {
    this.current.dispatch({
      run: function() {
        callback.apply(self, args || DUMMY_ARRAY);
      }
    }, Ci.nsIEventTarget.DISPATCH_NORMAL);
  },

  _delayRunner: function(timer) {
    var ctx = this.context;
    try {
      ctx.callback.apply(ctx.self, ctx.args);
    } finally {
      this.context = null;
      var tt = Thread._timers;
      var pos = tt.indexOf(timer);
      if (pos > -1) tt.splice(pos, 1);
      timer.cancel();
    }
  }
  
};
