import “../arrays/bisect”; import “../arrays/min”; import “../arrays/max”; import “../core/functor”; import “layout”;

d3.layout.histogram = function() {

var frequency = true,
    valuer = Number,
    ranger = d3_layout_histogramRange,
    binner = d3_layout_histogramBinSturges;

function histogram(data, i) {
  var bins = [],
      values = data.map(valuer, this),
      range = ranger.call(this, values, i),
      thresholds = binner.call(this, range, values, i),
      bin,
      i = -1,
      n = values.length,
      m = thresholds.length - 1,
      k = frequency ? 1 : 1 / n,
      x;

  // Initialize the bins.
  while (++i < m) {
    bin = bins[i] = [];
    bin.dx = thresholds[i + 1] - (bin.x = thresholds[i]);
    bin.y = 0;
  }

  // Fill the bins, ignoring values outside the range.
  if (m > 0) {
    i = -1; while(++i < n) {
      x = values[i];
      if (x >= range[0] && x <= range[1]) {
        bin = bins[d3.bisect(thresholds, x, 1, m) - 1];
        bin.y += k;
        bin.push(data[i]);
      }
    }
  }

  return bins;
}

// Specifies how to extract a value from the associated data. The default
// value function is `Number`, which is equivalent to the identity function.
histogram.value = function(x) {
  if (!arguments.length) return valuer;
  valuer = x;
  return histogram;
};

// Specifies the range of the histogram. Values outside the specified range
// will be ignored. The argument `x` may be specified either as a two-element
// array representing the minimum and maximum value of the range, or as a
// function that returns the range given the array of values and the current
// index `i`. The default range is the extent (minimum and maximum) of the
// values.
histogram.range = function(x) {
  if (!arguments.length) return ranger;
  ranger = d3_functor(x);
  return histogram;
};

// Specifies how to bin values in the histogram. The argument `x` may be
// specified as a number, in which case the range of values will be split
// uniformly into the given number of bins. Or, `x` may be an array of
// threshold values, defining the bins; the specified array must contain the
// rightmost (upper) value, thus specifying n + 1 values for n bins. Or, `x`
// may be a function which is evaluated, being passed the range, the array of
// values, and the current index `i`, returning an array of thresholds. The
// default bin function will divide the values into uniform bins using
// Sturges' formula.
histogram.bins = function(x) {
  if (!arguments.length) return binner;
  binner = typeof x === "number"
      ? function(range) { return d3_layout_histogramBinFixed(range, x); }
      : d3_functor(x);
  return histogram;
};

// Specifies whether the histogram's `y` value is a count (frequency) or a
// probability (density). The default value is true.
histogram.frequency = function(x) {
  if (!arguments.length) return frequency;
  frequency = !!x;
  return histogram;
};

return histogram;

};

function d3_layout_histogramBinSturges(range, values) {

return d3_layout_histogramBinFixed(range, Math.ceil(Math.log(values.length) / Math.LN2 + 1));

}

function d3_layout_histogramBinFixed(range, n) {

var x = -1,
    b = +range[0],
    m = (range[1] - b) / n,
    f = [];
while (++x <= n) f[x] = m * x + b;
return f;

}

function d3_layout_histogramRange(values) {

return [d3.min(values), d3.max(values)];

}