“use strict”; var firstLineError; try {throw new Error(); } catch (e) {firstLineError = e;} var schedule = require(“./schedule.js”); var Queue = require(“./queue.js”); var util = require(“./util.js”);

function Async() {

this._isTickUsed = false;
this._lateQueue = new Queue(16);
this._normalQueue = new Queue(16);
this._trampolineEnabled = true;
var self = this;
this.drainQueues = function () {
    self._drainQueues();
};
this._schedule =
    schedule.isStatic ? schedule(this.drainQueues) : schedule;

}

Async.prototype.disableTrampolineIfNecessary = function() {

if (util.hasDevTools) {
    this._trampolineEnabled = false;
}

};

Async.prototype.enableTrampoline = function() {

if (!this._trampolineEnabled) {
    this._trampolineEnabled = true;
    this._schedule = function(fn) {
        setTimeout(fn, 0);
    };
}

};

Async.prototype.haveItemsQueued = function () {

return this._normalQueue.length() > 0;

};

Async.prototype.throwLater = function(fn, arg) {

if (arguments.length === 1) {
    arg = fn;
    fn = function () { throw arg; };
}
if (typeof setTimeout !== "undefined") {
    setTimeout(function() {
        fn(arg);
    }, 0);
} else try {
    this._schedule(function() {
        fn(arg);
    });
} catch (e) {
    throw new Error("No async scheduler available\u000a\u000a    See http://goo.gl/m3OTXk\u000a");
}

};

function AsyncInvokeLater(fn, receiver, arg) {

this._lateQueue.push(fn, receiver, arg);
this._queueTick();

}

function AsyncInvoke(fn, receiver, arg) {

this._normalQueue.push(fn, receiver, arg);
this._queueTick();

}

function AsyncSettlePromises(promise) {

this._normalQueue._pushOne(promise);
this._queueTick();

}

if (!util.hasDevTools) {

Async.prototype.invokeLater = AsyncInvokeLater;
Async.prototype.invoke = AsyncInvoke;
Async.prototype.settlePromises = AsyncSettlePromises;

} else {

if (schedule.isStatic) {
    schedule = function(fn) { setTimeout(fn, 0); };
}
Async.prototype.invokeLater = function (fn, receiver, arg) {
    if (this._trampolineEnabled) {
        AsyncInvokeLater.call(this, fn, receiver, arg);
    } else {
        this._schedule(function() {
            setTimeout(function() {
                fn.call(receiver, arg);
            }, 100);
        });
    }
};

Async.prototype.invoke = function (fn, receiver, arg) {
    if (this._trampolineEnabled) {
        AsyncInvoke.call(this, fn, receiver, arg);
    } else {
        this._schedule(function() {
            fn.call(receiver, arg);
        });
    }
};

Async.prototype.settlePromises = function(promise) {
    if (this._trampolineEnabled) {
        AsyncSettlePromises.call(this, promise);
    } else {
        this._schedule(function() {
            promise._settlePromises();
        });
    }
};

}

Async.prototype.invokeFirst = function (fn, receiver, arg) {

this._normalQueue.unshift(fn, receiver, arg);
this._queueTick();

};

Async.prototype._drainQueue = function(queue) {

while (queue.length() > 0) {
    var fn = queue.shift();
    if (typeof fn !== "function") {
        fn._settlePromises();
        continue;
    }
    var receiver = queue.shift();
    var arg = queue.shift();
    fn.call(receiver, arg);
}

};

Async.prototype._drainQueues = function () {

this._drainQueue(this._normalQueue);
this._reset();
this._drainQueue(this._lateQueue);

};

Async.prototype._queueTick = function () {

if (!this._isTickUsed) {
    this._isTickUsed = true;
    this._schedule(this.drainQueues);
}

};

Async.prototype._reset = function () {

this._isTickUsed = false;

};

module.exports = new Async(); module.exports.firstLineError = firstLineError;