import “../core/document”; import “../core/vendor”;

var d3_timer_queueHead,

d3_timer_queueTail,
d3_timer_interval, // is an interval (or frame) active?
d3_timer_timeout; // is a timeout active?

// The timer will continue to fire until callback returns true. d3.timer = function(callback, delay, then) {

if (arguments.length < 3) {
  if (arguments.length < 2) delay = 0;
  else if (!isFinite(delay)) return;
  then = Date.now();
}

var time = then + delay;

// Add the callback to the tail of the queue.
var timer = {callback: callback, time: time, next: null};
if (d3_timer_queueTail) d3_timer_queueTail.next = timer;
else d3_timer_queueHead = timer;
d3_timer_queueTail = timer;

// Start animatin'!
if (!d3_timer_interval) {
  d3_timer_timeout = clearTimeout(d3_timer_timeout);
  d3_timer_interval = 1;
  d3_timer_frame(d3_timer_step);
}

};

function d3_timer_step() {

var now = d3_timer_mark(),
    delay = d3_timer_sweep() - now;
if (delay > 24) {
  if (isFinite(delay)) {
    clearTimeout(d3_timer_timeout);
    d3_timer_timeout = setTimeout(d3_timer_step, delay);
  }
  d3_timer_interval = 0;
} else {
  d3_timer_interval = 1;
  d3_timer_frame(d3_timer_step);
}

}

d3.timer.flush = function() {

d3_timer_mark();
d3_timer_sweep();

};

function d3_timer_mark() {

var now = Date.now(),
    timer = d3_timer_queueHead;
while (timer) {
  if (now >= timer.time) timer.flush = timer.callback(now - timer.time);
  timer = timer.next;
}
return now;

}

// Flush after callbacks to avoid concurrent queue modification. // Returns the time of the earliest active timer, post-sweep. function d3_timer_sweep() {

var t0,
    t1 = d3_timer_queueHead,
    time = Infinity;
while (t1) {
  if (t1.flush) {
    t1 = t0 ? t0.next = t1.next : d3_timer_queueHead = t1.next;
  } else {
    if (t1.time < time) time = t1.time;
    t1 = (t0 = t1).next;
  }
}
d3_timer_queueTail = t0;
return time;

}

var d3_timer_frame = d3_window[d3_vendorSymbol(d3_window, “requestAnimationFrame”)]

|| function(callback) { setTimeout(callback, 17); };