import “../arrays/bisect”; import “../core/rebind”; import “../core/true”; import “../scale/linear”; import “../scale/nice”; import “day”; import “format”; import “hour”; import “minute”; import “month”; import “second”; import “time”; import “week”; import “year”;

function d3_time_scale(linear, methods, format) {

function scale(x) {
  return linear(x);
}

scale.invert = function(x) {
  return d3_time_scaleDate(linear.invert(x));
};

scale.domain = function(x) {
  if (!arguments.length) return linear.domain().map(d3_time_scaleDate);
  linear.domain(x);
  return scale;
};

scale.nice = function(m) {
  return scale.domain(d3_scale_nice(scale.domain(), m));
};

scale.ticks = function(m, k) {
  var extent = d3_scaleExtent(scale.domain());
  if (typeof m !== "function") {
    var span = extent[1] - extent[0],
        target = span / m,
        i = d3.bisect(d3_time_scaleSteps, target);
    if (i == d3_time_scaleSteps.length) return methods.year(extent, m);
    if (!i) return linear.ticks(m).map(d3_time_scaleDate);
    if (Math.log(target / d3_time_scaleSteps[i - 1]) < Math.log(d3_time_scaleSteps[i] / target)) --i;
    m = methods[i];
    k = m[1];
    m = m[0].range;
  }
  return m(extent[0], new Date(+extent[1] + 1), k); // inclusive upper bound
};

scale.tickFormat = function() {
  return format;
};

scale.copy = function() {
  return d3_time_scale(linear.copy(), methods, format);
};

return d3_scale_linearRebind(scale, linear);

}

function d3_time_scaleDate(t) {

return new Date(t);

}

function d3_time_scaleFormat(formats) {

return function(date) {
  var i = formats.length - 1, f = formats[i];
  while (!f[1](date)) f = formats[--i];
  return f[0](date);
};

}

function d3_time_scaleSetYear(y) {

var d = new Date(y, 0, 1);
d.setFullYear(y); // Y2K fail
return d;

}

function d3_time_scaleGetYear(d) {

var y = d.getFullYear(),
    d0 = d3_time_scaleSetYear(y),
    d1 = d3_time_scaleSetYear(y + 1);
return y + (d - d0) / (d1 - d0);

}

var d3_time_scaleSteps = [

1e3,    // 1-second
5e3,    // 5-second
15e3,   // 15-second
3e4,    // 30-second
6e4,    // 1-minute
3e5,    // 5-minute
9e5,    // 15-minute
18e5,   // 30-minute
36e5,   // 1-hour
108e5,  // 3-hour
216e5,  // 6-hour
432e5,  // 12-hour
864e5,  // 1-day
1728e5, // 2-day
6048e5, // 1-week
2592e6, // 1-month
7776e6, // 3-month
31536e6 // 1-year

];

var d3_time_scaleLocalMethods = [

[d3.time.second, 1],
[d3.time.second, 5],
[d3.time.second, 15],
[d3.time.second, 30],
[d3.time.minute, 1],
[d3.time.minute, 5],
[d3.time.minute, 15],
[d3.time.minute, 30],
[d3.time.hour, 1],
[d3.time.hour, 3],
[d3.time.hour, 6],
[d3.time.hour, 12],
[d3.time.day, 1],
[d3.time.day, 2],
[d3.time.week, 1],
[d3.time.month, 1],
[d3.time.month, 3],
[d3.time.year, 1]

];

var d3_time_scaleLocalFormats = [

[d3.time.format("%Y"), d3_true],
[d3.time.format("%B"), function(d) { return d.getMonth(); }],
[d3.time.format("%b %d"), function(d) { return d.getDate() != 1; }],
[d3.time.format("%a %d"), function(d) { return d.getDay() && d.getDate() != 1; }],
[d3.time.format("%I %p"), function(d) { return d.getHours(); }],
[d3.time.format("%I:%M"), function(d) { return d.getMinutes(); }],
[d3.time.format(":%S"), function(d) { return d.getSeconds(); }],
[d3.time.format(".%L"), function(d) { return d.getMilliseconds(); }]

];

var d3_time_scaleLinear = d3.scale.linear(),

d3_time_scaleLocalFormat = d3_time_scaleFormat(d3_time_scaleLocalFormats);

d3_time_scaleLocalMethods.year = function(extent, m) {

return d3_time_scaleLinear.domain(extent.map(d3_time_scaleGetYear)).ticks(m).map(d3_time_scaleSetYear);

};

d3.time.scale = function() {

return d3_time_scale(d3.scale.linear(), d3_time_scaleLocalMethods, d3_time_scaleLocalFormat);

};