import “../arrays/map”; import “../core/array”; import “../core/document”; import “../core/noop”; import “../event/event”; import “../format/requote”; import “selection”;

d3_selectionPrototype.on = function(type, listener, capture) {

var n = arguments.length;
if (n < 3) {

  // For on(object) or on(object, boolean), the object specifies the event
  // types and listeners to add or remove. The optional boolean specifies
  // whether the listener captures events.
  if (typeof type !== "string") {
    if (n < 2) listener = false;
    for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
    return this;
  }

  // For on(string), return the listener for the first node.
  if (n < 2) return (n = this.node()["__on" + type]) && n._;

  // For on(string, function), use the default capture.
  capture = false;
}

// Otherwise, a type, listener and capture are specified, and handled as below.
return this.each(d3_selection_on(type, listener, capture));

};

function d3_selection_on(type, listener, capture) {

var name = "__on" + type,
    i = type.indexOf("."),
    wrap = d3_selection_onListener;

if (i > 0) type = type.substring(0, i);
var filter = d3_selection_onFilters.get(type);
if (filter) type = filter, wrap = d3_selection_onFilter;

function onRemove() {
  var l = this[name];
  if (l) {
    this.removeEventListener(type, l, l.$);
    delete this[name];
  }
}

function onAdd() {
  var l = wrap(listener, d3_array(arguments));
  onRemove.call(this);
  this.addEventListener(type, this[name] = l, l.$ = capture);
  l._ = listener;
}

function removeAll() {
  var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"),
      match;
  for (var name in this) {
    if (match = name.match(re)) {
      var l = this[name];
      this.removeEventListener(match[1], l, l.$);
      delete this[name];
    }
  }
}

return i
    ? listener ? onAdd : onRemove
    : listener ? d3_noop : removeAll;

}

var d3_selection_onFilters = d3.map({

mouseenter: "mouseover",
mouseleave: "mouseout"

});

d3_selection_onFilters.forEach(function(k) {

if ("on" + k in d3_document) d3_selection_onFilters.remove(k);

});

function d3_selection_onListener(listener, argumentz) {

return function(e) {
  var o = d3.event; // Events can be reentrant (e.g., focus).
  d3.event = e;
  argumentz[0] = this.__data__;
  try {
    listener.apply(this, argumentz);
  } finally {
    d3.event = o;
  }
};

}

function d3_selection_onFilter(listener, argumentz) {

var l = d3_selection_onListener(listener, argumentz);
return function(e) {
  var target = this, related = e.relatedTarget;
  if (!related || (related !== target && !(related.compareDocumentPosition(target) & 8))) {
    l.call(target, e);
  }
};

}