/*
YUI 3.17.2 (build 9c3c78e)
Copyright 2014 Yahoo! Inc. All rights reserved.
Licensed under the BSD License.
http://yuilibrary.com/license/
*/

YUI.add('timers', function (Y, NAME) {

/**
Provides utilities for timed asynchronous callback execution.
Y.soon is a setImmediate/process.nextTick/setTimeout wrapper.

This module includes [asap.js](https://github.com/kriskowal/asap) for scheduling
asynchronous tasks.

@module timers
@author Steven Olmsted
**/

// Hack. asap.js is written as a Node module and expects require, module and
// global to be available in the module's scope.
var module = {},
    global = Y.config.global;

// `asap` only requires a `queue` module that is bundled into this same file.
function require(mod) {
    return Queue;
}
"use strict";

module.exports = Queue;
function Queue(capacity) {
    this.capacity = this.snap(capacity);
    this.length = 0;
    this.front = 0;
    this.initialize();
}

Queue.prototype.push = function (value) {
    var length = this.length;
    if (this.capacity <= length) {
        this.grow(this.snap(this.capacity * this.growFactor));
    }
    var index = (this.front + length) & (this.capacity - 1);
    this[index] = value;
    this.length = length + 1;
};

Queue.prototype.shift = function () {
    var front = this.front;
    var result = this[front];

    this[front] = void 0;
    this.front = (front + 1) & (this.capacity - 1);
    this.length--;
    return result;
};

Queue.prototype.grow = function (capacity) {
    var oldFront = this.front;
    var oldCapacity = this.capacity;
    var oldQueue = new Array(oldCapacity);
    var length = this.length;

    copy(this, 0, oldQueue, 0, oldCapacity);
    this.capacity = capacity;
    this.initialize();
    this.front = 0;
    if (oldFront + length <= oldCapacity) {
        // Can perform direct linear copy
        copy(oldQueue, oldFront, this, 0, length);
    } else {
        // Cannot perform copy directly, perform as much as possible at the
        // end, and then copy the rest to the beginning of the buffer
        var lengthBeforeWrapping =
            length - ((oldFront + length) & (oldCapacity - 1));
        copy(
            oldQueue,
            oldFront,
            this,
            0,
            lengthBeforeWrapping
        );
        copy(
            oldQueue,
            0,
            this,
            lengthBeforeWrapping,
            length - lengthBeforeWrapping
        );
    }
};

Queue.prototype.initialize = function () {
    var length = this.capacity;
    for (var i = 0; i < length; ++i) {
        this[i] = void 0;
    }
};

Queue.prototype.snap = function (capacity) {
    if (typeof capacity !== "number") {
        return this.minCapacity;
    }
    return pow2AtLeast(
        Math.min(this.maxCapacity, Math.max(this.minCapacity, capacity))
    );
};

Queue.prototype.maxCapacity = (1 << 30) | 0;
Queue.prototype.minCapacity = 16;
Queue.prototype.growFactor = 8;

function copy(source, sourceIndex, target, targetIndex, length) {
    for (var index = 0; index < length; ++index) {
        target[index + targetIndex] = source[index + sourceIndex];
    }
}

function pow2AtLeast(n) {
    n = n >>> 0;
    n = n - 1;
    n = n | (n >> 1);
    n = n | (n >> 2);
    n = n | (n >> 4);
    n = n | (n >> 8);
    n = n | (n >> 16);
    return n + 1;
}
"use strict";

// Use the fastest possible means to execute a task in a future turn
// of the event loop.

// Queue is a circular buffer with good locality of reference and doesn't
// allocate new memory unless there are more than `InitialCapacity` parallel
// tasks in which case it will resize itself generously to x8 more capacity.
// The use case of asap should require no or few amount of resizes during
// runtime.
// Calling a task frees a slot immediately so if the calling
// has a side effect of queuing itself again, it can be sustained
// without additional memory
// Queue specifically uses
// http://en.wikipedia.org/wiki/Circular_buffer#Use_a_Fill_Count
// Because:
// 1. We need fast .length operation, since queue
//   could have changed after every iteration
// 2. Modulus can be negated by using power-of-two
//   capacities and replacing it with bitwise AND
// 3. It will not be used in a multi-threaded situation.

var Queue = require("./queue");

//1024 = InitialCapacity
var queue = new Queue(1024);
var flushing = false;
var requestFlush = void 0;
var hasSetImmediate = typeof setImmediate === "function";
var domain;

// Avoid shims from browserify.
// The existence of `global` in browsers is guaranteed by browserify.
var process = global.process;

// Note that some fake-Node environments,
// like the Mocha test runner, introduce a `process` global.
var isNodeJS = !!process && ({}).toString.call(process) === "[object process]";

function flush() {
    /* jshint loopfunc: true */

    while (queue.length > 0) {
        var task = queue.shift();

        try {
            task.call();

        } catch (e) {
            if (isNodeJS) {
                // In node, uncaught exceptions are considered fatal errors.
                // Re-throw them to interrupt flushing!

                // Ensure continuation if an uncaught exception is suppressed
                // listening process.on("uncaughtException") or domain("error").
                requestFlush();

                throw e;

            } else {
                // In browsers, uncaught exceptions are not fatal.
                // Re-throw them asynchronously to avoid slow-downs.
                setTimeout(function () {
                    throw e;
                }, 0);
            }
        }
    }

    flushing = false;
}

if (isNodeJS) {
    // Node.js
    requestFlush = function () {
        // Ensure flushing is not bound to any domain.
        var currentDomain = process.domain;
        if (currentDomain) {
            domain = domain || (1,require)("domain");
            domain.active = process.domain = null;
        }

        // Avoid tick recursion - use setImmediate if it exists.
        if (flushing && hasSetImmediate) {
            setImmediate(flush);
        } else {
            process.nextTick(flush);
        }

        if (currentDomain) {
            domain.active = process.domain = currentDomain;
        }
    };

} else if (hasSetImmediate) {
    // In IE10, or https://github.com/NobleJS/setImmediate
    requestFlush = function () {
        setImmediate(flush);
    };

} else if (typeof MessageChannel !== "undefined") {
    // modern browsers
    // http://www.nonblocking.io/2011/06/windownexttick.html
    var channel = new MessageChannel();
    // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create
    // working message ports the first time a page loads.
    channel.port1.onmessage = function () {
        requestFlush = requestPortFlush;
        channel.port1.onmessage = flush;
        flush();
    };
    var requestPortFlush = function () {
        // Opera requires us to provide a message payload, regardless of
        // whether we use it.
        channel.port2.postMessage(0);
    };
    requestFlush = function () {
        setTimeout(flush, 0);
        requestPortFlush();
    };

} else {
    // old browsers
    requestFlush = function () {
        setTimeout(flush, 0);
    };
}

function asap(task) {
    if (isNodeJS && process.domain) {
        task = process.domain.bind(task);
    }

    queue.push(task);

    if (!flushing) {
        requestFlush();
        flushing = true;
    }
};

module.exports = asap;
/**
Y.soon accepts a callback function.  The callback function will be called
once in a future turn of the JavaScript event loop.  If the function
requires a specific execution context or arguments, wrap it with Y.bind.
Y.soon returns an object with a cancel method.  If the cancel method is
called before the callback function, the callback function won't be
called.

@method soon
@for YUI
@param {Function} callbackFunction
@return {Object} An object with a cancel method.  If the cancel method is
    called before the callback function, the callback function won't be
    called.
**/
function soon(callbackFunction) {
    var canceled;

    soon._asynchronizer(function () {
        // Some asynchronizers may provide their own cancellation
        // methods such as clearImmediate or clearTimeout but some
        // asynchronizers do not.  For simplicity, cancellation is
        // entirely handled here rather than wrapping the other methods.
        // All asynchronizers are expected to always call this anonymous
        // function.
        if (!canceled) {
            callbackFunction();
        }
    });

    return {
        cancel: function () {
            canceled = 1;
        }
    };
}

soon._asynchronizer = asap;
soon._impl = 'asap';

Y.soon = soon;


}, '3.17.2', {"requires": ["yui-base"]});
